feat: 客服「成交与自动结算」配置页与指标列表
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -84,6 +84,11 @@ const routes = [
|
||||
component: () => import('@/views/order/MerchantOrder.vue'),
|
||||
meta: { title: '商家订单' }
|
||||
},
|
||||
{
|
||||
path: 'order/deal-config',
|
||||
component: () => import('@/views/order/OrderDealConfig.vue'),
|
||||
meta: { title: '成交与自动结算' }
|
||||
},
|
||||
{
|
||||
path: 'order/detail/:id',
|
||||
component: () => import('@/views/order/Detail.vue'),
|
||||
@@ -323,6 +328,11 @@ const routes = [
|
||||
component: () => import('@/views/club/RechargePageCopy.vue'),
|
||||
meta: { title: '充值页文案' }
|
||||
},
|
||||
{
|
||||
path: 'miniapp/role-agreement',
|
||||
component: () => import('@/views/miniapp/RoleAgreement.vue'),
|
||||
meta: { title: '角色协议' }
|
||||
},
|
||||
// ========== 店铺管理(原有) ==========
|
||||
{
|
||||
path: 'shop/list',
|
||||
|
||||
@@ -133,6 +133,8 @@ const KEFU_MENU_ROWS = [
|
||||
{ page_id: 'assessment.record', parent_id: 'assessment', path: '/assessment/record', sort_order: 23, perm_codes: ['kaohepeizhi'] },
|
||||
{ page_id: 'order.platform', parent_id: 'order', path: '/order/platform', sort_order: 31, perm_codes: ['002ab'] },
|
||||
{ page_id: 'order.merchant', parent_id: 'order', path: '/order/merchant', sort_order: 32, perm_codes: ['002ac', '002ab', '003aa'] },
|
||||
{ page_id: 'order.deal-config', parent_id: 'order', path: '/order/deal-config', sort_order: 33, perm_codes: ['002ab', '002ac', '003aa'] },
|
||||
{ page_id: 'order.merchant', parent_id: 'order', path: '/order/merchant', sort_order: 32, perm_codes: ['002ac', '002ab', '003aa'] },
|
||||
{ page_id: 'cross-platform.order', parent_id: 'cross-platform', path: '/cross-order', sort_order: 41, perm_codes: ['003aa'] },
|
||||
{ page_id: 'cross-platform.settings', parent_id: 'cross-platform', path: '/cross-settings', sort_order: 42, perm_codes: ['003aa'] },
|
||||
{ page_id: 'cross-platform.data', parent_id: 'cross-platform', path: '/cross-data', sort_order: 43, perm_codes: ['003aa'] },
|
||||
@@ -166,6 +168,7 @@ const KEFU_MENU_ROWS = [
|
||||
{ page_id: 'miniapp.dashou-exam', parent_id: 'miniapp', path: '/miniapp/dashou-exam', sort_order: 117, perm_codes: ['dsks666', '8080a'] },
|
||||
{ page_id: 'miniapp.rank-reward', parent_id: 'miniapp', path: '/miniapp/rank-reward', sort_order: 118, perm_codes: ['phbj666', '8080a'] },
|
||||
{ page_id: 'miniapp.recharge-copy', parent_id: 'miniapp', path: '/miniapp/recharge-copy', sort_order: 119, perm_codes: ['8080a'] },
|
||||
{ page_id: 'miniapp.role-agreement', parent_id: 'miniapp', path: '/miniapp/role-agreement', sort_order: 120, perm_codes: ['xycfg001', '8080a'] },
|
||||
{ page_id: 'miniapp.withdraw-settings', parent_id: 'miniapp', path: '/withdraw/settings', sort_order: 114, perm_codes: ['5500a', '5500b', '5500c'] },
|
||||
{ page_id: 'shop.list', parent_id: 'shop', path: '/shop/list', sort_order: 121, perm_codes: ['999a', '999b', '999c', '999d', '999e'] },
|
||||
{ page_id: 'shop.withdraw', parent_id: 'shop', path: '/shop/withdraw-apply', sort_order: 122, perm_codes: ['999a', '999b', '999c', '999d', '999e'] },
|
||||
@@ -177,13 +180,13 @@ const KEFU_MENU_PARENT_IDS = {
|
||||
admin: ['admin.role', 'admin.data-scope', 'admin.club-config', 'admin.order-grab-share', 'admin.user', 'admin.operation-log'],
|
||||
finance: ['finance.bankuai', 'finance.data', 'finance.fund-freeze-config', 'finance.fund-freeze-ledger', 'finance.fund-risk-stats'],
|
||||
assessment: ['assessment.examiner', 'assessment.config', 'assessment.record'],
|
||||
order: ['order.platform', 'order.merchant'],
|
||||
order: ['order.platform', 'order.merchant', 'order.deal-config'],
|
||||
'cross-platform': ['cross-platform.order', 'cross-platform.settings', 'cross-platform.data', 'cross-platform.pre'],
|
||||
user: ['user.player', 'user.guanli', 'user.shangjia', 'user.zuzhang', 'user.identity-tag'],
|
||||
withdraw: ['withdraw.audit', 'withdraw.data', 'withdraw.settings'],
|
||||
product: ['product.list', 'product.type-zone', 'product.turntable', 'product.data', 'product.fake-orders'],
|
||||
member: ['member.list', 'member.data'],
|
||||
miniapp: ['miniapp.carousel', 'miniapp.assets', 'miniapp.popup', 'miniapp.leixing', 'miniapp.kaohe-tags', 'miniapp.dashou-exam', 'miniapp.rank-reward', 'miniapp.recharge-copy', 'miniapp.withdraw-settings'],
|
||||
miniapp: ['miniapp.carousel', 'miniapp.assets', 'miniapp.popup', 'miniapp.leixing', 'miniapp.kaohe-tags', 'miniapp.dashou-exam', 'miniapp.rank-reward', 'miniapp.recharge-copy', 'miniapp.role-agreement', 'miniapp.withdraw-settings'],
|
||||
shop: ['shop.list', 'shop.withdraw', 'shop.products'],
|
||||
};
|
||||
|
||||
@@ -429,6 +432,10 @@ export const JITUAN_API = {
|
||||
fundFreezeConfig: '/jituan/houtai/fund-freeze-config',
|
||||
fundFreezeLedger: '/jituan/houtai/fund-freeze-ledger',
|
||||
fundFreezeRisk: '/jituan/houtai/fund-freeze-risk',
|
||||
roleAgreement: '/jituan/houtai/role-agreement',
|
||||
orderDealConfig: '/jituan/houtai/order-deal-config',
|
||||
merchantDealStat: '/jituan/houtai/merchant-deal-stat',
|
||||
dashouDealStat: '/jituan/houtai/dashou-deal-stat',
|
||||
paymentChannelManage: '/jituan/houtai/payment-channel-manage',
|
||||
clubCertUpload: '/jituan/houtai/club-cert-upload',
|
||||
memberList: '/jituan/houtai/hthqhylb',
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
</template>
|
||||
<el-menu-item v-if="canShow('order.platform')" index="/order/platform">平台订单</el-menu-item>
|
||||
<el-menu-item v-if="canShow('order.merchant')" index="/order/merchant">商家订单</el-menu-item>
|
||||
<el-menu-item v-if="canShow('order.deal-config')" index="/order/deal-config">成交与自动结算</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<!-- 跨平台管理 -->
|
||||
@@ -156,6 +157,7 @@
|
||||
<el-menu-item v-if="canShow('miniapp.dashou-exam')" index="/miniapp/dashou-exam">打手接单考试</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.rank-reward')" index="/miniapp/rank-reward">排行榜奖励</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.recharge-copy')" index="/miniapp/recharge-copy">充值页文案</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.role-agreement')" index="/miniapp/role-agreement">角色协议</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.withdraw-settings')" index="/withdraw/settings">提现与收款设置</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
|
||||
165
src/views/order/OrderDealConfig.vue
Normal file
165
src/views/order/OrderDealConfig.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div class="page" v-loading="loading">
|
||||
<ClubScopeHint />
|
||||
<div class="header">
|
||||
<h2>成交指标与自动结算</h2>
|
||||
<el-button @click="load">刷新</el-button>
|
||||
</div>
|
||||
<el-alert
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="默认全关。打开自动结算后,仅「本次开启之后新进入结算中」的订单会计时并到期自动完成;历史结算中老单永远不会被自动结。"
|
||||
style="margin-bottom: 16px"
|
||||
/>
|
||||
<div v-if="form.club_id" class="club">当前俱乐部:{{ form.club_id }}</div>
|
||||
|
||||
<el-card shadow="never" class="card">
|
||||
<template #header>自动结算</template>
|
||||
<el-form label-width="160px">
|
||||
<el-form-item label="启用自动结算">
|
||||
<el-switch v-model="form.auto_settle_enabled" />
|
||||
</el-form-item>
|
||||
<el-form-item label="平台单超时(小时)">
|
||||
<el-input-number v-model="form.hours_platform" :min="1" :max="720" />
|
||||
</el-form-item>
|
||||
<el-form-item label="商家单超时(小时)">
|
||||
<el-input-number v-model="form.hours_merchant" :min="1" :max="720" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.auto_settle_enabled_at" label="本次开启时间">
|
||||
<span>{{ form.auto_settle_enabled_at }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="card">
|
||||
<template #header>成交 / 罚款指标统计</template>
|
||||
<el-form label-width="160px">
|
||||
<el-form-item label="启用指标统计">
|
||||
<el-switch v-model="form.stats_enabled" />
|
||||
<span class="tip">从开启时刻起记账,不算历史单</span>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.stats_since" label="统计起点">
|
||||
<span>{{ form.stats_since }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-button type="primary" :loading="saving" @click="save">保存</el-button>
|
||||
|
||||
<el-card v-if="form.stats_enabled" shadow="never" class="card" style="margin-top:16px">
|
||||
<template #header>商家指标(本俱乐部)</template>
|
||||
<el-table :data="merchantList" size="small" max-height="360">
|
||||
<el-table-column prop="merchant_uid" label="商家UID" width="120" />
|
||||
<el-table-column prop="order_count" label="订单量" width="90" />
|
||||
<el-table-column prop="deal_rate" label="成交率" width="100">
|
||||
<template #default="{ row }">{{ pct(row.deal_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fine_rate" label="罚款率" width="100">
|
||||
<template #default="{ row }">{{ pct(row.fine_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="refund_rate" label="退款率" width="100">
|
||||
<template #default="{ row }">{{ pct(row.refund_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avg_deal_hours" label="平均成交时长(h)" min-width="120" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="form.stats_enabled" shadow="never" class="card">
|
||||
<template #header>打手指标(本俱乐部)</template>
|
||||
<el-table :data="dashouList" size="small" max-height="360">
|
||||
<el-table-column prop="dashou_uid" label="打手UID" width="120" />
|
||||
<el-table-column prop="order_count" label="接单量" width="90" />
|
||||
<el-table-column prop="deal_rate" label="成交率" width="100">
|
||||
<template #default="{ row }">{{ pct(row.deal_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fined_rate" label="被罚款率" width="100">
|
||||
<template #default="{ row }">{{ pct(row.fined_rate) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import request from '@/utils/request'
|
||||
import { JITUAN_API } from '@/utils/club-context'
|
||||
import ClubScopeHint from '@/components/ClubScopeHint.vue'
|
||||
|
||||
const username = localStorage.getItem('username') || ''
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const merchantList = ref([])
|
||||
const dashouList = ref([])
|
||||
const form = reactive({
|
||||
club_id: '',
|
||||
auto_settle_enabled: false,
|
||||
auto_settle_enabled_at: '',
|
||||
hours_platform: 48,
|
||||
hours_merchant: 48,
|
||||
stats_enabled: false,
|
||||
stats_since: '',
|
||||
})
|
||||
|
||||
function pct(v) {
|
||||
const n = Number(v) || 0
|
||||
return `${(n * 100).toFixed(2)}%`
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await request.post(JITUAN_API.orderDealConfig, { username, action: 'get' })
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
Object.assign(form, res.data || {})
|
||||
} else {
|
||||
ElMessage.error(res.msg || '加载失败')
|
||||
}
|
||||
if (form.stats_enabled) {
|
||||
const [m, d] = await Promise.all([
|
||||
request.post(JITUAN_API.merchantDealStat, { username, action: 'list' }),
|
||||
request.post(JITUAN_API.dashouDealStat, { username, action: 'list' }),
|
||||
])
|
||||
merchantList.value = m.data?.list || []
|
||||
dashouList.value = d.data?.list || []
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
saving.value = true
|
||||
try {
|
||||
const res = await request.post(JITUAN_API.orderDealConfig, {
|
||||
username,
|
||||
action: 'save',
|
||||
auto_settle_enabled: form.auto_settle_enabled,
|
||||
hours_platform: form.hours_platform,
|
||||
hours_merchant: form.hours_merchant,
|
||||
stats_enabled: form.stats_enabled,
|
||||
})
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
Object.assign(form, res.data || {})
|
||||
ElMessage.success('已保存')
|
||||
load()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { padding: 16px; }
|
||||
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
|
||||
.club { margin-bottom: 12px; color: #64748b; font-size: 13px; }
|
||||
.card { margin-bottom: 16px; }
|
||||
.tip { margin-left: 12px; color: #94a3b8; font-size: 12px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user