Переглянути джерело

增加SRM产品、供应商相关页面

yangzm123 1 рік тому
батько
коміт
466f3fb949

+ 2 - 2
.env.development

@@ -1,2 +1,2 @@
-VUE_APP_API_BASE_URL=http://192.168.31.126:8080/apis
-VUE_APP_BASE_URL=http://192.168.31.126:8080
+VUE_APP_API_BASE_URL=https://www.tingnin.cn:6543/apis
+VUE_APP_BASE_URL=https://www.tingnin.cn:6543

+ 1 - 1
src/App.vue

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-18 14:01:44
  * @LastEditors: PoJun
- * @LastEditTime: 2023-12-13 17:32:10
+ * @LastEditTime: 2024-01-11 15:02:34
  * @Message: Nothing
 -->
 <template>

+ 2 - 1
src/api/index.js

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-03-07 14:46:02
  * @LastEditors: PoJun
- * @LastEditTime: 2023-12-22 14:52:19
+ * @LastEditTime: 2024-01-17 15:08:52
  * @Message: Nothing
  */
 export * from "./reqs/auth";
@@ -14,3 +14,4 @@ export * from "./reqs/dict";
 export * from "./reqs/env";
 export * from "./reqs/org";
 export * from "./reqs/srm";
+export * from "./reqs/products";

+ 38 - 0
src/api/reqs/products.js

@@ -0,0 +1,38 @@
+/*
+ * @Author: PoJun
+ * @Date: 2023-08-28 11:22:46
+ * @LastEditors: PoJun
+ * @LastEditTime: 2024-01-17 17:32:19
+ * @Message: 产品目录相关
+ */
+import { $get, $post } from "../config/http.js";
+
+/** 产品目录树 */
+export const getProductsTree = reqConfig => {
+    return $get({ url: "/product_dirs/tree", reqConfig });
+};
+
+/** 获取产品目录树(无需权限) */
+export const getProductsTreeNoAuth = reqConfig => {
+    return $get({ url: "/product_dirs/tree_noauth", reqConfig });
+};
+
+/** 新建产品目录 */
+export const addProductsDir = data => {
+    return $post({ url: `/product_dirs/`, data, reqConfig: { showMsg: true } });
+};
+
+/** 编辑产品目录 */
+export const editProductsDir = (data, id) => {
+    return $post({ url: `/product_dirs/${id}/info`, data, reqConfig: { showMsg: true } });
+};
+
+/** 删除产品目录 */
+export const deleteProductsDir = id => {
+    return $post({ url: `/product_dirs/${id}/`, reqConfig: { showMsg: true } });
+};
+
+/** 根据id查找产品目录表 */
+export const getProductsInfo = (id, reqConfig) => {
+    return $get({ url: `/product_dirs/${id}/info`, reqConfig });
+};

+ 1 - 1
src/components/menu/SideMenu.vue

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-18 14:01:44
  * @LastEditors: PoJun
- * @LastEditTime: 2023-08-30 10:31:36
+ * @LastEditTime: 2024-01-16 10:16:04
  * @Message: Nothing
 -->
 <template>

+ 1 - 1
src/components/table/CommonTable.vue

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-24 10:46:56
  * @LastEditors: PoJun
- * @LastEditTime: 2024-01-08 11:14:39
+ * @LastEditTime: 2024-01-16 10:40:24
  * @Message: Nothing
 -->
 <template>

+ 2 - 2
src/config/config.js

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-18 14:01:44
  * @LastEditors: PoJun
- * @LastEditTime: 2023-10-13 10:30:52
+ * @LastEditTime: 2024-01-18 14:56:42
  * @Message: Nothing
  */
 // 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可
@@ -21,5 +21,5 @@ module.exports = {
         name: "fade",
         direction: "default",
     },
-    asyncRoutes: false, // 是否异步路由
+    asyncRoutes: true, // 是否异步路由
 };

+ 19 - 40
src/pages/affairs/transaction.vue

