|
|
@@ -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>
|