refactor(shop): 重构分销商设置存储结构并优化数据处理逻辑

- 将单个设置对象改为按类型分组的映射结构,支持基础设置、分销商条件、结算等功能模块
- 新增 getBooleanFlag、getNumberFlag、pickEnumValue 等工具函数统一数据转换逻辑
- 实现 ensurePath 和 setWordValue 函数用于深层对象路径操作和文案配置
- 优化图片上传相关函数 getUploadUrl 和 toUploadFileList 的 URL 获取逻辑
- 将整体保存逻辑拆分为按设置类型分别保存的 saveSettingItem 方法
- 更新分销商类型显示,将"配送员"修改为"总分销商"以符合业务需求
- 调整精度控制从4位小数改为3位小数以匹配实际业务场景
This commit is contained in:
2026-02-05 16:10:37 +08:00
parent 73af733309
commit 355eada582
3 changed files with 218 additions and 66 deletions

View File

@@ -245,10 +245,16 @@
const activeTab = ref('basic'); const activeTab = ref('basic');
// 保存状态 // 保存状态
const saving = ref(false); const saving = ref(false);
const currentSetting = ref<ShopDealerSetting | null>(null); const settingMap = ref<Record<string, ShopDealerSetting>>({});
const hasSetting = ref(false); const settingValuesMap = ref<Record<string, any>>({});
const SETTING_KEY = 'dealer_setting'; const settingMeta = {
const SETTING_DESCRIPTION = '分销商设置'; basic: '基础设置',
condition: '分销商条件',
settlement: '结算',
license: '申请协议',
words: '自定义文字',
background: '页面背景图'
};
// 基础设置 // 基础设置
const basicSettings = reactive({ const basicSettings = reactive({
@@ -289,19 +295,61 @@
backgroundImages: [] backgroundImages: []
}); });
const applySettingGroup = (target: Record<string, any>, source?: any) => { const getBooleanFlag = (value: any) => value === 1 || value === true;
if (source && typeof source === 'object') { const getNumberFlag = (value: any) => (value ? 1 : 0);
Object.assign(target, source); const pickEnumValue = (value: any, options: number[], fallback: number) =>
} options.includes(value) ? value : fallback;
const ensurePath = (root: Record<string, any>, path: string[]) => {
let current = root;
path.forEach((key) => {
if (!current[key] || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
});
return current;
}; };
const applySettingValues = (values: any) => { const setWordValue = (
applySettingGroup(basicSettings, values?.basic); root: Record<string, any>,
applySettingGroup(commissionSettings, values?.commission); path: string[],
applySettingGroup(withdrawSettings, values?.withdraw); value: string
applySettingGroup(agreementSettings, values?.agreement); ) => {
applySettingGroup(notificationSettings, values?.notification); const node = ensurePath(root, path);
applySettingGroup(pageSettings, values?.page); if (typeof node.default !== 'string') {
node.default = value;
}
node.value = value;
};
const getUploadUrl = (fileList: any[]) => {
if (!Array.isArray(fileList) || fileList.length === 0) {
return '';
}
const file = fileList[0];
return (
file?.url ||
file?.thumbUrl ||
file?.response?.url ||
file?.response?.data?.url ||
file?.response?.data?.path ||
''
);
};
const toUploadFileList = (url?: string) => {
if (!url) {
return [];
}
return [
{
uid: 'background-0',
name: '背景图',
status: 'done',
url
}
];
}; };
/* 图片预览 */ /* 图片预览 */
@@ -313,73 +361,177 @@
const loadSettings = async () => { const loadSettings = async () => {
try { try {
const list = await listShopDealerSetting(); const list = await listShopDealerSetting();
const setting = const nextMap: Record<string, ShopDealerSetting> = {};
list.find((item) => item.key === SETTING_KEY) ?? list[0]; const nextValues: Record<string, any> = {};
if (!setting) { list.forEach((item) => {
hasSetting.value = false; if (!item.key) {
currentSetting.value = null; return;
return; }
nextMap[item.key] = item;
if (item.values) {
try {
nextValues[item.key] = JSON.parse(item.values);
} catch (error) {
console.warn('解析设置失败:', item.key, error);
}
}
});
settingMap.value = nextMap;
settingValuesMap.value = nextValues;
const basicValue = nextValues.basic || {};
basicSettings.enableDistribution = getBooleanFlag(basicValue.is_open);
basicSettings.distributionLevel = basicValue.level ?? 3;
basicSettings.dealerSelfBuy = getBooleanFlag(basicValue.self_buy);
const conditionValue = nextValues.condition || {};
commissionSettings.applyType = pickEnumValue(
conditionValue.become,
[10, 20],
commissionSettings.applyType
);
const settlementValue = nextValues.settlement || {};
commissionSettings.settlementType = pickEnumValue(
settlementValue.settle_days ?? settlementValue.settlement_type,
[10, 20],
commissionSettings.settlementType
);
commissionSettings.minWithdrawAmount =
settlementValue.min_money ?? commissionSettings.minWithdrawAmount;
withdrawSettings.withdrawMethods = Array.isArray(settlementValue.pay_type)
? settlementValue.pay_type
: withdrawSettings.withdrawMethods;
withdrawSettings.withdrawFeeRate =
typeof settlementValue.fee_rate === 'number'
? settlementValue.fee_rate
: withdrawSettings.withdrawFeeRate;
withdrawSettings.withdrawAudit =
settlementValue.audit === undefined
? withdrawSettings.withdrawAudit
: getBooleanFlag(settlementValue.audit);
const licenseValue = nextValues.license || {};
if (licenseValue.license) {
agreementSettings.dealerAgreement = licenseValue.license;
} }
currentSetting.value = setting; const wordsValue = nextValues.words || {};
hasSetting.value = true; if (wordsValue.index?.title?.value) {
if (setting.values) { pageSettings.centerTitle = wordsValue.index.title.value;
try {
const parsed = JSON.parse(setting.values);
applySettingValues(parsed);
} catch (error) {
console.warn('解析设置失败:', error);
message.warning('设置数据解析失败,已使用默认值');
}
} }
if (wordsValue.apply?.words?.wait_audit?.value) {
notificationSettings.applySuccessText =
wordsValue.apply.words.wait_audit.value;
}
if (wordsValue.apply?.words?.fail?.value) {
notificationSettings.applyFailText = wordsValue.apply.words.fail.value;
}
if (wordsValue.withdraw_apply?.words?.success?.value) {
notificationSettings.withdrawSuccessText =
wordsValue.withdraw_apply.words.success.value;
}
const backgroundValue = nextValues.background || {};
const backgroundUrl =
backgroundValue.index ||
backgroundValue.apply ||
backgroundValue.withdraw_apply;
pageSettings.backgroundImages = toUploadFileList(backgroundUrl);
} catch (error) { } catch (error) {
console.error('加载设置失败:', error); console.error('加载设置失败:', error);
hasSetting.value = false;
currentSetting.value = null;
message.error('加载设置失败'); message.error('加载设置失败');
} }
}; };
const saveSettingItem = async (
key: keyof typeof settingMeta,
values: Record<string, any>
) => {
const existSetting = settingMap.value[key];
const payload: ShopDealerSetting = {
...(existSetting || {}),
key,
describe: existSetting?.describe ?? settingMeta[key],
values: JSON.stringify(values),
updateTime: Date.now()
};
const saveOrUpdate = existSetting
? updateShopDealerSetting
: addShopDealerSetting;
await saveOrUpdate(payload);
settingMap.value[key] = payload;
settingValuesMap.value[key] = values;
};
/* 保存设置 */ /* 保存设置 */
const saveSettings = async () => { const saveSettings = async () => {
saving.value = true; saving.value = true;
try { try {
// 收集所有设置数据 const basicValues = {
const allSettings = { is_open: getNumberFlag(basicSettings.enableDistribution),
basic: { ...basicSettings }, level: basicSettings.distributionLevel,
commission: { ...commissionSettings }, self_buy: getNumberFlag(basicSettings.dealerSelfBuy)
withdraw: { ...withdrawSettings },
agreement: { ...agreementSettings },
notification: { ...notificationSettings },
page: {
...pageSettings,
backgroundImages: [...pageSettings.backgroundImages]
}
}; };
console.log('保存设置:', allSettings); const conditionValues = {
...(settingValuesMap.value.condition || {}),
const payload: ShopDealerSetting = { become: commissionSettings.applyType
...currentSetting.value,
key: currentSetting.value?.key ?? SETTING_KEY,
describe: currentSetting.value?.describe ?? SETTING_DESCRIPTION,
values: JSON.stringify(allSettings),
updateTime: Date.now()
}; };
const saveOrUpdate = hasSetting.value const settlementValues = {
? updateShopDealerSetting ...(settingValuesMap.value.settlement || {}),
: addShopDealerSetting; pay_type: [...withdrawSettings.withdrawMethods],
await saveOrUpdate(payload); min_money: commissionSettings.minWithdrawAmount,
settle_days: commissionSettings.settlementType,
fee_rate: withdrawSettings.withdrawFeeRate,
audit: getNumberFlag(withdrawSettings.withdrawAudit)
};
if (!hasSetting.value) { const licenseValues = {
await loadSettings(); license: agreementSettings.dealerAgreement
} else { };
currentSetting.value = payload;
}
// 模拟保存 const wordsValues = {
await new Promise((resolve) => setTimeout(resolve, 1000)); ...(settingValuesMap.value.words || {})
};
setWordValue(wordsValues, ['index', 'title'], pageSettings.centerTitle);
setWordValue(
wordsValues,
['apply', 'words', 'wait_audit'],
notificationSettings.applySuccessText
);
setWordValue(
wordsValues,
['apply', 'words', 'fail'],
notificationSettings.applyFailText
);
setWordValue(
wordsValues,
['withdraw_apply', 'words', 'success'],
notificationSettings.withdrawSuccessText
);
const backgroundUrl = getUploadUrl(pageSettings.backgroundImages);
const backgroundValues = {
...(settingValuesMap.value.background || {}),
index: backgroundUrl || settingValuesMap.value.background?.index || '',
apply: backgroundUrl || settingValuesMap.value.background?.apply || '',
withdraw_apply:
backgroundUrl || settingValuesMap.value.background?.withdraw_apply || ''
};
await saveSettingItem('basic', basicValues);
await saveSettingItem('condition', conditionValues);
await saveSettingItem('settlement', settlementValues);
await saveSettingItem('license', licenseValues);
await saveSettingItem('words', wordsValues);
await saveSettingItem('background', backgroundValues);
await loadSettings();
message.success('设置保存成功'); message.success('设置保存成功');
} catch (error) { } catch (error) {

View File

@@ -40,7 +40,7 @@
<a-select v-model:value="form.type" placeholder="请选择类型"> <a-select v-model:value="form.type" placeholder="请选择类型">
<a-select-option :value="0">分销商</a-select-option> <a-select-option :value="0">分销商</a-select-option>
<a-select-option :value="1">门店</a-select-option> <a-select-option :value="1">门店</a-select-option>
<a-select-option :value="2">配送员</a-select-option> <a-select-option :value="2">总分销商</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
@@ -136,7 +136,7 @@
class="ele-fluid" class="ele-fluid"
:min="0" :min="0"
:max="1" :max="1"
:precision="4" :precision="3"
stringMode stringMode
:disabled="true" :disabled="true"
placeholder="例如 0.007" placeholder="例如 0.007"

View File

@@ -26,7 +26,7 @@
<template v-if="column.key === 'type'"> <template v-if="column.key === 'type'">
<a-tag v-if="record.type === 0">分销商</a-tag> <a-tag v-if="record.type === 0">分销商</a-tag>
<a-tag v-if="record.type === 1" color="orange">门店</a-tag> <a-tag v-if="record.type === 1" color="orange">门店</a-tag>
<a-tag v-if="record.type === 2" color="purple">配送员</a-tag> <a-tag v-if="record.type === 2" color="purple">总分销商</a-tag>
</template> </template>
<template v-if="column.key === 'qrcode'"> <template v-if="column.key === 'qrcode'">
<QrcodeOutlined :style="{fontSize: '24px'}" @click="openQrCode(record)" /> <QrcodeOutlined :style="{fontSize: '24px'}" @click="openQrCode(record)" />