diff --git a/manager/src/api/index.js b/manager/src/api/index.js
index 9e4d2492..09210bfa 100644
--- a/manager/src/api/index.js
+++ b/manager/src/api/index.js
@@ -3,10 +3,10 @@ import {
getRequest,
postRequest,
putRequest,
+ putRequestWithNoForm,
deleteRequest,
importRequest,
getRequestWithNoToken,
- putRequestWithNoForm,
postRequestWithNoTokenData,
postRequestWithNoForm,
managerUrl
@@ -388,6 +388,21 @@ export const applyWxChannelsCategory = (params) => {
return postRequestWithNoForm(`/wxchannels/category/apply`, params);
};
+// 删除微信小店类目申请
+export const deleteWxChannelsCategoryApply = (id) => {
+ return deleteRequest(`/wxchannels/category/${id}`);
+};
+
+// 编辑微信小店类目映射
+export const updateWxChannelsCategoryMapping = (id, params) => {
+ return putRequestWithNoForm(`/wxchannels/category/${id}`, params);
+};
+
+// 查询已关联平台类目
+export const getWxChannelsCategoryMapped = (params) => {
+ return getRequest(`/wxchannels/category/mapped`, params);
+};
+
// 微信小店类目审核单详情
export const getWxChannelsCategoryFlowDetail = (params) => {
return getRequest(`/wxchannels/category/flow/detail`, params);
@@ -403,6 +418,11 @@ export const getWxChannelsGoodsPage = (params) => {
return getRequest(`/wxchannels/goods`, params);
};
+// 微信视频号可关联平台商品分页
+export const getWxChannelsLinkableGoodsPage = (params) => {
+ return getRequest(`/wxchannels/goods/linkable`, params);
+};
+
// 微信视频号订单分页
export const getWxChannelsOrderPage = (params) => {
return getRequest(`/wxchannels/order`, params);
diff --git a/manager/src/views/promotions/wxchannels/category-apply.vue b/manager/src/views/promotions/wxchannels/category-apply.vue
index 893ec02f..ca448378 100644
--- a/manager/src/views/promotions/wxchannels/category-apply.vue
+++ b/manager/src/views/promotions/wxchannels/category-apply.vue
@@ -42,7 +42,7 @@
-
+
+
+ 当前类目无需提交资质信息
+
@@ -64,6 +67,13 @@ import { getWxChannelsCategoryDetail, applyWxChannelsCategory } from "@/api/inde
export default {
name: "wxchannels-category-apply",
+ computed: {
+ needQualification() {
+ const list = this.detailData && this.detailData.productQuaList;
+ if (!Array.isArray(list) || list.length === 0) return false;
+ return list.some((item) => item && (item.mandatory === true || item.needToApply === true));
+ },
+ },
data() {
return {
loading: false,
@@ -125,15 +135,17 @@ export default {
},
async submitApply() {
let licenseGroupList = [];
- try {
- licenseGroupList = JSON.parse(this.applyForm.licenseGroupJson || "[]");
- } catch (e) {
- this.$Message.error("证照组JSON格式错误");
- return;
- }
- if (!Array.isArray(licenseGroupList) || licenseGroupList.length === 0) {
- this.$Message.warning("licenseGroupList不能为空");
- return;
+ if (this.needQualification) {
+ try {
+ licenseGroupList = JSON.parse(this.applyForm.licenseGroupJson || "[]");
+ } catch (e) {
+ this.$Message.error("证照组JSON格式错误");
+ return;
+ }
+ if (!Array.isArray(licenseGroupList) || licenseGroupList.length === 0) {
+ this.$Message.warning("licenseGroupList不能为空");
+ return;
+ }
}
const brandIds = (this.applyForm.brandIdsText || "")
.split(",")
@@ -159,8 +171,10 @@ export default {
const payload = {
// 按一级->二级->三级顺序传递完整分类链
catsV2,
- licenseGroupList,
};
+ if (this.needQualification) {
+ payload.licenseGroupList = licenseGroupList;
+ }
if (brandIds.length > 0) {
payload.brandIds = brandIds;
}
diff --git a/manager/src/views/promotions/wxchannels/category.vue b/manager/src/views/promotions/wxchannels/category.vue
index ab894005..ff4626f8 100644
--- a/manager/src/views/promotions/wxchannels/category.vue
+++ b/manager/src/views/promotions/wxchannels/category.vue
@@ -1,25 +1,6 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -97,6 +97,29 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -107,19 +130,48 @@ import {
getWxChannelsCategoryFlowDetail,
getWxChannelsCategoryDetail,
initWxChannelsCategory,
+ deleteWxChannelsCategoryApply,
+ updateWxChannelsCategoryMapping,
+ getWxChannelsCategoryMapped,
} from "@/api/index";
+import { getCategoryTree } from "@/api/goods";
+
+const toStringArray = (arr) => {
+ if (!Array.isArray(arr)) return [];
+ return arr.map((x) => String(x)).filter((x) => x.length > 0);
+};
+
+const buildCategoryIdNameMap = (list, map) => {
+ if (!Array.isArray(list) || list.length === 0) return;
+ list.forEach((item) => {
+ if (!item) return;
+ const id = item.id !== undefined && item.id !== null ? String(item.id) : "";
+ if (id) map[id] = item.name;
+ buildCategoryIdNameMap(item.children || [], map);
+ });
+};
export default {
name: "wxchannels-category",
data() {
return {
- innerTab: "third",
+ innerTab: "apply",
thirdLoading: false,
initLoading: false,
applyLoading: false,
thirdData: [],
applyData: [],
applyTotal: 0,
+ bindModalVisible: false,
+ bindModalTitle: "关联分类",
+ bindSubmitting: false,
+ bindTargetRow: null,
+ selectedCategoryIds: [],
+ categoryTreeLoading: false,
+ categoryTreeData: [],
+ categoryTreeSource: [],
+ categoryIdNameMap: {},
+ categoryTreeKey: 0,
// 保存用户当前选择的完整类目链(一级 -> 二级 -> 三级)
fullCategoryPath: [],
detailModalVisible: false,
@@ -127,7 +179,7 @@ export default {
detailData: null,
detailRawJson: "",
applyQuery: {
- status: "",
+ status: "APPROVED",
pageNumber: 1,
pageSize: 20,
},
@@ -169,7 +221,8 @@ export default {
align: "center",
render: (h, params) => {
const row = params.row || {};
- if (Number(row.level) !== 3) {
+ // 仅最底层(无下级)展示申请按钮
+ if (row.hasChildren === true) {
return h("span", "-");
}
return h(
@@ -184,9 +237,33 @@ export default {
},
],
applyColumns: [
- { title: "审核单ID", key: "auditId", minWidth: 120, tooltip: true },
- { title: "类目ID", key: "catId", minWidth: 120, tooltip: true },
- { title: "类目名称", key: "catName", minWidth: 180, tooltip: true },
+ {
+ title: "类目ID",
+ key: "wxCategoryId",
+ minWidth: 120,
+ tooltip: true,
+ render: (h, params) => {
+ const row = params.row || {};
+ return h("span", row.wxCategoryId || row.catId || "-");
+ },
+ },
+ {
+ title: "类目名称",
+ key: "wxCategoryName",
+ minWidth: 180,
+ tooltip: true,
+ render: (h, params) => {
+ const row = params.row || {};
+ return h("span", row.wxCategoryName || row.catName || "-");
+ },
+ },
+ {
+ title: "已关联平台分类",
+ key: "mappedPlatformCategoryNames",
+ minWidth: 220,
+ tooltip: true,
+ render: (h, params) => h("span", this.formatMappedPlatformCategoryNames(params.row)),
+ },
{
title: "状态",
key: "status",
@@ -206,31 +283,31 @@ export default {
{
title: "操作",
key: "action",
- width: 180,
+ width: 120,
render: (h, params) => {
const row = params.row || {};
- const actions = [];
- actions.push(
- h(
+ if (row.status === "APPROVED") {
+ return h(
"Button",
{
props: { type: "text", size: "small" },
- on: { click: () => this.showCategoryDetail(row.catId) },
+ on: { click: () => this.openBindCategoryModal(row) },
},
- "类目详情"
- )
- );
- actions.push(
- h(
+ "关联分类"
+ );
+ }
+ if (row.status === "PENDING") {
+ return h(
"Button",
{
props: { type: "text", size: "small" },
- on: { click: () => this.showFlowDetail(row.auditId) },
+ style: { color: "#ed4014" },
+ on: { click: () => this.handleDeleteApply(row) },
},
- "审核单详情"
- )
- );
- return h("div", actions);
+ "删除"
+ );
+ }
+ return h("span", "-");
},
},
],
@@ -257,11 +334,17 @@ export default {
innerTab(val) {
if (val === "apply" && this.applyData.length === 0) {
this.loadApplyPage();
+ } else if (val === "third" && this.thirdData.length === 0) {
+ this.loadThirdCategories();
}
},
},
mounted() {
- this.loadThirdCategories();
+ if (this.innerTab === "apply") {
+ this.loadApplyPage();
+ } else {
+ this.loadThirdCategories();
+ }
},
methods: {
boolText(val) {
@@ -436,6 +519,156 @@ export default {
this.detailModalVisible = true;
}
},
+ buildCategoryTreeNodes(list, selectedSet) {
+ if (!Array.isArray(list) || list.length === 0) return [];
+ return list.map((item) => {
+ const children = this.buildCategoryTreeNodes(item.children || [], selectedSet);
+ return {
+ id: item.id,
+ title: item.name,
+ expand: true,
+ checked: selectedSet.has(String(item.id)),
+ children,
+ };
+ });
+ },
+ parsePlatformCategoryIds(row) {
+ if (!row) return [];
+ const raw =
+ row.platformCategoryIds ??
+ row.platform_category_ids ??
+ row.platformCategoryId ??
+ row.platform_category_id;
+ if (Array.isArray(raw)) return toStringArray(raw);
+ if (typeof raw === "string") {
+ const text = raw.trim();
+ if (!text) return [];
+ try {
+ const parsed = JSON.parse(text);
+ if (Array.isArray(parsed)) return toStringArray(parsed);
+ } catch (e) {
+ // ignore
+ }
+ return text
+ .split(",")
+ .map((x) => x.trim())
+ .filter((x) => x.length > 0);
+ }
+ if (raw !== undefined && raw !== null && String(raw)) return [String(raw)];
+ return [];
+ },
+ formatMappedPlatformCategoryNames(row) {
+ if (!row) return "-";
+ const raw = row.mappedPlatformCategoryNames ?? row.platformCategoryNames ?? row.platform_category_names;
+ if (Array.isArray(raw)) {
+ const names = raw.map((x) => String(x || "").trim()).filter((x) => x.length > 0);
+ return names.length > 0 ? names.join(",") : "-";
+ }
+ if (typeof raw === "string") {
+ const text = raw.trim();
+ if (!text) return "-";
+ try {
+ const parsed = JSON.parse(text);
+ if (Array.isArray(parsed)) {
+ const names = parsed.map((x) => String(x || "").trim()).filter((x) => x.length > 0);
+ return names.length > 0 ? names.join(",") : "-";
+ }
+ } catch (e) {
+ // ignore
+ }
+ return text;
+ }
+ return "-";
+ },
+ async fetchMappedCategoryIds(id, row) {
+ if (!id) return this.parsePlatformCategoryIds(row);
+ try {
+ const res = await getWxChannelsCategoryMapped({ id });
+ if (res && res.success) {
+ const list = Array.isArray(res.result) ? res.result : [];
+ return toStringArray(
+ list
+ .map((item) => item && (item.platformCategoryId || item.platform_category_id))
+ .filter((x) => x !== undefined && x !== null && String(x)),
+ );
+ }
+ } catch (e) {
+ // ignore and fallback
+ }
+ return this.parsePlatformCategoryIds(row);
+ },
+ async openBindCategoryModal(row) {
+ this.bindTargetRow = row || null;
+ this.bindModalVisible = true;
+ this.categoryTreeLoading = true;
+ this.categoryTreeKey += 1;
+ try {
+ const id = row && row.id;
+ this.selectedCategoryIds = await this.fetchMappedCategoryIds(id, row);
+ if (!Array.isArray(this.categoryTreeSource) || this.categoryTreeSource.length === 0) {
+ const res = await getCategoryTree();
+ this.categoryTreeSource = res && res.success ? res.result || [] : [];
+ const map = {};
+ buildCategoryIdNameMap(this.categoryTreeSource, map);
+ this.categoryIdNameMap = map;
+ }
+ const selectedSet = new Set(toStringArray(this.selectedCategoryIds));
+ this.categoryTreeData = this.buildCategoryTreeNodes(this.categoryTreeSource || [], selectedSet);
+ } finally {
+ this.categoryTreeLoading = false;
+ }
+ },
+ onBindCategoryCheckChange(checkedNodes) {
+ if (!Array.isArray(checkedNodes)) {
+ this.selectedCategoryIds = [];
+ return;
+ }
+ this.selectedCategoryIds = toStringArray(checkedNodes.map((node) => node && node.id).filter(Boolean));
+ },
+ async submitBindCategory() {
+ const row = this.bindTargetRow || {};
+ const id = row.id;
+ if (!id) {
+ this.$Message.warning("缺少申请ID");
+ return;
+ }
+ const platformCategoryIds = toStringArray(this.selectedCategoryIds);
+ const platformCategoryNames = platformCategoryIds
+ .map((x) => this.categoryIdNameMap[x] || "")
+ .filter((x) => x.length > 0);
+ this.bindSubmitting = true;
+ try {
+ const res = await updateWxChannelsCategoryMapping(id, {
+ platformCategoryIds,
+ platformCategoryNames,
+ });
+ if (res && res.success) {
+ this.$Message.success("关联分类成功");
+ this.bindModalVisible = false;
+ this.loadApplyPage();
+ }
+ } finally {
+ this.bindSubmitting = false;
+ }
+ },
+ handleDeleteApply(row) {
+ const id = row && row.id;
+ if (!id) {
+ this.$Message.warning("缺少申请ID");
+ return;
+ }
+ this.$Modal.confirm({
+ title: "确认删除",
+ content: "确认删除该类目申请吗?",
+ onOk: async () => {
+ const res = await deleteWxChannelsCategoryApply(id);
+ if (res && res.success) {
+ this.$Message.success("删除成功");
+ this.loadApplyPage();
+ }
+ },
+ });
+ },
},
};
diff --git a/manager/src/views/promotions/wxchannels/goods.vue b/manager/src/views/promotions/wxchannels/goods.vue
index 2e8384fa..b6bb8303 100644
--- a/manager/src/views/promotions/wxchannels/goods.vue
+++ b/manager/src/views/promotions/wxchannels/goods.vue
@@ -1,61 +1,114 @@
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+