酒店
build / task (16.x, npm, macOS-latest) (push) Canceled after 0s
build / task (16.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, npm, windows-latest) (push) Canceled after 0s
build / task (16.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (16.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (16.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (16.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, yarn, windows-latest) (push) Canceled after 0s
build / task (18.x, npm, macOS-latest) (push) Canceled after 0s
build / task (18.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, npm, windows-latest) (push) Canceled after 0s
build / task (18.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (18.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (18.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (18.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, yarn, windows-latest) (push) Canceled after 0s
build / task (20.x, npm, macOS-latest) (push) Canceled after 0s
build / task (20.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, npm, windows-latest) (push) Canceled after 0s
build / task (20.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (20.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (20.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (20.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, yarn, windows-latest) (push) Canceled after 0s
build / task (16.x, npm, macOS-latest) (push) Canceled after 0s
build / task (16.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, npm, windows-latest) (push) Canceled after 0s
build / task (16.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (16.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (16.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (16.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, yarn, windows-latest) (push) Canceled after 0s
build / task (18.x, npm, macOS-latest) (push) Canceled after 0s
build / task (18.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, npm, windows-latest) (push) Canceled after 0s
build / task (18.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (18.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (18.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (18.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, yarn, windows-latest) (push) Canceled after 0s
build / task (20.x, npm, macOS-latest) (push) Canceled after 0s
build / task (20.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, npm, windows-latest) (push) Canceled after 0s
build / task (20.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (20.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (20.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (20.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, yarn, windows-latest) (push) Canceled after 0s
This commit is contained in:
1 parent
1976afa5e2
commit
04e1d3bdab
5 files changed
+283
-59
No files matched your search
@@ -22,6 +22,14 @@ export function retryTask(id: string | number) {
|
||||
})
|
||||
}
|
||||
|
||||
/** 把滞留待处理任务重新推入 Redis 消费队列 */
|
||||
export function requeuePendingTasks() {
|
||||
return request({
|
||||
url: "/supermarket/smHotelCallback/requeuePending",
|
||||
method: "post",
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除单条 */
|
||||
export function delTask(id: string | number) {
|
||||
return request({
|
||||
|
||||
@@ -1,59 +1,99 @@
|
||||
<template>
|
||||
<el-drawer v-model="visible" :title="title" size="72%" destroy-on-close @closed="reset">
|
||||
<div v-loading="loading">
|
||||
<el-descriptions v-if="hotel" :column="2" border class="mb-4">
|
||||
<el-descriptions-item label="酒店名称">{{ hotel.hotelName || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="酒店编码">{{ hotel.hotelCode || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="数据来源">
|
||||
<dict-tag :options="sm_hotel_data_source" :value="hotel.sheetName" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="上架状态">
|
||||
<el-tag :type="hotel.upstreamStatus === 'OFFLINE' ? 'info' : 'success'" size="small">
|
||||
{{ hotel.upstreamStatus === "OFFLINE" ? "下架" : "上架" }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ hotel.phone || "-" }}</el-descriptions-item>
|
||||
<template v-if="isLocal">
|
||||
<el-descriptions-item label="自动滚加">
|
||||
<el-tag :type="hotel.localAutoRoll === 1 ? 'success' : 'info'" size="small">
|
||||
{{ hotel.localAutoRoll === 1 ? "已开启" : "未开启" }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="滚动天数">
|
||||
{{ hotel.localAutoRoll === 1 ? `${hotel.localRollHorizonDays || 30} 天` : "-" }}
|
||||
</el-descriptions-item>
|
||||
</template>
|
||||
<el-descriptions-item label="详细地址" :span="2">{{ hotel.address || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="位置区域">
|
||||
{{ hotel.district || "-" }}
|
||||
<span v-if="hotel.districtAdcode" class="text-gray-400">({{ hotel.districtAdcode }})</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="商圈地标">{{ hotel.bizArea || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="星级档次">{{ starLabel(hotel.starLevel) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="评分">{{ hotel.score != null ? hotel.score : "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="设施标签" :span="2">{{ hotel.facilityTags || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="坐标">
|
||||
<span v-if="hotel.longitude != null && hotel.latitude != null">
|
||||
{{ hotel.longitude }}, {{ hotel.latitude }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="主图">
|
||||
<el-image
|
||||
v-if="hotel.coverImage"
|
||||
:src="resolveFileUrl(hotel.coverImage)"
|
||||
style="width: 72px; height: 72px"
|
||||
fit="cover"
|
||||
:preview-src-list="[resolveFileUrl(hotel.coverImage)]"
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="简介" :span="2">
|
||||
<div v-if="hotel.intro" class="intro-html" v-html="hotel.intro" />
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">{{ hotel.remark || "-" }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<!-- 顶部概览:主图+名称+状态一眼可见;不用 border descriptions(标签易被挤成竖排) -->
|
||||
<div v-if="hotel" class="hotel-overview mb-4">
|
||||
<div class="hotel-overview__hero">
|
||||
<div class="hotel-overview__cover">
|
||||
<el-image
|
||||
v-if="hotel.coverImage"
|
||||
:src="resolveFileUrl(hotel.coverImage)"
|
||||
fit="cover"
|
||||
class="hotel-overview__cover-img"
|
||||
:preview-src-list="[resolveFileUrl(hotel.coverImage)]"
|
||||
/>
|
||||
<div v-else class="hotel-overview__cover-empty">暂无主图</div>
|
||||
</div>
|
||||
<div class="hotel-overview__main">
|
||||
<div class="hotel-overview__name">{{ hotel.hotelName || "-" }}</div>
|
||||
<div class="hotel-overview__code">编码 {{ hotel.hotelCode || "-" }}</div>
|
||||
<div class="hotel-overview__tags">
|
||||
<dict-tag :options="sm_hotel_data_source" :value="hotel.sheetName" />
|
||||
<el-tag :type="hotel.upstreamStatus === 'OFFLINE' ? 'info' : 'success'" effect="dark" size="small">
|
||||
{{ hotel.upstreamStatus === "OFFLINE" ? "下架" : "上架" }}
|
||||
</el-tag>
|
||||
<el-tag v-if="starLabel(hotel.starLevel) !== '-'" type="warning" effect="plain" size="small">
|
||||
{{ starLabel(hotel.starLevel) }}
|
||||
</el-tag>
|
||||
<el-tag v-if="hotel.score != null" type="danger" effect="plain" size="small">评分 {{ hotel.score }}</el-tag>
|
||||
<template v-if="isLocal">
|
||||
<el-tag :type="hotel.localAutoRoll === 1 ? 'success' : 'info'" effect="plain" size="small">
|
||||
自动滚加 {{ hotel.localAutoRoll === 1 ? "已开启" : "未开启" }}
|
||||
</el-tag>
|
||||
<el-tag v-if="hotel.localAutoRoll === 1" effect="plain" size="small">
|
||||
滚动 {{ hotel.localRollHorizonDays || 30 }} 天
|
||||
</el-tag>
|
||||
</template>
|
||||
</div>
|
||||
<div class="hotel-overview__addr">
|
||||
<span class="hotel-overview__addr-label">地址</span>
|
||||
<span>{{ hotel.address || "-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hotel-overview__grid">
|
||||
<div class="hotel-overview__cell">
|
||||
<span class="hotel-overview__label">联系电话</span>
|
||||
<span class="hotel-overview__value">{{ hotel.phone || "-" }}</span>
|
||||
</div>
|
||||
<div class="hotel-overview__cell">
|
||||
<span class="hotel-overview__label">位置区域</span>
|
||||
<span class="hotel-overview__value">
|
||||
{{ hotel.district || "-" }}
|
||||
<span v-if="hotel.districtAdcode" class="text-gray-400">({{ hotel.districtAdcode }})</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="hotel-overview__cell">
|
||||
<span class="hotel-overview__label">商圈地标</span>
|
||||
<span class="hotel-overview__value">{{ hotel.bizArea || "-" }}</span>
|
||||
</div>
|
||||
<div class="hotel-overview__cell">
|
||||
<span class="hotel-overview__label">坐标</span>
|
||||
<span class="hotel-overview__value">
|
||||
<template v-if="hotel.longitude != null && hotel.latitude != null">
|
||||
{{ hotel.longitude }}, {{ hotel.latitude }}
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="hotel-overview__cell hotel-overview__cell--full">
|
||||
<span class="hotel-overview__label">设施标签</span>
|
||||
<span class="hotel-overview__value">
|
||||
<template v-if="facilityTagList.length">
|
||||
<el-tag
|
||||
v-for="(tag, idx) in facilityTagList"
|
||||
:key="`${tag}-${idx}`"
|
||||
size="small"
|
||||
effect="plain"
|
||||
class="mr-1 mb-1"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="hotel.intro" class="hotel-overview__cell hotel-overview__cell--full">
|
||||
<span class="hotel-overview__label">简介</span>
|
||||
<div class="hotel-overview__value intro-html" v-html="hotel.intro" />
|
||||
</div>
|
||||
<div v-if="hotel.remark" class="hotel-overview__cell hotel-overview__cell--full">
|
||||
<span class="hotel-overview__label">备注</span>
|
||||
<span class="hotel-overview__value">{{ hotel.remark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-alert
|
||||
v-if="isLocal"
|
||||
@@ -530,6 +570,14 @@ const orderForm = reactive({
|
||||
|
||||
const title = computed(() => (hotel.value?.hotelName ? `酒店详情 - ${hotel.value.hotelName}` : "酒店详情"))
|
||||
const isLocal = computed(() => String(hotel.value?.sheetName || "").toLowerCase() === "local")
|
||||
const facilityTagList = computed(() => {
|
||||
const raw = String(hotel.value?.facilityTags || "").trim()
|
||||
if (!raw) return [] as string[]
|
||||
return raw
|
||||
.split(/[,,;;|、\n]+/)
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
})
|
||||
const resolveFileUrl = (url?: string) => {
|
||||
const u = String(url || "").trim()
|
||||
if (!u) return ""
|
||||
@@ -1055,6 +1103,117 @@ defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hotel-overview {
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.hotel-overview__hero {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, var(--el-fill-color-light) 0%, var(--el-bg-color) 55%);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
.hotel-overview__cover {
|
||||
flex: 0 0 120px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--el-fill-color);
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
.hotel-overview__cover-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
.hotel-overview__cover-empty {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--el-text-color-placeholder);
|
||||
font-size: 13px;
|
||||
}
|
||||
.hotel-overview__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.hotel-overview__name {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 1.35;
|
||||
color: var(--el-text-color-primary);
|
||||
word-break: break-word;
|
||||
}
|
||||
.hotel-overview__code {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
.hotel-overview__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.hotel-overview__addr {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
.hotel-overview__addr-label {
|
||||
flex: 0 0 auto;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
.hotel-overview__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0;
|
||||
}
|
||||
.hotel-overview__cell {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--el-border-color-extra-light);
|
||||
border-right: 1px solid var(--el-border-color-extra-light);
|
||||
min-height: 44px;
|
||||
}
|
||||
.hotel-overview__cell:nth-child(2n) {
|
||||
border-right: none;
|
||||
}
|
||||
.hotel-overview__cell--full {
|
||||
grid-column: 1 / -1;
|
||||
border-right: none;
|
||||
}
|
||||
.hotel-overview__label {
|
||||
flex: 0 0 72px;
|
||||
width: 72px;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: var(--el-text-color-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hotel-overview__value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: var(--el-text-color-primary);
|
||||
word-break: break-word;
|
||||
}
|
||||
.intro-html {
|
||||
line-height: 1.6;
|
||||
word-break: break-word;
|
||||
@@ -1062,4 +1221,20 @@ defineExpose({ open })
|
||||
.intro-html :deep(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.hotel-overview__hero {
|
||||
flex-direction: column;
|
||||
}
|
||||
.hotel-overview__cover {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
flex-basis: auto;
|
||||
}
|
||||
.hotel-overview__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.hotel-overview__cell {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -150,7 +150,6 @@
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="isLocalHotel(scope.row)"
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
|
||||
@@ -45,6 +45,16 @@
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="RefreshRight"
|
||||
v-auth="'supermarket_smHotelCallback_retry'"
|
||||
:loading="requeuing"
|
||||
@click="handleRequeuePending"
|
||||
>
|
||||
重新入队待处理
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
@@ -100,7 +110,7 @@
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" v-auth="'supermarket_smHotelCallback_view'" @click="openDetail(scope.row)">详情</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.status === 'FAILED' || scope.row.status === 'SKIPPED' || scope.row.status === 'SUCCESS'"
|
||||
v-if="scope.row.status !== 'RUNNING'"
|
||||
text
|
||||
type="warning"
|
||||
v-auth="'supermarket_smHotelCallback_retry'"
|
||||
@@ -182,7 +192,15 @@
|
||||
|
||||
<script setup lang="ts" name="systemSmHotelCallback">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||
import { fetchList, getObj, retryTask, delTask, delTaskByRange, clearAllTasks } from "/@/api/supermarket/smHotelCallback"
|
||||
import {
|
||||
fetchList,
|
||||
getObj,
|
||||
retryTask,
|
||||
requeuePendingTasks,
|
||||
delTask,
|
||||
delTaskByRange,
|
||||
clearAllTasks,
|
||||
} from "/@/api/supermarket/smHotelCallback"
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||
|
||||
const queryRef = ref()
|
||||
@@ -190,6 +208,7 @@ const showSearch = ref(true)
|
||||
const detailVisible = ref(false)
|
||||
const detail = ref<any>(null)
|
||||
const clearing = ref(false)
|
||||
const requeuing = ref(false)
|
||||
const rangeVisible = ref(false)
|
||||
const rangeDeleting = ref(false)
|
||||
const rangeBegin = ref("")
|
||||
@@ -238,7 +257,7 @@ const openDetail = async (row: any) => {
|
||||
|
||||
const handleRetry = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm(`确认重试任务 ${row.id}?将重新拉取上游房价房量。`)
|
||||
await useMessageBox().confirm(`确认重试任务 ${row.id}?将重新推入消费队列并拉取上游。`)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
@@ -251,6 +270,26 @@ const handleRetry = async (row: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleRequeuePending = async () => {
|
||||
try {
|
||||
await useMessageBox().confirm(
|
||||
"确认把当前滞留的「待处理」任务重新推入 Redis 队列?需先保证渠道配置里 callback-queue-enabled=true,且 supermarket 服务已启动。",
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
requeuing.value = true
|
||||
try {
|
||||
const res: any = await requeuePendingTasks()
|
||||
useMessage().success(res?.msg || `已重新入队 ${res?.data ?? 0} 条`)
|
||||
getDataList(false)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || err?.message || "重新入队失败")
|
||||
} finally {
|
||||
requeuing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteOne = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm(`确认删除任务 ${row.id}?(软删除,不影响本地已落库房价)`)
|
||||
|
||||
@@ -72,5 +72,8 @@ push-log-retain-days: 15
|
||||
# order-pull-schedule-enabled: true # false=整机关掉定时(手动仍可用)
|
||||
# push-log-cleanup-cron: 0 40 4 * * ? # 推送流水清理
|
||||
#
|
||||
# 环启侧配置我们的接收地址(B→A 推送,与拉取独立):
|
||||
# {网关}/supermarket/third/party/api/order/push
|
||||
# 环启侧需配置/联调的地址(B→A,验签同 app-key):
|
||||
# 下单前预检(我方补充,文档无;请环启售前调用):
|
||||
# POST {网关}/supermarket/third/party/api/order/check
|
||||
# 订单推送接收:
|
||||
# POST {网关}/supermarket/third/party/api/order/push
|
||||
Reference in new issue
Block a user