@@ -2,32 +2,26 @@
  * @Author: PoJun
  * @Date: 2023-10-13 10:35:43
  * @LastEditors: PoJun
- * @LastEditTime: 2024-01-03 18:17:49
+ * @LastEditTime: 2024-01-17 10:01:38
  * @Message: 事务处理中心
 -->
 <template>
     <div class="affairsTransaction">
-        <div class="affairsTransaction-menu">
-            <a-menu :defaultSelectedKeys="['todo']" mode="inline" @select="menuSelect">
-                <a-menu-item key="todo">
-                    <span>待处理</span>
-                </a-menu-item>
-                <a-menu-item key="done">
-                    <span>已处理</span>
-                </a-menu-item>
-            </a-menu>
-        </div>
-
-        <div class="affairsTransaction-table">
-            <CommonTable
-                :showCheckbox="false"
-                ref="xTable"
-                :titles="titles"
-                :optButton="optButton"
-                @optClick="optClick"
-                :url="currentUrl"
-            ></CommonTable>
-        </div>
+        <CommonTable
+            :showCheckbox="false"
+            ref="xTable"
+            :titles="titles"
+            :optButton="optButton"
+            @optClick="optClick"
+            :url="currentUrl"
+        >
+            <template slot="extraBtns">
+                <a-radio-group default-value="todo" button-style="solid" @change="menuSelect">
+                    <a-radio-button value="todo">待处理</a-radio-button>
+                    <a-radio-button value="done">已处理</a-radio-button>
+                </a-radio-group>
+            </template>
+        </CommonTable>
 
         <a-modal v-model="showModal" :zIndex="1002" title="内容详情">
             <a-spin :spinning="spinning">
@@ -103,7 +97,8 @@ export default {
             this.detailItem = data;
             this.spinning = false;
         },
