Files
ruoyi-vue/src/views/system/jdorder/components/DistributionMarkTouserConfig.vue
2025-12-02 17:39:29 +08:00

654 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
:visible.sync="visible"
width="900px"
:close-on-click-modal="false"
@close="handleClose"
top="5vh"
>
<!-- 自定义标题 -->
<div slot="title" class="dialog-title">
<i class="el-icon-user"></i>
<span>分销标识接收人配置</span>
<el-tag v-if="hasConfigured" type="success" size="mini" style="margin-left: 10px;">
<i class="el-icon-success"></i> 已配置 {{ configuredCount }}
</el-tag>
</div>
<div class="config-container">
<!-- 左侧配置表单 -->
<div class="config-left">
<div class="config-section">
<div class="section-header">
<i class="el-icon-setting"></i>
<span>分销标识接收人映射</span>
<el-button
type="text"
size="mini"
icon="el-icon-plus"
@click="handleAddConfig"
style="margin-left: auto;"
>
添加配置
</el-button>
</div>
<div class="config-list">
<div
v-for="(item, index) in configList"
:key="index"
class="config-item"
>
<el-form-item label="分销标识" style="margin-bottom: 10px;">
<el-input
v-model="item.distributionMark"
placeholder="请输入分销标识F、PDD、H-TF"
size="small"
style="width: 200px;"
@blur="handleDistributionMarkChange(item, index)"
/>
<el-button
type="danger"
size="mini"
icon="el-icon-delete"
@click="handleRemoveConfig(index)"
style="margin-left: 10px;"
>
删除
</el-button>
</el-form-item>
<el-form-item label="接收人列表" style="margin-bottom: 8px;">
<el-input
v-model="item.touser"
placeholder="请输入接收人列表多个用逗号分隔abc,bcd,efg"
size="small"
/>
<div class="item-hint">
<i class="el-icon-info"></i>
配置说明当订单的分销标识为"{{ item.distributionMark || '分销标识' }}"将发送给这些接收人
</div>
<div class="item-hint" style="margin-top: 4px;">
<i class="el-icon-key"></i>
配置键名logistics.push.touser.{{ item.distributionMark || '分销标识' }}
</div>
</el-form-item>
</div>
<div v-if="configList.length === 0" class="empty-state">
<i class="el-icon-document-add"></i>
<p>暂无配置点击"添加配置"开始设置</p>
</div>
</div>
</div>
</div>
<!-- 右侧状态信息 -->
<div class="config-right">
<!-- 配置状态提示 -->
<div class="status-card">
<div class="status-icon" :class="hasConfigured ? 'success' : 'warning'">
<i :class="hasConfigured ? 'el-icon-success' : 'el-icon-warning'"></i>
</div>
<div class="status-text">
<div class="status-title">{{ hasConfigured ? '配置完成' : '配置未完成' }}</div>
<div class="status-desc">
{{ hasConfigured ? `已配置 ${configuredCount} 个分销标识的接收人` : '请至少配置一个分销标识的接收人' }}
</div>
</div>
</div>
<!-- 快速帮助 -->
<div class="help-card">
<div class="card-header">
<i class="el-icon-question"></i>
<span>配置说明</span>
</div>
<div class="help-content">
<div class="help-item">
<i class="el-icon-check"></i>
<span><strong>分销标识</strong>必须与订单中的分销标识完全匹配区分大小写</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span><strong>接收人列表</strong>企业微信用户ID多个用逗号分隔例如abc,bcd,efg</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span>配置会自动保存到系统配置表中</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span>推送时会根据订单的分销标识自动匹配对应的接收人列表</span>
</div>
</div>
</div>
<!-- 常见分销标识 -->
<div class="help-card">
<div class="card-header">
<i class="el-icon-collection-tag"></i>
<span>常见分销标识</span>
</div>
<div class="help-content">
<div class="tag-list">
<el-tag
v-for="mark in commonDistributionMarks"
:key="mark"
size="small"
@click="handleQuickAdd(mark)"
style="cursor: pointer; margin: 4px;"
>
{{ mark }}
</el-tag>
</div>
</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div slot="footer" class="footer-buttons">
<div class="footer-left">
<el-button @click="handleLoadFromOrders" :loading="loadLoading" icon="el-icon-refresh" size="small">
从订单加载分销标识
</el-button>
</div>
<div class="footer-right">
<el-button @click="handleClose" size="small">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading" size="small">
<i class="el-icon-check"></i> 保存配置
</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import { listConfig, getConfigKey, addConfig, updateConfig } from '@/api/system/config'
import { listJDOrders } from '@/api/system/jdorder'
export default {
name: 'DistributionMarkTouserConfig',
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
visible: false,
configList: [],
saveLoading: false,
loadLoading: false,
commonDistributionMarks: ['F', 'PDD', 'H-TF', 'H', 'TF'],
configKeyPrefix: 'logistics.push.touser.'
}
},
computed: {
hasConfigured() {
return this.configList.some(item =>
item.distributionMark && item.touser && item.distributionMark.trim() && item.touser.trim()
)
},
configuredCount() {
return this.configList.filter(item =>
item.distributionMark && item.touser && item.distributionMark.trim() && item.touser.trim()
).length
}
},
watch: {
value(val) {
this.visible = val
if (val) {
this.loadConfig()
}
},
visible(val) {
this.$emit('input', val)
}
},
methods: {
/** 加载当前配置 */
async loadConfig() {
try {
// 先尝试从系统配置中加载已有的配置
// 由于我们不知道有哪些分销标识,先加载所有以 logistics.push.touser. 开头的配置
const res = await listConfig({
configKey: 'logistics.push.touser.',
pageNum: 1,
pageSize: 100
})
if (res.code === 200 && res.rows && res.rows.length > 0) {
this.configList = res.rows
.filter(item => item.configKey && item.configKey.startsWith(this.configKeyPrefix))
.map(item => {
const distributionMark = item.configKey.replace(this.configKeyPrefix, '')
return {
distributionMark: distributionMark,
touser: item.configValue || '',
configId: item.configId,
configKey: item.configKey,
configName: item.configName
}
})
}
// 如果没有配置,至少添加一个空项
if (this.configList.length === 0) {
this.configList.push({
distributionMark: '',
touser: '',
configId: null,
configKey: '',
configName: ''
})
}
} catch (e) {
console.error('加载配置失败:', e)
// 即使加载失败,也至少添加一个空项
if (this.configList.length === 0) {
this.configList.push({
distributionMark: '',
touser: '',
configId: null,
configKey: '',
configName: ''
})
}
}
},
/** 从订单中加载分销标识 */
async handleLoadFromOrders() {
this.loadLoading = true
try {
const res = await listJDOrders({
pageNum: 1,
pageSize: 1000
})
if (res.code === 200 && res.rows) {
// 提取所有不重复的分销标识
const distributionMarks = [...new Set(
res.rows
.map(order => order.distributionMark)
.filter(mark => mark && mark.trim())
)].sort()
// 为每个分销标识添加配置项(如果不存在)
distributionMarks.forEach(mark => {
const exists = this.configList.some(item => item.distributionMark === mark)
if (!exists) {
this.configList.push({
distributionMark: mark,
touser: '',
configId: null,
configKey: this.configKeyPrefix + mark,
configName: `${mark}分销标识接收人`
})
}
})
this.$message.success(`已加载 ${distributionMarks.length} 个分销标识`)
}
} catch (e) {
this.$message.error('加载分销标识失败:' + (e.message || '未知错误'))
} finally {
this.loadLoading = false
}
},
/** 快速添加分销标识 */
handleQuickAdd(mark) {
const exists = this.configList.some(item => item.distributionMark === mark)
if (!exists) {
this.configList.push({
distributionMark: mark,
touser: '',
configId: null,
configKey: this.configKeyPrefix + mark,
configName: `${mark}分销标识接收人`
})
this.$message.success(`已添加分销标识:${mark}`)
} else {
this.$message.info(`分销标识 ${mark} 已存在`)
}
},
/** 添加配置项 */
handleAddConfig() {
this.configList.push({
distributionMark: '',
touser: '',
configId: null,
configKey: '',
configName: ''
})
},
/** 删除配置项 */
handleRemoveConfig(index) {
this.configList.splice(index, 1)
// 如果删除后列表为空,至少保留一个空项
if (this.configList.length === 0) {
this.handleAddConfig()
}
},
/** 分销标识变化时更新配置键名 */
handleDistributionMarkChange(item, index) {
if (item.distributionMark && item.distributionMark.trim()) {
item.configKey = this.configKeyPrefix + item.distributionMark.trim()
item.configName = `${item.distributionMark.trim()}分销标识接收人`
} else {
item.configKey = ''
item.configName = ''
}
},
/** 保存配置 */
async handleSave() {
// 验证配置
const validConfigs = this.configList.filter(item =>
item.distributionMark && item.distributionMark.trim() &&
item.touser && item.touser.trim()
)
if (validConfigs.length === 0) {
this.$message.warning('请至少配置一个有效的分销标识和接收人')
return
}
// 检查是否有重复的分销标识
const marks = validConfigs.map(item => item.distributionMark.trim())
const uniqueMarks = [...new Set(marks)]
if (marks.length !== uniqueMarks.length) {
this.$message.warning('存在重复的分销标识,请检查')
return
}
this.saveLoading = true
try {
// 保存每个配置项
const savePromises = validConfigs.map(async (item) => {
const configData = {
configKey: this.configKeyPrefix + item.distributionMark.trim(),
configName: `${item.distributionMark.trim()}分销标识接收人`,
configValue: item.touser.trim(),
configType: 'N',
remark: `分销标识 ${item.distributionMark.trim()} 对应的企业微信接收人列表`
}
if (item.configId) {
// 更新现有配置
configData.configId = item.configId
return updateConfig(configData)
} else {
// 新增配置
return addConfig(configData)
}
})
await Promise.all(savePromises)
this.$message.success(`配置保存成功!共保存 ${validConfigs.length} 项配置`)
// 重新加载配置
await this.loadConfig()
this.$emit('config-updated')
} catch (e) {
this.$message.error('保存失败:' + (e.message || '未知错误'))
} finally {
this.saveLoading = false
}
},
/** 关闭对话框 */
handleClose() {
this.visible = false
}
}
}
</script>
<style scoped>
/* 标题样式 */
.dialog-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 500;
}
.dialog-title i {
margin-right: 8px;
font-size: 18px;
}
/* 容器布局 */
.config-container {
display: flex;
gap: 20px;
min-height: 400px;
}
.config-left {
flex: 1;
display: flex;
flex-direction: column;
gap: 15px;
}
.config-right {
width: 300px;
display: flex;
flex-direction: column;
gap: 15px;
}
/* 配置区块 */
.config-section {
background: #f5f7fa;
border-radius: 6px;
padding: 15px;
}
.section-header {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 2px solid #e4e7ed;
}
.section-header i {
margin-right: 6px;
font-size: 16px;
color: #409eff;
}
/* 配置列表 */
.config-list {
display: flex;
flex-direction: column;
gap: 15px;
max-height: 500px;
overflow-y: auto;
}
.config-item {
background: white;
border: 1px solid #e4e7ed;
border-radius: 6px;
padding: 12px;
}
.item-header {
display: flex;
align-items: center;
}
.item-content {
margin-top: 8px;
}
.item-hint {
font-size: 12px;
color: #909399;
margin-top: 6px;
display: flex;
align-items: center;
gap: 4px;
}
.item-hint i {
color: #409eff;
}
.empty-state {
text-align: center;
padding: 40px 20px;
color: #909399;
}
.empty-state i {
font-size: 48px;
margin-bottom: 10px;
display: block;
}
/* 状态卡片 */
.status-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
padding: 20px;
color: white;
display: flex;
align-items: center;
gap: 15px;
box-shadow: 0 2px 12px rgba(102, 126, 234, 0.3);
}
.status-card.warning {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.status-icon {
width: 48px;
height: 48px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
flex-shrink: 0;
}
.status-icon.success {
background: rgba(103, 194, 58, 0.2);
}
.status-icon.warning {
background: rgba(230, 162, 60, 0.2);
}
.status-text {
flex: 1;
}
.status-title {
font-size: 16px;
font-weight: 500;
margin-bottom: 5px;
}
.status-desc {
font-size: 12px;
opacity: 0.9;
line-height: 1.5;
}
/* 帮助卡片 */
.help-card {
background: white;
border: 1px solid #e4e7ed;
border-radius: 6px;
overflow: hidden;
}
.card-header {
background: #f5f7fa;
padding: 12px 15px;
font-size: 14px;
font-weight: 500;
color: #303133;
display: flex;
align-items: center;
border-bottom: 1px solid #e4e7ed;
}
.card-header i {
margin-right: 6px;
color: #409eff;
}
.help-content {
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
}
.help-item {
display: flex;
align-items: flex-start;
gap: 8px;
font-size: 13px;
color: #606266;
line-height: 1.6;
}
.help-item i {
color: #67c23a;
margin-top: 2px;
flex-shrink: 0;
}
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
/* 底部按钮 */
.footer-buttons {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
}
.footer-left,
.footer-right {
display: flex;
gap: 8px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.config-container {
flex-direction: column;
}
.config-right {
width: 100%;
}
}
</style>