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

feat(公告): 新增公告分类管理功能

yz 2 місяців тому
батько
коміт
d803340095

+ 153 - 0
src/api/announcement/category.js

@@ -0,0 +1,153 @@
+/**
+ * 公告分类管理API
+ * @description 提供公告分类的增删改查功能
+ * @author AI Assistant
+ * @version 1.0.0
+ */
+import request from '@/router/axios';
+
+/**
+ * 分类数据类型定义
+ * @typedef {Object} CategoryItem
+ * @property {number} id - 分类ID
+ * @property {string} name - 分类名称
+ * @property {number} sortOrder - 排序
+ * @property {number} orgId - 组织ID
+ * @property {string} orgCode - 组织编码
+ * @property {string} orgName - 组织名称
+ * @property {number} isSystem - 是否系统分类 (0-否, 1-是)
+ * @property {string} remark - 备注
+ * @property {number} createUser - 创建用户ID
+ * @property {number} createDept - 创建部门ID
+ * @property {string|null} createTime - 创建时间
+ * @property {number|null} updateUser - 更新用户ID
+ * @property {string|null} updateTime - 更新时间
+ * @property {number} status - 状态 (0-禁用, 1-启用)
+ * @property {number} isDeleted - 是否删除 (0-否, 1-是)
+ */
+
+/**
+ * 新增分类请求参数类型
+ * @typedef {Object} AddCategoryParams
+ * @property {number} createDept - 创建部门ID
+ * @property {number} createUser - 创建用户ID
+ * @property {string} name - 分类名称
+ * @property {string} orgCode - 组织编码
+ * @property {number} orgId - 组织ID
+ * @property {string} orgName - 组织名称
+ * @property {string} [remark] - 备注
+ * @property {number} [sortOrder] - 排序
+ */
+
+/**
+ * 更新分类请求参数类型
+ * @typedef {AddCategoryParams & {id: number}} UpdateCategoryParams
+ */
+
+/**
+ * API响应类型
+ * @typedef {Object} ApiResponse
+ * @property {number} code - 响应码
+ * @property {boolean} success - 是否成功
+ * @property {*} data - 响应数据
+ * @property {string} msg - 响应消息
+ */
+
+/**
+ * 获取分类列表
+ * @returns {Promise<ApiResponse<Array<CategoryItem>>>} 分类列表响应
+ */
+export const getCategoryList = () => {
+  return request({
+    url: '/blade-factory/api/notice/category/list',
+    method: 'get'
+  })
+}
+
+/**
+ * 新增分类
+ * @param {AddCategoryParams} params - 分类信息
+ * @param {number} params.createDept - 创建部门ID
+ * @param {number} params.createUser - 创建用户ID
+ * @param {string} params.name - 分类名称
+ * @param {string} params.orgCode - 组织编码
+ * @param {number} params.orgId - 组织ID
+ * @param {string} params.orgName - 组织名称
+ * @param {string} [params.remark=''] - 备注
+ * @param {number} [params.sortOrder=0] - 排序
+ * @returns {Promise<ApiResponse<null>>} 操作结果
+ */
+export const addCategory = (params) => {
+  return request({
+    url: '/blade-factory/api/notice/category/add',
+    method: 'post',
+    data: {
+      sortOrder: 0,
+      ...params
+    }
+  })
+}
+
+/**
+ * 更新分类
+ * @param {UpdateCategoryParams} params - 分类信息(包含id)
+ * @param {number} params.id - 分类ID
+ * @param {string} params.name - 分类名称
+ * @param {string} [params.remark] - 备注
+ * @param {number} [params.sortOrder] - 排序
+ * @returns {Promise<ApiResponse<null>>} 操作结果
+ */
+export const updateCategory = (params) => {
+  return request({
+    url: '/blade-factory/api/notice/category/update',
+    method: 'post',
+    data: params
+  })
+}
+
+/**
+ * 删除分类
+ * @param {string|number} ids - 分类ID,多个用逗号分隔
+ * @returns {Promise<ApiResponse<null>>} 操作结果
+ */
+export const removeCategory = (ids) => {
+  return request({
+    url: '/blade-factory/api/notice/category/remove',
+    method: 'post',
+    params: {
+      ids: String(ids)
+    }
+  })
+}
+
+/**
+ * 获取分类详情
+ * @param {number} id - 分类ID
+ * @returns {Promise<ApiResponse<CategoryItem>>} 分类详情
+ */
+export const getCategoryDetail = (id) => {
+  return request({
+    url: '/blade-factory/api/notice/category/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+/**
+ * 更新分类状态
+ * @param {number} id - 分类ID
+ * @param {number} status - 状态 (0-禁用, 1-启用)
+ * @returns {Promise<ApiResponse<null>>} 操作结果
+ */
+export const updateCategoryStatus = (id, status) => {
+  return request({
+    url: '/blade-factory/api/notice/category/status',
+    method: 'post',
+    params: {
+      id,
+      status
+    }
+  })
+}

+ 2 - 2
src/api/announcement/index.js

@@ -64,10 +64,10 @@ export const getBrandList = () => {
   })
 }
 
-// 获取分类列表
+// 获取分类列表 - 更新为使用新的分类接口
 export const getCategoryList = () => {
   return request({
-    url: '/api/blade-system/category/list',
+    url: '/blade-factory/api/notice/category/list',
     method: 'get'
   })
 }

+ 16 - 1
src/router/views/index.js

@@ -30,13 +30,28 @@ export default [{
     path: '/announcement',
     component: Layout,
     redirect: '/announcement/index',
+    meta: {
+        title: '公告管理',
+        icon: 'el-icon-bell'
+    },
     children: [{
         path: 'index',
         name: '公告管理',
         meta: {
             keepAlive: true,
+            title: '公告管理',
+            icon: 'el-icon-document'
         },
-        component: () => import( /* webpackChunkName: "views" */ '@/views/announcement/index')
+        component: () => import( /* webpackChunkName: "announcement" */ '@/views/announcement/index')
+    }, {
+        path: 'category',
+        name: '分类管理',
+        meta: {
+            keepAlive: true,
+            title: '分类管理',
+            icon: 'el-icon-folder'
+        },
+        component: () => import( /* webpackChunkName: "announcement" */ '@/views/announcement/category')
     }]
 }, {
     path: '/forecast',

+ 544 - 0
src/views/announcement/category.vue

@@ -0,0 +1,544 @@
+<template>
+  <div>
+    <basic-container>
+      <avue-crud
+        :option="option"
+        :table-loading="loading"
+        :data="data"
+        ref="crud"
+        v-model="form"
+        :permission="permissionList"
+        :before-open="beforeOpen"
+        :before-close="beforeClose"
+        @row-del="rowDel"
+        @row-update="rowUpdate"
+        @row-save="rowSave"
+        @search-change="searchChange"
+        @search-reset="searchReset"
+        @selection-change="selectionChange"
+        @refresh-change="refreshChange"
+        @on-load="onLoad"
+      >
+        <template slot="menuLeft">
+          <el-button
+            type="danger"
+            size="small"
+            icon="el-icon-delete"
+            v-if="permission.category_delete"
+            plain
+            @click="handleDelete"
+          >
+            删除
+          </el-button>
+        </template>
+
+        <template slot-scope="{ row }" slot="status">
+          <el-switch
+            v-model="row.status"
+            :active-value="1"
+            :inactive-value="0"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            @change="handleStatusChange(row)"
+            :disabled="!permission.category_edit"
+          >
+          </el-switch>
+        </template>
+
+        <template slot-scope="{ row }" slot="isSystem">
+          <el-tag :type="row.isSystem ? 'warning' : 'success'">
+            {{ row.isSystem ? '系统分类' : '自定义分类' }}
+          </el-tag>
+        </template>
+      </avue-crud>
+    </basic-container>
+  </div>
+</template>
+
+<script>
+/**
+ * 公告分类管理页面
+ * @description 提供公告分类的完整CRUD功能,包括状态管理
+ * @author AI Assistant
+ * @version 1.0.0
+ */
+import {
+  getCategoryList,
+  addCategory,
+  updateCategory,
+  removeCategory,
+  getCategoryDetail,
+  updateCategoryStatus
+} from "@/api/announcement/category";
+import { mapGetters } from "vuex";
+
+/**
+ * 分类表单数据类型
+ * @typedef {Object} CategoryForm
+ * @property {number} [id] - 分类ID(编辑时存在)
+ * @property {string} name - 分类名称
+ * @property {number} sortOrder - 排序
+ * @property {number} orgId - 组织ID
+ * @property {string} orgCode - 组织编码
+ * @property {string} orgName - 组织名称
+ * @property {string} remark - 备注
+ * @property {number} status - 状态
+ */
+
+/**
+ * 查询参数类型
+ * @typedef {Object} QueryParams
+ * @property {string} [name] - 分类名称
+ * @property {string} [orgName] - 组织名称
+ * @property {number} [status] - 状态
+ */
+
+export default {
+  name: "CategoryManagement",
+
+  data() {
+    return {
+      /** @type {CategoryForm} 表单数据 */
+      form: {},
+
+      /** @type {Array<import('@/api/announcement/category').CategoryItem>} 选中的行数据 */
+      selectionList: [],
+
+      /** @type {QueryParams} 查询条件 */
+      query: {},
+
+      /** @type {boolean} 表格加载状态 */
+      loading: true,
+
+      /** @type {Array<import('@/api/announcement/category').CategoryItem>} 表格数据 */
+      data: [],
+
+      /** @type {Object} 表格配置选项 */
+      option: {
+        height: 'auto',
+        calcHeight: 30,
+        tip: false,
+        searchShow: true,
+        searchMenuSpan: 6,
+        border: true,
+        index: true,
+        selection: true,
+        viewBtn: true,
+        dialogClickModal: false,
+        column: [
+          {
+            label: "分类名称",
+            prop: "name",
+            search: true,
+            rules: [
+              {
+                required: true,
+                message: "请输入分类名称",
+                trigger: "blur"
+              },
+              {
+                min: 2,
+                max: 50,
+                message: "分类名称长度在2到50个字符",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "组织名称",
+            prop: "orgName",
+            search: true,
+            rules: [
+              {
+                required: true,
+                message: "请输入组织名称",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "组织编码",
+            prop: "orgCode",
+            rules: [
+              {
+                required: true,
+                message: "请输入组织编码",
+                trigger: "blur"
+              },
+              {
+                pattern: /^[A-Z0-9_]+$/,
+                message: "组织编码只能包含大写字母、数字和下划线",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "组织ID",
+            prop: "orgId",
+            type: "number",
+            rules: [
+              {
+                required: true,
+                message: "请输入组织ID",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "排序",
+            prop: "sortOrder",
+            type: "number",
+            value: 0,
+            rules: [
+              {
+                type: "number",
+                min: 0,
+                max: 9999,
+                message: "排序值范围为0-9999",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "状态",
+            prop: "status",
+            type: "select",
+            slot: true,
+            dicData: [
+              {
+                label: "启用",
+                value: 1
+              },
+              {
+                label: "禁用",
+                value: 0
+              }
+            ],
+            search: true,
+            value: 1
+          },
+          {
+            label: "分类类型",
+            prop: "isSystem",
+            slot: true,
+            addDisplay: false,
+            editDisplay: false
+          },
+          {
+            label: "备注",
+            prop: "remark",
+            type: "textarea",
+            span: 24,
+            hide: true,
+            rules: [
+              {
+                max: 500,
+                message: "备注不能超过500个字符",
+                trigger: "blur"
+              }
+            ]
+          },
+          {
+            label: "创建时间",
+            prop: "createTime",
+            type: "datetime",
+            format: "yyyy-MM-dd HH:mm:ss",
+            valueFormat: "yyyy-MM-dd HH:mm:ss",
+            addDisplay: false,
+            editDisplay: false,
+            width: 180
+          }
+        ]
+      }
+    };
+  },
+
+  computed: {
+    ...mapGetters(["permission", "userInfo"]),
+
+    /**
+     * 权限列表配置
+     * @returns {Object} 权限配置对象
+     */
+    permissionList() {
+      return {
+        // addBtn: this.vaildData(this.permission.category_add, false),
+        addBtn: true,
+        viewBtn: this.vaildData(this.permission.category_view, false),
+        delBtn: this.vaildData(this.permission.category_delete, false),
+        editBtn: this.vaildData(this.permission.category_edit, false)
+      };
+    },
+
+    /**
+     * 表格行主键
+     * @returns {string} 主键字段名
+     */
+    ids() {
+      const ids = [];
+      this.selectionList.forEach(ele => {
+        ids.push(ele.id);
+      });
+      return ids.join(",");
+    }
+  },
+
+  methods: {
+    /**
+     * 删除选中的分类
+     * @description 批量删除选中的分类
+     */
+    handleDelete() {
+      if (this.selectionList.length === 0) {
+        this.$message.warning("请选择至少一条数据");
+        return;
+      }
+
+      // 检查是否包含系统分类
+      const hasSystemCategory = this.selectionList.some(item => item.isSystem === 1);
+      if (hasSystemCategory) {
+        this.$message.error("系统分类不能删除");
+        return;
+      }
+
+      this.$confirm("确定将选择数据删除?", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          return removeCategory(this.ids);
+        })
+        .then(() => {
+          this.onLoad();
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          this.$refs.crud.toggleSelection();
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除"
+          });
+        });
+    },
+
+    /**
+     * 状态变更处理
+     * @param {import('@/api/announcement/category').CategoryItem} row - 行数据
+     */
+    handleStatusChange(row) {
+      const statusText = row.status === 1 ? '启用' : '禁用';
+      this.$confirm(`确定${statusText}该分类吗?`, {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          return updateCategoryStatus(row.id, row.status);
+        })
+        .then(() => {
+          this.$message({
+            type: "success",
+            message: `${statusText}成功!`
+          });
+        })
+        .catch(() => {
+          // 恢复原状态
+          row.status = row.status === 1 ? 0 : 1;
+          this.$message({
+            type: "info",
+            message: "已取消操作"
+          });
+        });
+    },
+
+    /**
+     * 表单打开前的回调
+     * @param {Function} done - 完成回调
+     * @param {string} type - 操作类型 (add/edit/view)
+     */
+    beforeOpen(done, type) {
+      if (["edit", "view"].includes(type)) {
+        getCategoryDetail(this.form.id).then(res => {
+          this.form = res.data.data;
+        });
+      } else if (type === "add") {
+        // 新增时设置默认值
+        this.form = {
+          createDept: this.userInfo.deptId || 1,
+          createUser: this.userInfo.userId || 1,
+          orgId: 1,
+          orgCode: "ORG_0001",
+          orgName: "库比森",
+          sortOrder: 0,
+          status: 1,
+          remark: ""
+        };
+      }
+      done();
+    },
+
+    /**
+     * 表单关闭前的回调
+     * @param {Function} done - 完成回调
+     */
+    beforeClose(done) {
+      this.form = {};
+      done();
+    },
+
+    /**
+     * 行删除回调
+     * @param {import('@/api/announcement/category').CategoryItem} row - 行数据
+     * @param {number} index - 行索引
+     */
+    rowDel(row, index) {
+      if (row.isSystem === 1) {
+        this.$message.error("系统分类不能删除");
+        return;
+      }
+
+      this.$confirm("确定将选择数据删除?", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          return removeCategory(row.id);
+        })
+        .then(() => {
+          this.onLoad();
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+        });
+    },
+
+    /**
+     * 行更新回调
+     * @param {CategoryForm} row - 行数据
+     * @param {number} index - 行索引
+     * @param {Function} done - 完成回调
+     * @param {Function} loading - 加载状态回调
+     */
+    rowUpdate(row, index, done, loading) {
+      updateCategory(row)
+        .then(() => {
+          this.onLoad();
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        })
+        .catch(() => {
+          loading();
+        });
+    },
+
+    /**
+     * 行保存回调
+     * @param {CategoryForm} row - 行数据
+     * @param {Function} done - 完成回调
+     * @param {Function} loading - 加载状态回调
+     */
+    rowSave(row, done, loading) {
+      addCategory(row)
+        .then(() => {
+          this.onLoad();
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        })
+        .catch(() => {
+          loading();
+        });
+    },
+
+    /**
+     * 搜索条件变化回调
+     * @param {QueryParams} params - 搜索参数
+     * @param {Function} done - 完成回调
+     */
+    searchChange(params, done) {
+      this.query = params;
+      this.onLoad(params);
+      done();
+    },
+
+    /**
+     * 搜索重置回调
+     */
+    searchReset() {
+      this.query = {};
+      this.onLoad();
+    },
+
+    /**
+     * 选择变化回调
+     * @param {Array<import('@/api/announcement/category').CategoryItem>} list - 选中的行数据列表
+     */
+    selectionChange(list) {
+      this.selectionList = list;
+    },
+
+    /**
+     * 清空选择
+     */
+    selectionClear() {
+      this.selectionList = [];
+      this.$refs.crud.toggleSelection();
+    },
+
+    /**
+     * 刷新回调
+     */
+    refreshChange() {
+      this.onLoad(this.query);
+    },
+
+    /**
+     * 加载数据
+     * @param {QueryParams} params - 查询参数
+     */
+    onLoad(params = {}) {
+      this.loading = true;
+      getCategoryList(Object.assign(params, this.query))
+        .then(res => {
+          const data = res.data.data;
+          this.data = Array.isArray(data) ? data : [];
+          this.loading = false;
+          this.selectionClear();
+        })
+        .catch(() => {
+          this.loading = false;
+          this.data = [];
+        });
+    }
+  },
+
+  /**
+   * 组件挂载后初始化数据
+   */
+  mounted() {
+    this.onLoad();
+  }
+};
+</script>
+
+<style scoped>
+/* 组件样式 */
+.el-tag {
+  margin-right: 8px;
+}
+
+.el-switch {
+  margin: 0;
+}
+</style>