|
@@ -0,0 +1,404 @@
|
|
|
+<script lang="ts" setup>
|
|
|
+/**
|
|
|
+ * @Name: SkuBuilder.vue
|
|
|
+ * @Description: 产品属性-行编辑
|
|
|
+ * @Author: Cheney
|
|
|
+ */
|
|
|
+
|
|
|
+import * as api from '/@/views/sku-manage/company-sku/api';
|
|
|
+import { useResponse } from '/@/utils/useResponse';
|
|
|
+import XEUtils from 'xe-utils';
|
|
|
+import { ElForm, ElMessage, FormInstance } from 'element-plus';
|
|
|
+
|
|
|
+const btnLoading = ref(false);
|
|
|
+const showSkuBuilder = defineModel({ default: false });
|
|
|
+const editDrawer = <Ref>useTemplateRef('editDrawer');
|
|
|
+
|
|
|
+interface RuleForm {
|
|
|
+ powerType: any;
|
|
|
+ versionType: any;
|
|
|
+ version: number;
|
|
|
+ versionFeature: string;
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ rowData: Object,
|
|
|
+ skuData: Object,
|
|
|
+});
|
|
|
+const { rowData, skuData } = props;
|
|
|
+const emit = defineEmits(['refresh']);
|
|
|
+
|
|
|
+const selectedBrand = ref(rowData?.brand.id || '');
|
|
|
+const selectedKind = ref(rowData?.kind.id || '');
|
|
|
+const brandOptions = ref([]);
|
|
|
+const kindOptions = ref([]);
|
|
|
+
|
|
|
+const relatedAttrs = ref([]);
|
|
|
+const kindInfo = ref({});
|
|
|
+const formData = reactive<RuleForm>({
|
|
|
+ powerType: '',
|
|
|
+ versionType: '',
|
|
|
+ version: 1,
|
|
|
+ versionFeature: '',
|
|
|
+});
|
|
|
+const powerTypeList = ref([]);
|
|
|
+const skuList = ref([]);
|
|
|
+const isUpdate = computed(() => rowData !== undefined);
|
|
|
+const PublishedStatus = 3;
|
|
|
+const versionTypeList = [
|
|
|
+ { label: '无', value: '' },
|
|
|
+ { label: 'T', value: 'T' },
|
|
|
+ { label: 'V', value: 'V' },
|
|
|
+];
|
|
|
+
|
|
|
+const ruleFormRef = ref<FormInstance>();
|
|
|
+
|
|
|
+const sku = computed(() => {
|
|
|
+ const ret = [];
|
|
|
+ for (const part of skuList.value) {
|
|
|
+ let t = '';
|
|
|
+ for (const k of part) {
|
|
|
+ t += formData[k] || '*';
|
|
|
+ }
|
|
|
+ ret.push(t);
|
|
|
+ }
|
|
|
+ for (const k of ['powerType']) {
|
|
|
+ const val = formData[k];
|
|
|
+ if (val) {
|
|
|
+ ret.push(val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (formData.versionType) {
|
|
|
+ ret.push(formData.versionType + formData.version);
|
|
|
+ }
|
|
|
+ return ret.join('-');
|
|
|
+});
|
|
|
+const disabledSaveButton = computed(() => {
|
|
|
+ if (rowData && rowData.status === PublishedStatus) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return !selectedKind.value || kindInfo.value.status !== PublishedStatus;
|
|
|
+});
|
|
|
+
|
|
|
+const skuWithDetails = computed(() => {
|
|
|
+ const skuDetails = {};
|
|
|
+ for (const sectionData of relatedAttrs.value) {
|
|
|
+ const sectionName = sectionData.section;
|
|
|
+ skuDetails[sectionName] = []; // 初始化每个 section 的数组
|
|
|
+
|
|
|
+ for (const item of sectionData.items) {
|
|
|
+ const k = item.attr.key + '_' + item.id;
|
|
|
+ const value = formData[k] || '*';
|
|
|
+
|
|
|
+ const attrDict = item.attr_dict.find((dict) => dict.value === value);
|
|
|
+
|
|
|
+ if (attrDict) {
|
|
|
+ skuDetails[sectionName].push(attrDict.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return skuDetails;
|
|
|
+});
|
|
|
+
|
|
|
+async function initData() {
|
|
|
+ if (!selectedKind.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const tmpRelatedAttrs = [];
|
|
|
+ const tmpFormData = {
|
|
|
+ powerType: '',
|
|
|
+ versionType: '',
|
|
|
+ version: 1,
|
|
|
+ versionFeature: '',
|
|
|
+ };
|
|
|
+ const tmpSkuList = [];
|
|
|
+
|
|
|
+ const ret = await useResponse(api.getSkuDetailByKind, selectedKind.value);
|
|
|
+ kindInfo.value = ret.data;
|
|
|
+
|
|
|
+ if (kindInfo.value.status !== PublishedStatus) {
|
|
|
+ ElMessage.warning('警告:尚未发布的产品种类!!!');
|
|
|
+ }
|
|
|
+
|
|
|
+ const info = XEUtils.groupBy(ret.data.RelatedAttrs, 'section');
|
|
|
+ const sortedKey = XEUtils.sortBy(Object.keys(info), (key) => key);
|
|
|
+
|
|
|
+ for (const section of sortedKey) {
|
|
|
+ const attrItems = XEUtils.sortBy(info[section], 'order');
|
|
|
+
|
|
|
+ tmpRelatedAttrs.push({
|
|
|
+ section: section,
|
|
|
+ items: attrItems,
|
|
|
+ });
|
|
|
+ const skuPart = [];
|
|
|
+ let selectedIds = []; // 初始化为一个空数组
|
|
|
+ if (skuData) {
|
|
|
+ selectedIds = skuData[`section${section}`] || []; // 获取对应 section 的选中 ID
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const item of attrItems) {
|
|
|
+ const k = item.attr.key + '_' + item.id;
|
|
|
+ let v = '';
|
|
|
+
|
|
|
+ // 检查选中的 ID 是否在当前属性的字典中
|
|
|
+ if (item.attr_dict.some((dict) => selectedIds.includes(dict.id))) {
|
|
|
+ // 找到对应的 dict 并设置值
|
|
|
+ v = item.attr_dict.find((dict) => selectedIds.includes(dict.id))?.value || '';
|
|
|
+ }
|
|
|
+
|
|
|
+ formData[k] = v; // 将值赋给 formData
|
|
|
+ skuPart.push(k); // 将 SKU 部分加入 SKU 列表
|
|
|
+ }
|
|
|
+
|
|
|
+ tmpSkuList.push(skuPart); // 将 SKU 部分加入 SKU 列表
|
|
|
+ }
|
|
|
+ // 用 skuData 的 optional 部分来设置可选项
|
|
|
+ if (skuData && isUpdate.value) {
|
|
|
+ selectedBrand.value = rowData.brand.id;
|
|
|
+ tmpFormData.powerType = skuData.optional.powerType || '';
|
|
|
+ tmpFormData.versionType = skuData.optional.versionType || '';
|
|
|
+ tmpFormData.version = skuData.optional.version || 1;
|
|
|
+ tmpFormData.versionFeature = rowData.version_feature || '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最后更新组件的状态
|
|
|
+ Object.assign(formData, tmpFormData);
|
|
|
+ relatedAttrs.value = tmpRelatedAttrs;
|
|
|
+ skuList.value = tmpSkuList;
|
|
|
+}
|
|
|
+
|
|
|
+async function initPower() {
|
|
|
+ const resp = await useResponse(api.getSkuDetailByPower, { key: 'power' });
|
|
|
+ if (!resp || resp.data.total === 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'warning',
|
|
|
+ message: '警告:未找到产品属性:power(电源规格)!请在产品属性中定义标识为power的电源规格属性!',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const items = resp.data[0].attr_dict;
|
|
|
+ items.unshift({
|
|
|
+ label: '无',
|
|
|
+ value: '',
|
|
|
+ });
|
|
|
+ powerTypeList.value = items;
|
|
|
+}
|
|
|
+
|
|
|
+async function saveSku(formName, isSaveAs) {
|
|
|
+ const formattedSkuDetails = {
|
|
|
+ section1: skuWithDetails.value[1] || [],
|
|
|
+ section2: skuWithDetails.value[2] || [],
|
|
|
+ section3: skuWithDetails.value[3] || [],
|
|
|
+ };
|
|
|
+ const optionalData = {
|
|
|
+ powerType: formData.powerType,
|
|
|
+ versionType: formData.versionType || null,
|
|
|
+ version: formData.versionType === '' ? null : formData.version || null,
|
|
|
+ };
|
|
|
+
|
|
|
+ if (isUpdate.value && !isSaveAs) {
|
|
|
+ try {
|
|
|
+ const body = {
|
|
|
+ sku: sku.value,
|
|
|
+ kind: selectedKind.value,
|
|
|
+ brand: selectedBrand.value,
|
|
|
+ version_feature: formData.versionFeature,
|
|
|
+ sku_selection: {
|
|
|
+ ...formattedSkuDetails,
|
|
|
+ optional: optionalData,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ const ret = await api.PartialUpdateObj(rowData.id, body);
|
|
|
+
|
|
|
+ ElMessage({
|
|
|
+ message: ret.msg,
|
|
|
+ type: 'success',
|
|
|
+ });
|
|
|
+ showSkuBuilder.value = false;
|
|
|
+ emit('refresh');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('更新操作失败:', error);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ruleFormRef.value.validate(async (valid: boolean) => {
|
|
|
+ if (valid) {
|
|
|
+ if (kindInfo.value.status !== 3) {
|
|
|
+ ElMessage({
|
|
|
+ message: '此产品种类尚未发布!',
|
|
|
+ type: 'warning',
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ const ret = await api.createObj({
|
|
|
+ sku: sku.value,
|
|
|
+ kind: selectedKind.value,
|
|
|
+ brand: selectedBrand.value,
|
|
|
+ version_feature: formData.versionFeature,
|
|
|
+ sku_selection: {
|
|
|
+ ...formattedSkuDetails,
|
|
|
+ optional: optionalData,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ if (ret.code === 2000) {
|
|
|
+ ElMessage({
|
|
|
+ message: ret.msg,
|
|
|
+ type: 'success',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ showSkuBuilder.value = false;
|
|
|
+ emit('refresh');
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error({
|
|
|
+ message: error.msg,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+async function changedKind() {
|
|
|
+ await nextTick(); // 等待 DOM 更新
|
|
|
+ if (ruleFormRef.value) {
|
|
|
+ ruleFormRef.value.resetFields(); // 确保 ref 不为 null
|
|
|
+ await initData();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function changeVersion() {
|
|
|
+ if (formData.version === 1) {
|
|
|
+ ruleFormRef.value!.clearValidate('versionFeature');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function fetchOptions() {
|
|
|
+ brandOptions.value = (await useResponse(api.getBrandOptions)).data;
|
|
|
+ kindOptions.value = (await useResponse(api.getKindOptions)).data;
|
|
|
+}
|
|
|
+
|
|
|
+onBeforeMount(() => {
|
|
|
+ initData();
|
|
|
+});
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchOptions();
|
|
|
+ // initData();
|
|
|
+ initPower();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="drawer-container">
|
|
|
+ <el-drawer ref="editDrawer" v-model="showSkuBuilder" :close-on-click-modal="false" :close-on-press-escape="false" :title="`SKU生成器`" size="50%">
|
|
|
+ <div class="m-5">
|
|
|
+ <!--选择器-->
|
|
|
+ <div style="margin-bottom: 20px">
|
|
|
+ <span class="select-container">产品品牌:</span>
|
|
|
+ <el-select v-model="selectedBrand" placeholder="请选择品牌" style="width: 25%">
|
|
|
+ <el-option v-for="item in brandOptions" :key="item.id" :label="item.brand_name" :value="item.id" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div style="margin-bottom: 20px" v-if="selectedBrand">
|
|
|
+ <span class="select-container">种类名称:</span>
|
|
|
+ <el-select v-model="selectedKind" :disabled="isUpdate" placeholder="请选择产品种类" style="width: 25%" @change="changedKind">
|
|
|
+ <el-option v-for="item in kindOptions" :key="item.id" :label="item.name" :value="item.id" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <!--SKU-->
|
|
|
+ <div v-if="selectedKind" class="sku-text">
|
|
|
+ <span>SKU:{{ sku }}</span>
|
|
|
+ </div>
|
|
|
+ <!--属性-->
|
|
|
+ <div v-if="selectedKind">
|
|
|
+ <el-form ref="ruleFormRef" :model="formData" label-position="right" label-suffix=":">
|
|
|
+ <template v-for="info in relatedAttrs" :key="info.section">
|
|
|
+ <div class="sku-title">第{{ info.section }}部分</div>
|
|
|
+ <el-form-item
|
|
|
+ v-for="item in info.items"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.attr.name"
|
|
|
+ :prop="item.attr.key + '_' + item.id"
|
|
|
+ :rules="[{ required: true, message: '必填项' }]"
|
|
|
+ >
|
|
|
+ <el-radio-group v-model="formData[item.attr.key + '_' + item.id]">
|
|
|
+ <el-radio v-for="dict in item.attr_dict" :key="dict.id" :label="dict.value">
|
|
|
+ {{ dict.label }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <div class="sku-title">可选部分</div>
|
|
|
+ <el-form-item label="电源" prop="powerType">
|
|
|
+ <el-radio-group v-model="formData.powerType">
|
|
|
+ <el-radio v-for="dict in powerTypeList" :key="dict.value" :label="dict.value">
|
|
|
+ {{ dict.label }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="版本类型" prop="versionType">
|
|
|
+ <el-radio-group v-model="formData.versionType">
|
|
|
+ <el-radio v-for="dict in versionTypeList" :key="dict.value" :label="dict.value">
|
|
|
+ {{ dict.label }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-show="formData.versionType" label="版本编号" prop="version">
|
|
|
+ <el-input-number v-model="formData.version" :max="9" :min="1" @change="changeVersion" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-bind="{
|
|
|
+ rules: [{ required: formData.version > 1, message: '必填项', trigger: 'blur' }],
|
|
|
+ label: '版本特征',
|
|
|
+ prop: 'versionFeature',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input v-model="formData.versionFeature" autosize clearable style="width: 25%" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div class="button-container">
|
|
|
+ <el-button :disabled="disabledSaveButton" type="primary" @click="saveSku('skuForm', false)">保存</el-button>
|
|
|
+ <el-button :disabled="kindInfo.status !== 3" type="primary" @click="saveSku('skuForm', true)">另存</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-drawer>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.drawer-container :deep(.el-drawer__header) {
|
|
|
+ border-bottom: none;
|
|
|
+ /* font-weight: 500; */
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-container :deep(.el-drawer__title) {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.sku-text {
|
|
|
+ margin: 20px 0;
|
|
|
+ color: #515151;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.sku-title {
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-form-item__label) {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.select-container {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+</style>
|