This commit is contained in:
van
2026-04-15 20:50:55 +08:00
parent 86df461d82
commit d87127f675
2 changed files with 374 additions and 94 deletions

View File

@@ -1,29 +1,29 @@
<template>
<div class="app-container">
<el-card class="box-card">
<el-form :model="form" label-width="45px" label-position="top">
<div class="app-container jd-instruction-root">
<el-card class="box-card jd-instruction-card">
<el-form :model="form" label-width="45px" label-position="top" class="jd-instruction-form">
<el-form-item label="输入指令">
<el-input v-model="form.command" type="textarea" :rows="8" placeholder="💰💰💰💰💰💰💰💰" />
<el-input v-model="form.command" type="textarea" :rows="8" placeholder="💰💰💰💰💰💰💰💰" class="jd-instruction-command-input" />
</el-form-item>
<div class="button-group button-group-primary" :class="{ 'is-mobile-compact': isMobile }">
<el-button type="success" size="medium" @click="run" :loading="loading">执行</el-button>
<el-button type="danger" size="medium" @click="clearAll">清空</el-button>
<el-button type="primary" plain size="small" class="jd-filter-act-btn jd-inst-focus" icon="el-icon-right" @click="run" :loading="loading">执行</el-button>
<el-button class="jd-tb-muted jd-filter-act-btn" plain size="small" icon="el-icon-delete" @click="clearAll">清空</el-button>
<template v-if="!isMobile">
<el-button size="warning" @click="fillMan">慢单</el-button>
<el-button size="success" @click="fillSheng">通用格式</el-button>
<el-button class="jd-tb-muted jd-filter-act-btn jd-inst-focus" plain size="small" icon="el-icon-time" @click="fillMan">慢单</el-button>
<el-button class="jd-tb-muted jd-filter-act-btn" plain size="small" @click="fillSheng">通用格式</el-button>
</template>
</div>
<div v-if="!isMobile" class="button-group button-group-secondary">
<el-button type="primary" size="medium" @click="fillTF">腾峰</el-button>
<el-button type="primary" size="medium" @click="fillFan"></el-button>
<!-- <el-button type="primary" size="medium" @click="fillWen"></el-button> -->
<el-button type="primary" size="medium" @click="fillHong">鸿</el-button>
<el-button type="primary" size="medium" @click="fillPDD">拼多多</el-button>
<!-- <el-button type="primary" size="medium" @click="fillPDDWen">拼多多-纹</el-button> -->
<el-button type="primary" plain size="small" class="jd-filter-act-btn jd-inst-focus" @click="fillTF">腾峰</el-button>
<el-button type="primary" plain size="small" class="jd-filter-act-btn jd-inst-focus" @click="fillFan"></el-button>
<!-- <el-button type="primary" plain size="small" class="jd-filter-act-btn" @click="fillWen"></el-button> -->
<el-button type="primary" plain size="small" class="jd-filter-act-btn" @click="fillPDD">拼多多</el-button>
<el-button type="primary" plain size="small" class="jd-filter-act-btn" @click="fillHong">鸿</el-button>
<!-- <el-button type="primary" plain size="small" class="jd-filter-act-btn" @click="fillPDDWen">拼多多-纹</el-button> -->
</div>
</el-form>
<el-divider>响应</el-divider>
<el-divider class="jd-instruction-divider">响应</el-divider>
<div v-if="resultList.length === 0" style="padding: 12px 0;">
<el-empty description="无响应" />
@@ -59,7 +59,7 @@
</div>
</div>
<el-divider>历史消息记录</el-divider>
<el-divider class="jd-instruction-divider">历史消息记录</el-divider>
<div class="history-controls">
<div class="history-field history-field-limit">
@@ -619,8 +619,117 @@ export default {
</script>
<style scoped>
.box-card {
margin: 20px;
/* 与订单列表 jd-order-list-root 一致的色板与质感 */
.jd-instruction-root {
--jd-accent: #2563eb;
--jd-accent-hover: #1d4ed8;
--jd-warm-title: #c2410c;
--jd-border: #e5e7eb;
--jd-text: #111827;
--jd-muted: #6b7280;
--jd-surface: #ffffff;
--jd-header: #f8fafc;
--jd-row-hover: #fffbf5;
--jd-row-stripe: #fafbfc;
}
.box-card {
margin: 20px;
}
.jd-instruction-card {
border-radius: 10px;
overflow: hidden;
border: 1px solid var(--jd-border);
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.jd-instruction-card ::v-deep .el-card__body {
background: linear-gradient(165deg, #f4f8ff 0%, #fffaf5 42%, #ffffff 100%);
padding: 18px 20px 20px;
}
.jd-instruction-form ::v-deep .el-form-item__label {
color: var(--jd-muted);
font-weight: 500;
font-size: 13px;
}
.jd-instruction-command-input ::v-deep .el-textarea__inner {
border-radius: 8px;
border-color: var(--jd-border);
font-size: 13px;
line-height: 1.55;
}
.jd-instruction-command-input ::v-deep .el-textarea__inner:focus {
border-color: #bfdbfe;
box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.12);
}
.jd-instruction-divider ::v-deep .el-divider__text {
color: var(--jd-muted);
font-weight: 600;
font-size: 13px;
background: transparent;
}
.jd-instruction-divider.el-divider--horizontal {
margin: 18px 0;
background-color: var(--jd-border);
}
/* 按钮组对齐订单列表工具栏plain + 圆角) */
.jd-instruction-root .button-group ::v-deep .el-button {
border-radius: 6px;
font-weight: 500;
letter-spacing: 0.01em;
}
.jd-instruction-root .button-group ::v-deep .el-button--primary.is-plain {
color: var(--jd-accent);
border-color: #bfdbfe;
background: #eff6ff;
}
.jd-instruction-root .button-group ::v-deep .el-button--primary.is-plain:hover,
.jd-instruction-root .button-group ::v-deep .el-button--primary.is-plain:focus {
color: #fff;
background: var(--jd-accent);
border-color: var(--jd-accent);
}
.jd-instruction-root .button-group ::v-deep .jd-tb-muted.is-plain {
color: var(--jd-muted);
border-color: var(--jd-border);
background: var(--jd-surface);
}
.jd-instruction-root .button-group ::v-deep .jd-tb-muted.is-plain:hover,
.jd-instruction-root .button-group ::v-deep .jd-tb-muted.is-plain:focus {
color: var(--jd-text);
border-color: #cbd5e1;
background: var(--jd-row-hover);
}
/* 执行 / 腾峰 / 慢单 / 凡:略加强,不抢眼 */
.jd-instruction-root .button-group ::v-deep .jd-inst-focus.el-button--primary.is-plain {
font-weight: 600;
box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.08);
}
.jd-instruction-root .button-group ::v-deep .jd-inst-focus.jd-tb-muted.is-plain {
font-weight: 600;
border-color: #d1d9e6;
color: #374151;
background: linear-gradient(180deg, #fcfcfd 0%, #f4f7fb 100%);
}
.jd-instruction-root .button-group ::v-deep .jd-inst-focus.jd-tb-muted.is-plain:hover,
.jd-instruction-root .button-group ::v-deep .jd-inst-focus.jd-tb-muted.is-plain:focus {
border-color: #cbd5e1;
color: var(--jd-text);
background: var(--jd-row-hover);
}
/* 移动端卡片优化 */
@@ -629,14 +738,14 @@ export default {
margin: 10px;
border-radius: 8px;
}
.box-card ::v-deep .el-card__header {
padding: 12px 16px;
font-size: 16px;
}
.box-card ::v-deep .el-card__body {
padding: 16px;
.jd-instruction-card ::v-deep .el-card__body {
padding: 14px 14px 16px;
}
}
/* 响应容器 */
@@ -648,11 +757,12 @@ export default {
}
.response-section {
border: 1px solid #DCDFE6;
border-radius: 4px;
border: 1px solid var(--jd-border);
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.response-header {
@@ -660,10 +770,10 @@ export default {
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background-color: #F5F7FA;
border-bottom: 1px solid #DCDFE6;
background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 72%);
border-bottom: 1px solid #bfdbfe;
font-weight: 600;
color: #303133;
color: var(--jd-text);
font-size: 14px;
}
@@ -686,15 +796,17 @@ export default {
border-radius: 0;
resize: none;
min-height: 400px;
font-family: 'Courier New', monospace;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: var(--jd-text);
background: var(--jd-surface);
}
/* 消息列表区域 */
.response-content-list {
padding: 16px;
background-color: #FFFFFF;
background-color: var(--jd-surface);
max-height: 600px;
overflow-y: auto;
}
@@ -708,15 +820,16 @@ export default {
.message-item {
padding: 12px;
border-radius: 4px;
background-color: #F9FAFC;
border-left: 3px solid #409EFF;
transition: all 0.3s;
border-radius: 8px;
background-color: var(--jd-row-stripe);
border: 1px solid var(--jd-border);
border-left: 3px solid var(--jd-accent);
transition: all 0.2s;
}
.message-item:hover {
background-color: #ECF5FF;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: #eff6ff;
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}
.message-item-header {
@@ -730,13 +843,13 @@ export default {
.message-index {
font-size: 12px;
color: #909399;
color: var(--jd-muted);
font-weight: 500;
}
.message-content {
font-size: 13px;
color: #303133;
color: var(--jd-text);
line-height: 1.6;
white-space: pre-wrap;
word-break: break-word;
@@ -800,20 +913,20 @@ export default {
/* 按钮组样式 */
.button-group {
margin-bottom: 16px;
margin-bottom: 12px;
display: flex;
flex-wrap: wrap;
gap: 10px;
gap: 8px;
width: 100%;
}
.button-group .el-button {
margin-right: 0;
padding: 12px 24px;
font-size: 14px;
padding: 9px 14px;
font-size: 13px;
font-weight: 500;
flex: 1;
min-width: 80px;
min-width: 72px;
}
.button-group .el-button:last-child {
@@ -890,9 +1003,9 @@ export default {
margin-top: 16px;
margin-bottom: 12px;
padding: 12px 16px;
background-color: #F5F7FA;
border-radius: 4px;
border: 1px solid #DCDFE6;
background: linear-gradient(135deg, #fff8f0 0%, #fff4e6 38%, #ffffff 100%);
border-radius: 8px;
border: 1px solid #fdba74;
}
.history-field {
@@ -923,7 +1036,7 @@ export default {
.history-label {
font-size: 14px;
color: #606266;
color: var(--jd-muted);
font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
@@ -1012,9 +1125,10 @@ export default {
.history-column {
flex: 1;
border: 1px solid #DCDFE6;
border-radius: 4px;
border: 1px solid var(--jd-border);
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.history-header {
@@ -1022,10 +1136,10 @@ export default {
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background-color: #F5F7FA;
border-bottom: 1px solid #DCDFE6;
background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 72%);
border-bottom: 1px solid #bfdbfe;
font-weight: 600;
color: #303133;
color: var(--jd-text);
}
.history-content {
@@ -1048,26 +1162,27 @@ export default {
.history-item {
padding: 10px 12px;
margin-bottom: 8px;
border-radius: 4px;
background-color: #F9FAFC;
border-left: 3px solid #409EFF;
transition: all 0.3s;
border-radius: 8px;
background-color: var(--jd-row-stripe);
border: 1px solid var(--jd-border);
border-left: 3px solid var(--jd-accent);
transition: all 0.2s;
}
.history-item:hover {
background-color: #ECF5FF;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: #eff6ff;
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}
.history-time {
font-size: 12px;
color: #909399;
color: var(--jd-muted);
margin-bottom: 4px;
}
.history-text {
font-size: 13px;
color: #303133;
color: var(--jd-text);
line-height: 1.5;
white-space: pre-wrap;
word-break: break-all;

View File

@@ -226,7 +226,7 @@
aria-hidden="true"
/>
<div class="header-title-block">
<div class="order-id">{{ row.remark || row.orderId }}</div>
<div class="order-id">{{ row.orderId }}</div>
<el-tag
v-if="row.orderStatus != null"
:type="getOrderStatusType(row.orderStatus)"
@@ -324,7 +324,21 @@
class="card-summary-compact"
@click="toggleMobileOrderExpand(row)"
>
<span class="card-summary-line">{{ row.modelNumber || '—' }} · {{ toYuan(row.paymentAmount) }} · {{ toYuan(row.rebateAmount) }}<template v-if="row.distributionMark"> · {{ row.distributionMark }}</template></span>
<span class="card-summary-line">
<template v-if="row.distributionMark">
<span
class="card-distribution-mark-highlight jd-dist-mark-summary-pill"
:style="distributionMarkDisplayStyle(row.distributionMark)"
role="button"
tabindex="0"
title="点击编辑分销标识"
@click.stop="openDistributionMarkEditDialog(row)"
@keydown.enter.prevent.stop="openDistributionMarkEditDialog(row)"
>{{ row.distributionMark }}</span>
<span class="card-summary-sep"> · </span>
</template>
<span class="card-summary-meta">{{ row.modelNumber || '—' }} · {{ toYuan(row.paymentAmount) }} · {{ toYuan(row.rebateAmount) }}</span>
</span>
</div>
<el-collapse-transition>
@@ -349,17 +363,19 @@
<el-button type="primary" size="mini" plain @click="onThirdPartyOrderNoSave(row)">保存</el-button>
</div>
</div>
<div class="field-row">
<span class="field-label">标记</span>
<div class="field-value field-value--third-party-edit">
<el-input
v-model="row.distributionMark"
size="small"
clearable
placeholder="分销标识,失焦或保存写入"
@blur="onDistributionMarkBlur(row)"
/>
<el-button type="primary" size="mini" plain @click="onDistributionMarkSave(row)">保存</el-button>
<div class="field-row field-row--distribution-mark">
<span class="field-label">分销标识</span>
<div
class="field-value jd-dist-mark-mobile-tap"
title="点击编辑"
@click.stop="openDistributionMarkEditDialog(row)"
>
<span
class="jd-dist-mark-mobile-pill"
:class="[distributionMarkDisplayClass(row.distributionMark)]"
:style="distributionMarkDisplayStyle(row.distributionMark)"
>{{ distributionMarkCellLabel(row.distributionMark) }}</span>
<i class="el-icon-edit-outline jd-dist-mark-edit-ico" aria-hidden="true" />
</div>
</div>
<div class="field-row">
@@ -527,9 +543,24 @@
class="order-table jd-order-el-table">
<!-- 多选列仅桌面端显示 -->
<el-table-column v-if="!isMobile" type="selection" width="55" fixed="left" align="center"/>
<!-- 分销标识列置首相同标识稳定同色 -->
<el-table-column label="分销标识" prop="distributionMark" min-width="112" align="center" fixed="left" class-name="jd-col-distribution-mark">
<template slot-scope="scope">
<div
:class="['jd-dist-mark-cell', 'jd-dist-mark-cell--tap', distributionMarkDisplayClass(scope.row.distributionMark)]"
:style="distributionMarkDisplayStyle(scope.row.distributionMark)"
role="button"
tabindex="0"
title="点击编辑分销标识"
@click.stop="openDistributionMarkEditDialog(scope.row)"
@keydown.enter.prevent.stop="openDistributionMarkEditDialog(scope.row)"
>
<span class="jd-dist-mark-text">{{ distributionMarkCellLabel(scope.row.distributionMark) }}</span>
</div>
</template>
</el-table-column>
<!-- 核心信息列 -->
<el-table-column label="内部单号" prop="remark" width="120" sortable :fixed="isMobile ? false : 'left'"/>
<el-table-column label="订单号" prop="orderId" width="160"/>
<el-table-column label="单号" prop="orderId" width="160" :fixed="isMobile ? false : 'left'"/>
<el-table-column label="第三方单号" prop="thirdPartyOrderNo" min-width="188">
<template slot-scope="scope">
<template v-if="scope.row.thirdPartyOrderNo">
@@ -548,18 +579,6 @@
</el-table-column>
<!-- 业务信息列 -->
<el-table-column label="标记" prop="distributionMark" min-width="92" align="center">
<template slot-scope="scope">
<el-input
v-model="scope.row.distributionMark"
size="mini"
clearable
placeholder="标识"
@blur="onDistributionMarkBlur(scope.row)"
@keyup.enter.native="onDistributionMarkBlur(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="型号" prop="modelNumber" width="140"/>
<el-table-column label="地址" prop="address" min-width="220" show-overflow-tooltip class-name="address-cell">
<template slot-scope="scope">
@@ -1062,6 +1081,30 @@
<!-- 分销标识接收人配置 -->
<distribution-mark-touser-config v-model="showTouserConfig" @config-updated="handleTouserConfigUpdated" />
<!-- 分销标识点击列表单元格后编辑非行内快捷编辑 -->
<el-dialog
title="编辑分销标识"
:visible.sync="distributionMarkEditDialogVisible"
width="440px"
append-to-body
:close-on-click-modal="false"
@closed="onDistributionMarkEditDialogClosed"
>
<p v-if="distributionMarkEditRow" style="margin:0 0 12px;color:#909399;font-size:13px;">
订单号{{ distributionMarkEditRow.orderId }}
</p>
<el-input
v-model="distributionMarkEditDraft"
placeholder="分销标识"
clearable
@keyup.enter.native="confirmDistributionMarkEdit"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="distributionMarkEditDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmDistributionMarkEdit">保存</el-button>
</div>
</el-dialog>
<!-- 导入跟团返现 / 后返 Excel支持多文件一次提交后台依次处理 -->
<el-dialog
title="导入后返表(跟团返现等)"
@@ -1268,7 +1311,11 @@ export default {
/** 视口高度(桌面端用于矮窗口下自动收起「跟进状态」筛选) */
viewportHeight: typeof window !== 'undefined' ? window.innerHeight : 900,
/** 矮窗口下是否展开完整筛选(基础条件 / 跟进状态 / 查询) */
showDesktopExpandedFilters: true
showDesktopExpandedFilters: true,
/** 分销标识弹窗编辑 */
distributionMarkEditDialogVisible: false,
distributionMarkEditRow: null,
distributionMarkEditDraft: ''
}
},
computed: {
@@ -1308,6 +1355,23 @@ export default {
}, 0)
return has ? t : ''
},
/**
* 本页 list 中出现的分销标识(规范化后)去重、排序,再映射为连续下标。
* 同色只表示「本页内同一标识」,不同标识在本页一定不同色(色相按序号散开)。
*/
distributionMarkToneIndexByKey() {
const set = new Set()
for (const row of this.list || []) {
const k = this.normalizeDistributionMarkInput(row.distributionMark)
if (k) set.add(k)
}
const sorted = Array.from(set).sort()
const map = Object.create(null)
sorted.forEach((k, i) => {
map[k] = i
})
return map
},
actionButtons() {
// 移动端不展示顶部工具按钮(统一用底部导航与各页内操作)
if (this.isMobile) {
@@ -1381,6 +1445,43 @@ export default {
const m = String(mark).trim()
return m === 'F' || m.startsWith('F-')
},
distributionMarkCellLabel(mark) {
const k = this.normalizeDistributionMarkInput(mark)
return k || '点击编辑'
},
openDistributionMarkEditDialog(row) {
if (!row || row.id == null) return
this.distributionMarkEditRow = row
this.distributionMarkEditDraft = row.distributionMark == null ? '' : String(row.distributionMark)
this.distributionMarkEditDialogVisible = true
},
confirmDistributionMarkEdit() {
const row = this.distributionMarkEditRow
if (!row) return
row.distributionMark = this.distributionMarkEditDraft
this.saveDistributionMarkIfChanged(row, '分销标识已保存')
this.distributionMarkEditDialogVisible = false
},
onDistributionMarkEditDialogClosed() {
this.distributionMarkEditRow = null
this.distributionMarkEditDraft = ''
},
/** 空标识:仅用灰色底 class */
distributionMarkDisplayClass(mark) {
return this.normalizeDistributionMarkInput(mark) ? '' : 'jd-dist-tone-empty'
},
/** 非空:用本页 distributionMarkToneIndexByKey + 黄金角色相,避免哈希撞车 */
distributionMarkDisplayStyle(mark) {
const key = this.normalizeDistributionMarkInput(mark)
if (!key) return {}
const idx = this.distributionMarkToneIndexByKey[key]
if (idx == null) return {}
const hue = Math.round((idx * 222.49223594960218) % 360)
return {
background: `hsl(${hue}, 46%, 91%)`,
color: '#1e293b'
}
},
handleMainPagination() {
this.getList()
this.$nextTick(() => {
@@ -1834,12 +1935,6 @@ export default {
if (next === base) return
this.persistOrderRow(row, successMsg)
},
onDistributionMarkBlur(row) {
this.saveDistributionMarkIfChanged(row)
},
onDistributionMarkSave(row) {
this.saveDistributionMarkIfChanged(row, '分销标识已保存')
},
onOrderSellingPriceTypeChange(row) {
row.sellingPriceManual = 0
row.profitManual = 0
@@ -3757,6 +3852,25 @@ export default {
white-space: nowrap;
}
.mobile-order-card .card-distribution-mark-highlight {
font-size: 13px;
font-weight: 500;
letter-spacing: 0.01em;
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
}
.mobile-order-card .jd-dist-mark-summary-pill {
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.mobile-order-card .card-summary-sep {
color: #94a3b8;
font-weight: 400;
}
.mobile-order-card .card-content {
display: flex;
flex-direction: column;
@@ -4176,7 +4290,58 @@ export default {
min-width: 0;
}
/* 移动端卡片:第三方单号补录 */
/* 分销标识:单元格底色(本页同标识同色);点击弹窗编辑 */
.jd-dist-mark-cell {
padding: 3px 6px;
border-radius: 4px;
box-sizing: border-box;
min-height: 28px;
display: flex;
align-items: center;
justify-content: center;
}
.jd-dist-mark-cell.jd-dist-tone-empty {
background: #f4f4f5;
}
.jd-dist-mark-cell--tap {
cursor: pointer;
user-select: none;
}
.jd-dist-mark-text {
font-size: 13px;
font-weight: 400;
line-height: 1.4;
text-align: center;
word-break: break-all;
}
.jd-order-el-table ::v-deep td.jd-col-distribution-mark {
vertical-align: middle;
}
.mobile-order-card .jd-dist-mark-mobile-tap {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 6px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.mobile-order-card .jd-dist-mark-mobile-pill {
font-size: 14px;
font-weight: 400;
padding: 2px 8px;
border-radius: 4px;
max-width: 100%;
word-break: break-all;
}
.mobile-order-card .jd-dist-mark-edit-ico {
flex-shrink: 0;
color: #909399;
font-size: 14px;
}
/* 移动端卡片:第三方单号 / 分销标识等可编辑字段 */
.field-value--third-party-edit {
display: flex;
flex-direction: column;