1
This commit is contained in:
@@ -19,6 +19,14 @@ export function listQuickRecordModelOptions() {
|
||||
})
|
||||
}
|
||||
|
||||
/** 快捷录单页:型号后缀店铺选项(系统参数 quickRecord.modelShopOptions) */
|
||||
export function listQuickRecordShopOptions() {
|
||||
return request({
|
||||
url: '/system/jdorder/quickRecord/shopOptions',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// JD订单详情
|
||||
export function getJDOrder(id) {
|
||||
return request({
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="visible"
|
||||
width="640px"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
@close="handleClose"
|
||||
>
|
||||
<div slot="title" class="dialog-title">
|
||||
<i class="el-icon-shop"></i>
|
||||
<span>快捷录单型号店铺选项</span>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading">
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="每行一条,格式:短前缀(完整店名)。录单时仅将短前缀拼接到型号末尾。"
|
||||
style="margin-bottom: 12px;"
|
||||
/>
|
||||
<el-input
|
||||
v-model="configText"
|
||||
type="textarea"
|
||||
:rows="8"
|
||||
placeholder="海尔官旗(海尔官方旗舰店) 海尔厨房(海尔厨房电器官方旗舰店)"
|
||||
/>
|
||||
<p class="hint">参数键名:quickRecord.modelShopOptions(保存至系统参数)</p>
|
||||
</div>
|
||||
|
||||
<div slot="footer">
|
||||
<el-button size="small" @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" size="small" :loading="saveLoading" @click="handleSave">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listConfig, addConfig, updateConfig } from '@/api/system/config'
|
||||
|
||||
const CONFIG_KEY = 'quickRecord.modelShopOptions'
|
||||
const CONFIG_NAME = '快捷录单型号店铺选项'
|
||||
|
||||
export default {
|
||||
name: 'QuickRecordModelShopConfig',
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
loading: false,
|
||||
saveLoading: false,
|
||||
configText: '',
|
||||
configId: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.visible = val
|
||||
if (val) {
|
||||
this.loadConfig()
|
||||
}
|
||||
},
|
||||
visible(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadConfig() {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await listConfig({
|
||||
configKey: CONFIG_KEY,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
const row = res && res.rows && res.rows.find(r => r && r.configKey === CONFIG_KEY)
|
||||
if (row) {
|
||||
this.configId = row.configId
|
||||
this.configText = row.configValue || ''
|
||||
} else {
|
||||
this.configId = null
|
||||
this.configText = ''
|
||||
}
|
||||
} catch (e) {
|
||||
this.configId = null
|
||||
this.configText = ''
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async handleSave() {
|
||||
this.saveLoading = true
|
||||
try {
|
||||
const payload = {
|
||||
configName: CONFIG_NAME,
|
||||
configKey: CONFIG_KEY,
|
||||
configValue: (this.configText || '').trim(),
|
||||
configType: 'N'
|
||||
}
|
||||
if (this.configId) {
|
||||
payload.configId = this.configId
|
||||
await updateConfig(payload)
|
||||
} else {
|
||||
await addConfig(payload)
|
||||
}
|
||||
this.$modal.msgSuccess('店铺选项已保存')
|
||||
this.$emit('saved')
|
||||
this.handleClose()
|
||||
} catch (e) {
|
||||
this.$modal.msgError('保存失败,请确认有参数管理权限')
|
||||
} finally {
|
||||
this.saveLoading = false
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.visible = false
|
||||
this.$emit('input', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dialog-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 10px 0 0;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
@@ -14,19 +14,53 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="型号" required>
|
||||
<div class="model-row">
|
||||
<el-autocomplete
|
||||
v-model="form.model"
|
||||
class="model-input-full"
|
||||
class="model-input-base"
|
||||
:fetch-suggestions="queryModels"
|
||||
placeholder="可输入、可改;点选联想项会带出最近一单付款 / 后返"
|
||||
placeholder="型号本体;点选历史型号会拆分店铺并带出付款/后返"
|
||||
clearable
|
||||
:trigger-on-focus="true"
|
||||
@select="onModelSuggestionSelect"
|
||||
@blur="onModelBlur"
|
||||
>
|
||||
<template slot-scope="{ item }">
|
||||
<span class="model-suggest-label">{{ item.label }}</span>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<el-select
|
||||
v-model="form.shopPrefix"
|
||||
class="model-shop-select"
|
||||
:placeholder="shopOptions.length ? '店铺(必选)' : '店铺'"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in shopOptions"
|
||||
:key="opt.prefix"
|
||||
:label="opt.label"
|
||||
:value="opt.prefix"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
v-if="!isMobile"
|
||||
type="text"
|
||||
class="model-shop-config-btn"
|
||||
icon="el-icon-setting"
|
||||
title="配置型号店铺选项"
|
||||
@click="showShopConfig = true"
|
||||
/>
|
||||
</div>
|
||||
<p class="model-shop-hint">
|
||||
<template v-if="shopOptions.length">
|
||||
落库型号 = 上方输入 + 所选店铺前缀(如 W5000PLUS2.0白 + 海尔厨房 → W5000PLUS2.0白海尔厨房)
|
||||
</template>
|
||||
<template v-else>
|
||||
尚未配置店铺选项,录单时不强制选择店铺。
|
||||
</template>
|
||||
<el-button type="text" size="mini" @click="showShopConfig = true">配置店铺选项</el-button>
|
||||
</p>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单地址" required>
|
||||
<el-input
|
||||
@@ -114,15 +148,19 @@
|
||||
<el-button type="primary" :loading="verifyLoading" @click="handleVerify">确认录单</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<quick-record-model-shop-config v-model="showShopConfig" @saved="loadShopOptions" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { executeInstruction, executeInstructionWithForce } from '@/api/system/instruction'
|
||||
import { listQuickRecordModelOptions } from '@/api/system/jdorder'
|
||||
import { listQuickRecordModelOptions, listQuickRecordShopOptions } from '@/api/system/jdorder'
|
||||
import QuickRecordModelShopConfig from './components/QuickRecordModelShopConfig.vue'
|
||||
|
||||
export default {
|
||||
name: 'FadanQuickRecord',
|
||||
components: { QuickRecordModelShopConfig },
|
||||
props: {
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
@@ -134,6 +172,7 @@ export default {
|
||||
form: {
|
||||
markSuffix: '',
|
||||
model: '',
|
||||
shopPrefix: '',
|
||||
address: '',
|
||||
link: '',
|
||||
thirdPartyOrderNoText: '',
|
||||
@@ -152,11 +191,14 @@ export default {
|
||||
verifyMessage: '',
|
||||
verifyLoading: false,
|
||||
pendingCommand: '',
|
||||
modelOptions: []
|
||||
modelOptions: [],
|
||||
shopOptions: [],
|
||||
showShopConfig: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadModelOptions()
|
||||
this.loadShopOptions()
|
||||
},
|
||||
computed: {
|
||||
dialogWidth() {
|
||||
@@ -261,6 +303,59 @@ export default {
|
||||
// 静默失败,不影响手输型号
|
||||
}
|
||||
},
|
||||
async loadShopOptions() {
|
||||
try {
|
||||
const res = await listQuickRecordShopOptions()
|
||||
if (!(res && (res.code === 200 || res.msg === '操作成功'))) {
|
||||
return
|
||||
}
|
||||
const rows = Array.isArray(res.data) ? res.data : []
|
||||
this.shopOptions = rows
|
||||
.filter(o => o && String(o.prefix || '').trim())
|
||||
.map(o => ({
|
||||
prefix: String(o.prefix).trim(),
|
||||
fullName: o.fullName || '',
|
||||
label: o.label || o.prefix
|
||||
}))
|
||||
.sort((a, b) => b.prefix.length - a.prefix.length)
|
||||
} catch (e) {
|
||||
this.shopOptions = []
|
||||
}
|
||||
},
|
||||
/** 从完整型号末尾匹配店铺前缀(长前缀优先),用于回显 */
|
||||
parseModelWithShop(fullModel) {
|
||||
const full = String(fullModel || '').trim()
|
||||
if (!full || !this.shopOptions.length) {
|
||||
return { base: full, prefix: '' }
|
||||
}
|
||||
for (const opt of this.shopOptions) {
|
||||
const p = opt.prefix
|
||||
if (p && full.endsWith(p) && full.length > p.length) {
|
||||
return { base: full.slice(0, -p.length), prefix: p }
|
||||
}
|
||||
}
|
||||
return { base: full, prefix: '' }
|
||||
},
|
||||
applyModelWithShop(fullModel) {
|
||||
const parsed = this.parseModelWithShop(fullModel)
|
||||
this.form.model = parsed.base
|
||||
this.form.shopPrefix = parsed.prefix
|
||||
return parsed
|
||||
},
|
||||
onModelBlur() {
|
||||
if (!this.form.model || !this.shopOptions.length) return
|
||||
const parsed = this.parseModelWithShop(this.form.model)
|
||||
if (parsed.prefix) {
|
||||
this.form.model = parsed.base
|
||||
this.form.shopPrefix = parsed.prefix
|
||||
}
|
||||
},
|
||||
buildFullModelNumber() {
|
||||
const base = (this.form.model || '').trim()
|
||||
const prefix = (this.form.shopPrefix || '').trim()
|
||||
if (!base) return ''
|
||||
return prefix ? base + prefix : base
|
||||
},
|
||||
queryModels(queryString, cb) {
|
||||
const q = (queryString || '').trim().toLowerCase()
|
||||
const rows = this.modelOptions
|
||||
@@ -268,20 +363,27 @@ export default {
|
||||
const m = String(o.modelNumber || '').trim()
|
||||
if (!m) return false
|
||||
if (!q) return true
|
||||
return m.toLowerCase().includes(q)
|
||||
const parsed = this.parseModelWithShop(m)
|
||||
return m.toLowerCase().includes(q) || parsed.base.toLowerCase().includes(q)
|
||||
})
|
||||
.slice(0, 100)
|
||||
cb(
|
||||
rows.map(o => ({
|
||||
value: String(o.modelNumber).trim(),
|
||||
label: this.modelOptionLabel(o)
|
||||
}))
|
||||
rows.map(o => {
|
||||
const full = String(o.modelNumber).trim()
|
||||
const parsed = this.parseModelWithShop(full)
|
||||
const displayBase = parsed.base || full
|
||||
return {
|
||||
value: full,
|
||||
label: this.modelOptionLabel({ ...o, modelNumber: displayBase })
|
||||
}
|
||||
})
|
||||
)
|
||||
},
|
||||
/** 仅从联想列表点选时回填金额;型号本身为输入框,选后仍可继续编辑 */
|
||||
/** 仅从联想列表点选时回填金额;型号拆分为本体 + 店铺前缀 */
|
||||
onModelSuggestionSelect(item) {
|
||||
if (!item || !item.value) return
|
||||
const key = String(item.value).trim()
|
||||
this.applyModelWithShop(key)
|
||||
const hit = this.modelOptions.find(o => o && String(o.modelNumber || '').trim() === key)
|
||||
if (!hit) return
|
||||
const payRaw = hit.lastPaymentAmount
|
||||
@@ -291,9 +393,18 @@ export default {
|
||||
},
|
||||
buildCommand() {
|
||||
const mark = this.buildDistributionMark()
|
||||
const model = (this.form.model || '').trim()
|
||||
this.onModelBlur()
|
||||
const model = this.buildFullModelNumber()
|
||||
this.normalizeAddressField()
|
||||
const address = (this.form.address || '').trim()
|
||||
if (!(this.form.model || '').trim()) {
|
||||
this.$modal.msgError('请填写型号')
|
||||
return null
|
||||
}
|
||||
if (this.shopOptions.length && !this.form.shopPrefix) {
|
||||
this.$modal.msgError('请选择型号对应店铺')
|
||||
return null
|
||||
}
|
||||
if (!model) {
|
||||
this.$modal.msgError('请填写型号')
|
||||
return null
|
||||
@@ -506,6 +617,7 @@ export default {
|
||||
this.form = {
|
||||
markSuffix: '',
|
||||
model: '',
|
||||
shopPrefix: '',
|
||||
address: '',
|
||||
link: '',
|
||||
thirdPartyOrderNoText: '',
|
||||
@@ -582,6 +694,43 @@ export default {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.model-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.model-input-base {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.model-shop-select {
|
||||
width: 220px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.model-shop-config-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 4px;
|
||||
}
|
||||
|
||||
.model-shop-hint {
|
||||
margin: 6px 0 0;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.fadan-quick-record--mobile .model-row {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fadan-quick-record--mobile .model-shop-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.model-input-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user