refactor(shop): 重构分销商设置存储结构并优化数据处理逻辑
- 将单个设置对象改为按类型分组的映射结构,支持基础设置、分销商条件、结算等功能模块 - 新增 getBooleanFlag、getNumberFlag、pickEnumValue 等工具函数统一数据转换逻辑 - 实现 ensurePath 和 setWordValue 函数用于深层对象路径操作和文案配置 - 优化图片上传相关函数 getUploadUrl 和 toUploadFileList 的 URL 获取逻辑 - 将整体保存逻辑拆分为按设置类型分别保存的 saveSettingItem 方法 - 更新分销商类型显示,将"配送员"修改为"总分销商"以符合业务需求 - 调整精度控制从4位小数改为3位小数以匹配实际业务场景
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)" />
|
||||||
|
|||||||
Reference in New Issue
Block a user