-        menuSelect({ key }) {
+        menuSelect(e) {
+            const key = e.target.value;
             this.currentUrl = key == "todo" ? "/affairs/waitdo_list" : "/affairs/done_list";
             this.currentKey = key;
             setTimeout(() => {
@@ -139,22 +134,6 @@ export default {
 .affairsTransaction {
     height: 100%;
     background-color: @base-bg-color;
-    display: flex;
-    flex-direction: row;
-    position: relative;
-
-    &-menu {
-        width: 170px;
-        height: 100%;
-        box-shadow: 1px 0px 10px 0px @border-color-base;
-        display: flex;
-        flex-direction: column;
-    }
-    &-table {
-        flex: 1;
-        height: 100%;
-        padding: 18px;
-        overflow: auto;
-    }
+    padding: 18px;
 }
 </style>

+ 3 - 1
src/pages/login/login.vue

@@ -107,7 +107,9 @@ export default {
 
             getUserMenus().then(res => {
                 this.logging = false;
-                loadRoutes(res);
+                // 项目需要, 屏蔽掉流程.
+                const data = res.filter(item => item.code != "process");
+                loadRoutes(data);
                 if (this.menuData && this.menuData.length) {
                     const firstMenu = this.findFirstMenu(this.menuData);
                     this.$router.push(firstMenu.path);

+ 5 - 3
src/pages/permission/role.vue

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-25 10:30:15
  * @LastEditors: PoJun
- * @LastEditTime: 2024-01-08 11:28:54
+ * @LastEditTime: 2024-01-18 15:30:05
  * @Message: 角色管理
 -->
 <template>
@@ -129,8 +129,10 @@ export default {
         async doneInit() {
             try {
                 const { id, type } = this.$route.query;
-                const data = await getRoleByType({ type, id });
-                this.optClick({ id: data }, "edit");
+                if (id) {
+                    const data = await getRoleByType({ type, id });
+                    this.optClick({ id: data }, "edit");
+                }
             } catch (error) {
                 console.log(error);
             }

+ 179 - 0
src/pages/srm/components/ProductsDetail.vue

@@ -0,0 +1,179 @@
+<!--
+ * @Author: PoJun
+ * @Date: 2023-12-22 10:02:47
+ * @LastEditors: PoJun
+ * @LastEditTime: 2024-01-17 16:24:13
+ * @Message: 产品目录详情
+-->
+<template>
+    <CommonDrawer
+        :title="detailTitle"
+        v-model="visible"
+        :width="720"
+        @onClose="onClose"
+        @onConfirm="onConfirm"
+        :btnLoading="btnLoading"
+    >
+        <a-spin :spinning="spinning">
+            <a-form-model ref="ruleForm" :model="form" :rules="rules">
+                <a-row :gutter="18">
+                    <a-col :span="12">
+                        <a-form-model-item label="目录名称" prop="name">
+                            <a-input v-model="form.name" placeholder="请输入..." />
+                        </a-form-model-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-model-item label="目录编码" prop="code">
+                            <a-input v-model="form.code" placeholder="请输入..." />
+                        </a-form-model-item>
+                    </a-col>
+                    <a-col :span="24">
+                        <a-form-model-item label="描述" prop="remark">
+                            <a-input
+                                type="textarea"
+                                rows="4"
+                                v-model="form.remark"
+                                placeholder="请输入..."
+                                autocomplete="off"
+                            />
+                        </a-form-model-item>
+                    </a-col>
+                    <a-col :span="24">
+                        <a-form-model-item label="目录图片" prop="image">
+                            <upload-img
+                                height="200"
+                                width="200"
+                                text="移动端展示"
+                                v-model="form.image"
+                                :list="form.image"
+                                :maxLength="1"
+                                dataMode="string"
+                                @change="$refs.ruleForm.validateField('image')"
+                            ></upload-img>
+                        </a-form-model-item>
+                    </a-col>
+                </a-row>
+            </a-form-model>
+        </a-spin>
+    </CommonDrawer>
+</template>
+
+<script>
+import UploadImg from "@/components/tool/UploadImg.vue";
+import CommonDrawer from "@/components/table/CommonDrawer.vue";
+import { getProductsInfo, addProductsDir, editProductsDir } from "@/api/index.js";
+import { mergeObjects } from "@/utils/util";
+export default {
+    name: "ProductsDetail",
+    components: { CommonDrawer, UploadImg },
+    props: {
+        detailObj: {
+            type: Object,
+            default: function () {
+                return {};
+            },
+        },
+        detailTitle: {
+            type: String,
+            default: "详情",
+        },
+        detailType: {
+            type: String,
+            default: "add",
+        },
+    },
+    data() {
+        return {
+            spinning: true,
+            btnLoading: false,
+            visible: true,
+            form: {
+                name: "",
+                code: "",
+                remark: "",
+                image: "",
+                parentId: null,
+            },
+            rules: {
+                name: [{ required: true, message: "必填项不能为空", trigger: ["change", "blur"] }],
+                code: [{ required: true, message: "必填项不能为空", trigger: ["change", "blur"] }],
+            },
+            showSelectPerson: false,
+            showNames: "",
+        };
+    },
+    methods: {
+        onClose() {
+            setTimeout(() => {
+                this.$emit("close");
+            }, 200);
+        },
+        onConfirm() {
+            this.btnLoading = true;
+            this.$refs.ruleForm.validate(isValid => {
+                if (isValid) {
+                    const doAjax =
+                        this.detailType == "edit"
+                            ? editProductsDir(this.form, this.detailObj.id)
+                            : addProductsDir(this.form);
+                    doAjax
+                        .then(() => {
+                            this.$emit("confirm");
+                            this.btnLoading = false;
+                            this.visible = false;
+                            this.onClose();
+                        })
+                        .catch(() => {
+                            this.btnLoading = false;
+                        });
+                } else {
+                    this.btnLoading = false;
+                }
+            });
+        },
+        async getInfo() {
+            if (this.detailType == "add") {
+                if (!this.detailObj) {
+                    // 新增跟目录
+                    this.spinning = false;
+                } else {
+                    this.form.parentId = this.detailObj.id;
+                }
+            } else {
+                const res = await getProductsInfo(this.detailObj.id);
+                this.form = mergeObjects(this.form, res);
+            }
+
+            this.spinning = false;
+        },
+        selectConfirm(list) {
+            if (list && list.length) {
+                this.form.person = list[0].id;
+                this.form.personName = list[0].name;
+            } else {
+                this.form.person = "";
+                this.form.personName = "";
+            }
+            this.$refs.ruleForm.validateField("person");
+        },
+        convertToTree(list, parentKey = null) {
+            const tree = [];
+            for (const item of list) {
+                if (item.parentKey === parentKey) {
+                    const children = this.convertToTree(list, item.key);
+                    if (children.length > 0) {
+                        item.children = children;
+                    }
+                    tree.push(item);
+                }
+            }
+            return tree;
+        },
+    },
+    created() {
+        this.getInfo();
+    },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 12 - 23
src/pages/organization/components/SupplierDetail.vue → src/pages/srm/components/SupplierDetail.vue

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-12-22 10:02:47
  * @LastEditors: PoJun
- * @LastEditTime: 2024-01-03 17:55:22
+ * @LastEditTime: 2024-01-17 17:43:48
  * @Message: 供应商详情
 -->
 <template>
@@ -69,10 +69,10 @@
                             <a-tree-select
                                 v-model="form.product"
                                 style="width: 100%"
-                                :tree-data="getTreeData"
+                                :tree-data="treeData"
                                 tree-checkable
                                 search-placeholder="请选择..."
-                                :replaceFields="{ title: 'name', key: 'key', value: 'key' }"
+                                :replaceFields="{ title: 'name', key: 'id', value: 'id' }"
                                 :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
                             />
                         </a-form-model-item>
@@ -112,10 +112,9 @@
 <script>
 import UploadImg from "@/components/tool/UploadImg.vue";
 import CommonDrawer from "@/components/table/CommonDrawer.vue";
-import { getSupplierInfo, addSupplier, updateSupplier } from "@/api/index.js";
+import { getSupplierInfo, addSupplier, updateSupplier, getProductsTreeNoAuth } from "@/api/index.js";
 import SelectPerson from "@/components/tool/SelectPerson.vue";
 import { mergeObjects } from "@/utils/util";
-import { mapState } from "vuex";
 export default {
     name: "SupplierDetail",
     components: { CommonDrawer, SelectPerson, UploadImg },
@@ -185,6 +184,7 @@ export default {
             },
             showSelectPerson: false,
             showNames: "",
+            treeData: [],
         };
     },
     methods: {
@@ -235,30 +235,19 @@ export default {
             }
             this.$refs.ruleForm.validateField("person");
         },
-        convertToTree(list, parentKey = null) {
-            const tree = [];
-            for (const item of list) {
-                if (item.parentKey === parentKey) {
-                    const children = this.convertToTree(list, item.key);
-                    if (children.length > 0) {
-                        item.children = children;
-                    }
-                    tree.push(item);
-                }
+        async getTreeData() {
+            try {
+                const data = await getProductsTreeNoAuth();
+                this.treeData = data;
+            } catch (error) {
+                console.log(error);
             }
-            return tree;
         },
     },
     created() {
+        this.getTreeData();
         this.getInfo();
     },
-    computed: {
-        ...mapState("setting", ["dictData"]),
-        getTreeData() {
-            const list = this.convertToTree(this.dictData["productCatalog"] || []);
-            return list;
-        },
-    },
 };
 </script>
 

+ 0 - 0
src/pages/organization/components/WorkingRecords.vue → src/pages/srm/components/WorkingRecords.vue


+ 144 - 0
src/pages/srm/products.vue

@@ -0,0 +1,144 @@
+<!--
+ * @Author: PoJun
+ * @Date: 2023-12-22 10:01:43
+ * @LastEditors: PoJun
+ * @LastEditTime: 2024-01-17 17:04:02
+ * @Message: 产品目录
+-->
+<template>
+    <div class="products">
+        <div style="margin-bottom: 10px">
+            <a-space :size="12">
+                <a-button type="primary" @click="addRow(null)">新增根目录</a-button>
+                <a-button @click="$refs.xTable.setAllTreeExpand(true)">展开所有</a-button>
+                <a-button @click="$refs.xTable.clearTreeExpand()">关闭所有</a-button>
+            </a-space>
+        </div>
+        <div class="products-table">
+            <vxe-table
+                ref="xTable"
+                show-overflow
+                border="inner"
+                :data="dataList"
+                height="auto"
+                :tree-config="{
+                    iconOpen: 'vxe-icon-square-minus-fill',
+                    iconClose: 'vxe-icon-square-plus-fill',
+                }"
+                :row-config="{ isHover: true }"
+            >
+                <vxe-column field="name" title="目录名称" tree-node></vxe-column>
+                <vxe-column field="code" title="目录编码"></vxe-column>
+                <vxe-column title="操作" width="140">
+                    <template #default="{ row }">
+                        <a-space :size="20" align="end" style="flex: 1">
+                            <a-tooltip>
+                                <template slot="title">编辑</template>
+                                <a-icon type="form" @click="editRow(row)" :style="{ fontSize: '16px' }" />
+                            </a-tooltip>
+                            <a-tooltip>
+                                <template slot="title">删除</template>
+                                <a-icon type="delete" @click="deleteRow(row)" :style="{ fontSize: '16px' }" />
+                            </a-tooltip>
+                            <!-- 暂时来说只让两层 -->
+                            <a-tooltip v-if="row.path.length == 2">
+                                <template slot="title">新增子目录</template>
+                                <a-icon type="plus" @click="addRow(row)" :style="{ fontSize: '16px' }" />
+                            </a-tooltip>
+                        </a-space>
+                    </template>
+                </vxe-column>
+                <template #empty>
+                    <a-empty
+                        :image-style="{
+                            height: '60px',
+                        }"
+                    ></a-empty>
+                </template>
+            </vxe-table>
+        </div>
+
+        <ProductsDetail
+            :detailObj="detailObj"
+            :detailType="detailType"
+            v-if="showDetail"
+            :detailTitle="detailTitle"
+            @close="closeDetail"
+            @confirm="confirmDetail"
+        />
+    </div>
+</template>
+
+<script>
+import { getProductsTree, deleteProductsDir } from "@/api/index.js";
+import ProductsDetail from "./components/ProductsDetail";
+export default {
+    components: { ProductsDetail },
+    name: "Products",
+    data() {
+        return {
+            dataList: [],
+            rules: {
+                name: [{ required: true, message: "必填项不能为空", trigger: ["change", "blur"] }],
+                code: [{ required: true, message: "必填项不能为空", trigger: ["change", "blur"] }],
+            },
+            detailObj: null, // 详情对象
+            showDetail: false, // 详情
+            detailTitle: "", // 详情标题
+            detailType: "add",
+        };
+    },
+    methods: {
+        async initData() {
+            const data = await getProductsTree();
+            this.dataList = data;
+        },
+        addRow(row) {
+            this.detailObj = row;
+            this.detailType = "add";
+            this.detailTitle = "新增目录";
+            this.showDetail = true;
+        },
+        deleteRow(row) {
+            this.$confirm({
+                title: "数据删除无法复原,确认删除?",
+                onOk: () => {
+                    deleteProductsDir(row.id).then(() => {
+                        this.initData();
+                    });
+                },
+            });
+        },
+        editRow(row) {
+            this.detailType = "edit";
+            this.detailTitle = "编辑目录";
+            this.detailObj = row;
+            this.showDetail = true;
+        },
+        // 关闭详情窗口
+        closeDetail() {
+            this.showDetail = false;
+            this.detailObj = null;
+        },
+        confirmDetail() {
+            this.initData();
+        },
+    },
+    created() {
+        this.initData();
+    },
+};
+</script>
+
+<style scoped lang="less">
+.products {
+    height: 100%;
+    background-color: @base-bg-color;
+    padding: 18px;
+    display: flex;
+    flex-direction: column;
+    &-table {
+        flex: 1;
+    }
+}
+</style>

+ 6 - 8
src/pages/organization/supplier.vue → src/pages/srm/supplier.vue

@@ -2,11 +2,11 @@
  * @Author: PoJun
  * @Date: 2023-12-22 10:01:43
  * @LastEditors: PoJun
- * @LastEditTime: 2023-12-22 17:04:10
+ * @LastEditTime: 2024-01-17 17:33:23
  * @Message: 供应商列表
 -->
 <template>
-    <div class="pre-setting">
+    <div class="supplier">
         <CommonTable
             :showCheckbox="true"
             :showSeq="false"
@@ -48,10 +48,10 @@ import CommonTable from "@/components/table/CommonTable.vue";
 import SupplierDetail from "./components/SupplierDetail";
 import WorkingRecords from "./components/WorkingRecords";
 import { deleteSupplier, batchDeleteSuppliers } from "@/api/index.js";
-import { initDictList } from "@/components/enums/enum.js";
+
 export default {
     components: { CommonTable, SupplierDetail, WorkingRecords },
-    name: "sysManagerRole",
+    name: "Supplier",
     data() {
         return {
             optButton: [
@@ -183,14 +183,12 @@ export default {
             this.$refs.xTable.refresh();
         },
     },
-    async created() {
-        await initDictList("productCatalog");
-    },
+    created() {},
 };
 </script>
 
 <style scoped lang="less">
-.pre-setting {
+.supplier {
     height: 100%;
     background-color: @base-bg-color;
     padding: 18px;

+ 19 - 3
src/router/async/router.map.js

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-18 14:01:44
  * @LastEditors: PoJun
- * @LastEditTime: 2023-12-26 14:23:04
+ * @LastEditTime: 2024-01-18 15:00:59
  * @Message: 组件注册, 但是由于大部分是动态的, 所以只注册静态组件
  */
 // 视图组件
@@ -105,9 +105,25 @@ const routerMap = {
         name: "岗位管理",
         component: () => import("@/pages/organization/post"),
     },
-    organization_supplier: {
+    srm: {
+        name: "SRM管理",
+        component: view.blank,
+    },
+    srm_products: {
+        name: "产品目录",
+        component: () => import("@/pages/srm/products"),
+    },
+    srm_supplier: {
         name: "供应商管理",
-        component: () => import("@/pages/organization/supplier"),
+        component: () => import("@/pages/srm/supplier"),
+    },
+    affairs: {
+        name: "事务中心",
+        component: view.blank,
+    },
+    affairs_transaction: {
+        name: "事务处理",
+        component: () => import("@/pages/affairs/transaction"),
     },
     process: {
         name: "流程中心",

+ 21 - 6
src/router/config.js

@@ -2,7 +2,7 @@
  * @Author: PoJun
  * @Date: 2023-08-18 14:01:44
  * @LastEditors: PoJun
- * @LastEditTime: 2024-01-02 11:17:14
+ * @LastEditTime: 2024-01-17 14:54:57
  * @Message: 静态路由, 一般开发用, 存在权限的时候用不上
  */
 import TabsView from "@/layouts/tabs/TabsView";
@@ -83,6 +83,26 @@ const options = {
                         },
                     ],
                 },
+                {
+                    path: "srm",
+                    name: "SRM管理",
+                    meta: {
+                        icon: "profile",
+                    },
+                    component: BlankView,
+                    children: [
+                        {
+                            path: "products",
+                            name: "产品目录",
+                            component: () => import("@/pages/srm/products"),
+                        },
+                        {
+                            path: "supplier",
+                            name: "供应商管理",
+                            component: () => import("@/pages/srm/supplier"),
+                        },
+                    ],
+                },
                 {
                     path: "organization",
                     name: "组织管理",
@@ -111,11 +131,6 @@ const options = {
                             name: "岗位管理",
                             component: () => import("@/pages/organization/post"),
                         },
-                        {
-                            path: "supplier",
-                            name: "供应商管理",
-                            component: () => import("@/pages/organization/supplier"),
-                        },
                     ],
                 },
                 {