diff --git a/src/router/index.tsx b/src/router/index.tsx index 87706f91f87d5bd62d4ee4a039caa8ed1f776f8f..53b8c7944aab25f86bef6a76fc2e814900445ade 100644 --- a/src/router/index.tsx +++ b/src/router/index.tsx @@ -46,7 +46,21 @@ const Router: React.FC = () => { menu2.children.length <= 0 && renderElement(menu2.path) } - > + > + {menu2.children && + menu2.children.length > 0 && + menu2.children.map((menu3: IMenubar) => ( + + ))} + ))} )); diff --git a/src/utils/index.ts b/src/utils/index.ts index 32f7c4ab2273cd305e540d078c04d871acd2b2c9..26a5d780a2959e03f4553d4a9a255e855840b290 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -68,8 +68,8 @@ export const treeFormat = (data: any, options?: ITreeOptions) => { options && options.children ? options.children : defaultOptions.children; data.forEach((element: ITree) => { const obj: ITree = { - label: element[label], - id: element[id], + title: element[label], + key: element[id], children: [], }; if (element[children] && element[children].length > 0) { diff --git a/src/views/system/dept/index.tsx b/src/views/system/dept/index.tsx index 499f9c0452a336652de518ddd57b83600a4d8459..4b4083aa9c668f38e4c040a7d1a5ad3f0b1ff8a3 100644 --- a/src/views/system/dept/index.tsx +++ b/src/views/system/dept/index.tsx @@ -121,7 +121,6 @@ const Dept: React.FC = () => { * 加载数据 */ const loadData = () => { - debugger; const { key } = currentTreeData; const pId = key; setLoading(true); @@ -153,7 +152,6 @@ const Dept: React.FC = () => { }); }; const handleTreeClick = (data: any, done: any) => { - debugger; setCurrentTreeData({ ...data }); done(); }; diff --git a/src/views/system/dictionary/index.tsx b/src/views/system/dictionary/index.tsx index acec8c538baae91f4566f7dc80af29a95645b675..696e88bfd62c46d7d9b22cde466432709ce965f0 100644 --- a/src/views/system/dictionary/index.tsx +++ b/src/views/system/dictionary/index.tsx @@ -1,7 +1,270 @@ +/**导入第三方库 */ +import { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { Modal, TreeDataNode, message } from "antd"; +import { ExclamationCircleFilled } from "@ant-design/icons"; +import { + Crud, + IColumn, + IActionbar, + IToolbar, + IFormItem, + IOptions, + ITree, + ILeftTree, + IDialogTitle, +} from "@ainiteam/quick-react-ui"; +/**导入项目文件 */ +import { selectFormat, treeFormat, validatePermission } from "@/utils"; +import { AppDispatch, RootState } from "@/store"; +import { getPermissionBtns } from "@/store/modules/user"; +import { + addDictionary, + deleteDictionary, + getDictionaryList, + getDictionaryTypeList, + updateDictionary, +} from "@/api/system/dictionary"; +import { + IDictionary, + IDictionaryPermissionButton, + IDictionaryType, +} from "@/types"; + const Dictionary: React.FC = () => { - return ( -
Dictionary
- ); + const { confirm } = Modal; + const [dicTypeSelectData, setDicTypeSelectData] = useState([]); + const [treeDataList, setTreeDataList] = useState([]); + const [dataList, setDataList] = useState([]); + const [loading, setLoading] = useState(false); + const dispatch: AppDispatch = useDispatch(); + const { activeTab } = useSelector((state: RootState) => state.tab); + + const { permissionBtn }: { permissionBtn: IDictionaryPermissionButton } = + useSelector((state: RootState) => state.user); + + const [currentTreeData, setCurrentTreeData] = useState({ + key: "", + title: "", + children: [], + }); + + /** + * 加载字典分类下拉框 + * @param data 字典分类数据 + */ + const loadDicTypeSelect = (data: IDictionaryType[]) => { + const dicTypeselect = selectFormat(data, { + value: "dicTypeId", + label: "dicTypeName", + }); + dicTypeSelectData.length = 0; + dicTypeSelectData.push(...dicTypeselect); + }; + /** + * 加载数据 + */ + const loadData = () => { + const { key } = currentTreeData; + + setLoading(true); + getDictionaryList(key).then((res) => { + setLoading(false); + const { data: dictionaryList } = res; + console.log("dictionaryList", dictionaryList); + + setDataList([...dictionaryList]); + }); + }; + /** + * 左树 + */ + + const [leftTree] = useState({ + treeData: [], + treeSpan: 6, + }); + const treeloadData = (done: any) => { + getDictionaryTypeList().then((res) => { + const { data: dictionaryTypeList } = res; + loadDicTypeSelect(dictionaryTypeList); + const dicTree = treeFormat(dictionaryTypeList, { + id: "dicTypeId", + label: "dicTypeName", + }); + console.log("dictionaryTree", dictionaryTypeList); + setTreeDataList([...dicTree]); + leftTree.treeData = dicTree; + console.log("dicTree", dicTree); + + setCurrentTreeData({ ...(treeDataList && treeDataList[0]) }); + done(currentTreeData); + }); + }; + const handleTreeClick = (data: ITree, done: any) => { + setCurrentTreeData({ ...data }); + done(); + }; + /** + * 表单 + */ + const dialogTitle: IDialogTitle = { + add: "创建字典", + edit: "修改字典", + detail: "字典详情", + }; + const formModel: IDictionary = { + id: undefined, + dicTypeId: undefined, + dicId: "", + dicName: "", + }; + const formItems: IFormItem[] = [ + { + label: "字典编号", + labelWidth: "80px", + vModel: "dicId", + placeholder: "字典编号", + editReadonly: true, + prop: "dicId", + rules: [ + { + required: true, + message: "字典编号不能为空", + trigger: "blur", + }, + ], + }, + { + label: "字典名称", + labelWidth: "80px", + vModel: "dicName", + placeholder: "字典名称", + prop: "dicName", + rules: [ + { + required: true, + message: "字典名称不能为空", + trigger: "blur", + }, + ], + }, + { + label: "字典类型", + labelWidth: "80px", + vModel: "dicTypeId", + placeholder: "字典类型", + type: "select", + addDisabled: true, + editDisabled: true, + detailDisabled: true, + options: dicTypeSelectData, + prop: "dicTypeId", + }, + ]; + /** + * 操作栏 + */ + const handleDelete = (item: IDictionary, done: any) => { + confirm({ + title: "警告", + icon: , + content: `你真的删除【${item.dicName}】的字典吗?`, + onOk() { + if (!item.id) { + return; + } + deleteDictionary(item.id).then(() => { + message.success("字典删除成功"); + done(); + }); + }, + }); + }; + const tableActionbar: IActionbar = { + width: 300, + hiddenDetailButton: true, + hiddenEditButton: !validatePermission(permissionBtn?.edit), + hiddenDeleteButton: !validatePermission(permissionBtn?.delete), + }; + /** + * 工具栏 + */ + const handleAdd = (item: IDictionary, done: any) => { + const form = { ...item }; + form.dicTypeId = currentTreeData.id; + done(form); + }; + const tableToolbar: IToolbar = { + hiddenBatchDeleteButton: true, + hiddenImportButton: true, + hiddenExportButton: true, + hiddenPrintButton: true, + hiddenAddButton: !validatePermission(permissionBtn?.add), + }; + /** + * 表格 + */ + const tableColumns: IColumn[] = [ + { + width: "50", + type: "selection", + }, + { + label: "字典编号", + prop: "dicId", + width: "200", + }, + { + label: "字典名称", + prop: "dicName", + }, + ]; + const handleFormSubmit = (form: IDictionary, done: any) => { + const row = { ...form }; + if (row.id) { + console.log("updateDictionary", row); + updateDictionary(row).then(() => { + message.success("字典修改成功"); + done(); + }); + } else { + row.id = undefined; + console.log("addDictionary", row); + addDictionary(row).then(() => { + message.success("字典创建成功"); + done(); + }); + } + }; + useEffect(() => { + dispatch(getPermissionBtns(activeTab)); + loadData(); + }, [activeTab, currentTreeData, dispatch]); + return ( + <> +
+ +
+ + ); }; -export default Dictionary; \ No newline at end of file +export default Dictionary; diff --git a/src/views/system/dictionaryType/index.tsx b/src/views/system/dictionaryType/index.tsx index 15f64dfccc3844bf4d58f170f980e74ec68fce4c..62dab4e98d39c15ad46754066ad0a8a3380053e0 100644 --- a/src/views/system/dictionaryType/index.tsx +++ b/src/views/system/dictionaryType/index.tsx @@ -1,7 +1,223 @@ +import { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { Modal, message } from "antd"; +import { ExclamationCircleFilled } from "@ant-design/icons"; +import { + IActionbar, + IColumn, + IFormItem, + IPage, + IToolbar, + Crud, + IDialogTitle, +} from "@ainiteam/quick-react-ui"; + +import { validatePermission } from "@/utils"; +import { IDictionaryType, IUserPermissionButton } from "@/types"; +import { + getDictionaryTypeList, + addDictionaryType, + updateDictionaryType, + deleteDictionaryType, +} from "@/api/system/dictionaryType"; +import { AppDispatch, RootState } from "@/store"; +import { getPermissionBtns } from "@/store/modules/user"; + const DictionaryType: React.FC = () => { - return ( -
DictionaryType
- ); + /** + * 属性 + */ + const { confirm } = Modal; + // eslint-disable-next-line react-hooks/rules-of-hooks + const dispatch: AppDispatch = useDispatch(); + const { activeTab } = useSelector((state: RootState) => state.tab); + useEffect(() => { + dispatch(getPermissionBtns(activeTab)); + }, []); + const { permissionBtn }: { permissionBtn: IUserPermissionButton } = + useSelector((state: RootState) => state.user); + const [loading, setLoading] = useState(false); + const [tableDataList, setTableDataList] = useState([]); + + /** + * 分页 + */ + const [page] = useState({ + current: 1, + size: 10, + sizes: [10, 20, 30, 40, 50], + total: 0, + }); + + /** + * 工具栏 + */ + const tableToolbar: IToolbar = { + hiddenBatchDeleteButton: !validatePermission(permissionBtn?.batchDelete), + hiddenImportButton: !validatePermission(permissionBtn?.import), + hiddenExportButton: !validatePermission(permissionBtn?.export), + hiddenAddButton: !validatePermission(permissionBtn?.add), + hiddenPrintButton: !validatePermission(permissionBtn?.print), + position: "left", + // leftToolbarSlot:
lll
, + // rightToolbarSlot:
rrr
, + }; + + /** + * 表单 + */ + const dialogTitle: IDialogTitle = { + add: "添加字典分类", + edit: "编辑字典分类", + detail: "字典分类详情", + }; + const formModel: IDictionaryType = { + id: undefined, + dicTypeId: "", + dicTypeName: "", + // fullName: "", + // phone: "", + // email: "", + // address: "", + }; + const formItems: IFormItem[] = [ + { + label: "字典编号", + labelWidth: "80px", + vModel: "dicTypeId", + editReadonly: true, + placeholder: "请输入字典编号", + prop: "dicTypeId", + rules: [ + { + required: true, + message: "请输入字典编号", + trigger: "blur", + }, + { + // validator: validateUserId, + trigger: "blur", + }, + ], + }, + { + label: "字典名称", + labelWidth: "80px", + vModel: "dicTypeName", + placeholder: "请输入字典名称", + prop: "dicTypeName", + rules: [ + { + required: true, + message: "请输入字典名称", + trigger: "blur", + }, + { + // validator: validateUserName, + trigger: "blur", + }, + ], + }, + ]; + const handleFormSubmit = (form: IDictionaryType, done: any) => { + const row = { ...form }; + debugger; + if (row.id) { + console.log("updateDictionaryType", row); + updateDictionaryType(row).then(() => { + message.success("字典分类修改成功"); + done(); + }); + } else { + row.id = undefined; + console.log("addDictionaryType", row); + addDictionaryType(row).then(() => { + message.success("字典分类创建成功"); + done(); + }); + } + }; + + /** + * 操作栏 + */ + const handleDelete = (item: IDictionaryType, done: any) => { + confirm({ + title: "警告", + icon: , + content: `你真的删除【${item.dicTypeName}】的字典分类吗?`, + onOk() { + if (!item.id) { + return; + } + deleteDictionaryType(item.id).then(() => { + message.success(`【${item.dicTypeName}】的字典分类删除成功`); + done(); + }); + }, + }); + }; + + const tableActionbar: IActionbar = { + width: 200, + hiddenEditButton: !validatePermission(permissionBtn?.edit), + hiddenDeleteButton: !validatePermission(permissionBtn?.delete), + hiddenDetailButton: !validatePermission(permissionBtn?.detail), + }; + + /** + * 表格 + */ + const tableColumns: IColumn[] = [ + { + label: "字典编号", + prop: "dicTypeId", + }, + { + label: "字典名称", + prop: "dicTypeName", + // edit: true, + }, + ]; + + /** + * 加载数据 + */ + const loadData = (parmas: object) => { + setLoading(true); + getDictionaryTypeList(parmas) + .then((res) => { + setLoading(false); + const { data: userList, total } = res; + console.log("userList", userList); + if (userList) { + setTableDataList([...userList]); + } + page.total = total; + }) + .catch(() => { + setLoading(false); + }); + }; + + return ( +
+ +
+ ); }; -export default DictionaryType; \ No newline at end of file +export default DictionaryType; diff --git a/src/views/system/log/error.tsx b/src/views/system/log/error.tsx index 4bf5f59baffc576aceb869b1a64b84855d80a2e9..afefad91ec0e3de96addfbb564aead5d6d76c0a0 100644 --- a/src/views/system/log/error.tsx +++ b/src/views/system/log/error.tsx @@ -1,7 +1,248 @@ +import { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { + IColumn, + IActionbar, + IToolbar, + IFormItem, + IPage, + Crud, +} from "@ainiteam/quick-react-ui"; +import { getLogPageList } from "@/api/system/log"; +import { validatePermission } from "@/utils"; +import { ILog, ISearchLog, ILogPermissionButton } from "@/types"; +import { AppDispatch, RootState } from "@/store"; +import { getPermissionBtns } from "@/store/modules/user"; + const Error: React.FC = () => { - return ( -
Error
- ); + /** + * 属性 + */ + const [dataList, setDataList] = useState(); + const [loading, setLoading] = useState(false); + const dispatch: AppDispatch = useDispatch(); + const { activeTab } = useSelector((state: RootState) => state.tab); + const { permissionBtn }: { permissionBtn: ILogPermissionButton } = + useSelector((state: RootState) => state.user); + /** + * 分页 + */ + const [page] = useState({ + current: 1, + size: 10, + sizes: [10, 20, 30, 40, 50], + total: 0, + }); + /** + * 搜索 + */ + const searchForm: ISearchLog = { + startTime: "", + endTime: "", + logTime: "", + }; + const searchFormItems: IFormItem[] = [ + { + label: "日志时间", + vModel: "logTime", + placeholders: ["开始时间", "结束时间"], + type: "rangepicker", + }, + ]; + /** + * 工具栏 + */ + const tableToolbar: IToolbar = { + hiddenImportButton: true, + hiddenExportButton: true, + hiddenAddButton: true, + hiddenPrintButton: true, + hiddenBatchDeleteButton: true, + }; + /** + * 操作栏 + */ + const handleDetail = (item: ILog, done: any) => { + const form: ILog = { ...item }; + if (form.request) { + form.request = JSON.stringify(form.request, null, 4); + done(form); + } + if (form.response) { + form.response = JSON.stringify(form.response, null, 4); + done(form); + } + }; + const tableActionbar: IActionbar = { + width: 60, + hiddenEditButton: true, + hiddenDeleteButton: true, + hiddenDetailButton: !validatePermission(permissionBtn?.detail), + }; + /** + * 表格 + */ + const tableColumns: IColumn[] = [ + { + width: "50", + type: "selection", + align: "center", + }, + { + label: "日志时间", + prop: "createTime", + width: "200", + }, + { + label: "IP", + prop: "ip", + width: "120", + }, + { + label: "耗时(ms)", + prop: "duration", + width: "150", + }, + { + label: "操作人", + prop: "operateId", + width: "200", + }, + { + label: "请求类型", + prop: "request", + render: (value: any) => { + return value.method; + }, + width: "100", + }, + { + label: "请求接口", + prop: "request", + render: (value: any) => { + return value.url; + }, + }, + ]; + /** + * 加载数据 + */ + const loadData = (params: any) => { + let obj = {}; + const { logTime } = params; + if (logTime) { + obj = { + ...params, + type: 1, + startTime: logTime[0], + endTime: logTime[1], + }; + } else { + obj = { ...params, type: 1, logTime: null }; + } + setLoading(true); + getLogPageList(obj) + .then((res) => { + setLoading(false); + const { data: logList, total } = res; + console.log("logList", logList); + if (logList) { + setDataList([...logList]); + } + page.total = total; + }) + .catch(() => { + setLoading(false); + }); + }; + /** + * 表单 + */ + const dialogTitle = { + detail: "日志详情", + }; + const formModel: ILog = { + id: undefined, + type: 1, + ip: "", + request: "", + response: "", + duration: 0, + operateId: "", + createTime: "", + }; + const formItems: IFormItem[] = [ + { + label: "编号", + labelWidth: "80px", + vModel: "id", + }, + { + label: "日志时间", + labelWidth: "80px", + vModel: "createTime", + }, + { + label: "IP", + labelWidth: "80px", + vModel: "ip", + }, + { + label: "耗时", + labelWidth: "80px", + vModel: "duration", + }, + { + label: "操作人ID", + labelWidth: "80px", + vModel: "operateId", + }, + { + label: "操作人", + labelWidth: "80px", + vModel: "operator", + }, + { + label: "请求参数", + labelWidth: "80px", + vModel: "request", + type: "textarea", + }, + { + label: "响应", + labelWidth: "80px", + vModel: "response", + type: "textarea", + }, + { + label: "异常信息", + labelWidth: "80px", + vModel: "exception", + type: "textarea", + }, + ]; + useEffect(() => { + dispatch(getPermissionBtns(activeTab)); + }, []); + return ( +
+ +
+ ); }; -export default Error; \ No newline at end of file +export default Error; diff --git a/src/views/system/log/operate.tsx b/src/views/system/log/operate.tsx index 1e544d2f8df16a6d2c0d4d16ae8264de80b9a276..694ca757b58ba97cef1d46505fd70c8beb07791f 100644 --- a/src/views/system/log/operate.tsx +++ b/src/views/system/log/operate.tsx @@ -1,7 +1,243 @@ +import { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { + IColumn, + IActionbar, + IToolbar, + IFormItem, + IPage, + Crud, +} from "@ainiteam/quick-react-ui"; +import { getLogPageList } from "@/api/system/log"; +import { validatePermission } from "@/utils"; +import { ILog, ISearchLog, ILogPermissionButton } from "@/types"; +import { AppDispatch, RootState } from "@/store"; +import { getPermissionBtns } from "@/store/modules/user"; + const Operate: React.FC = () => { - return ( -
Operate
- ); + /** + * 属性 + */ + const [dataList, setDataList] = useState(); + const [loading, setLoading] = useState(false); + const dispatch: AppDispatch = useDispatch(); + const { activeTab } = useSelector((state: RootState) => state.tab); + const { permissionBtn }: { permissionBtn: ILogPermissionButton } = + useSelector((state: RootState) => state.user); + + /** + * 分页 + */ + const [page] = useState({ + current: 1, + size: 10, + sizes: [10, 20, 30, 40, 50], + total: 0, + }); + /** + * 搜索 + */ + const searchForm: ISearchLog = { + startTime: "", + endTime: "", + logTime: "", + }; + const searchFormItems: IFormItem[] = [ + { + label: "日志时间", + vModel: "logTime", + placeholders: ["开始时间", "结束时间"], + type: "rangepicker", + }, + ]; + /** + * 工具栏 + */ + const tableToolbar: IToolbar = { + hiddenImportButton: true, + hiddenExportButton: true, + hiddenAddButton: true, + hiddenPrintButton: true, + hiddenBatchDeleteButton: true, + }; + /** + * 操作栏 + */ + const handleDetail = (item: ILog, done: any) => { + const form: ILog = { ...item }; + if (form.request) { + form.request = JSON.stringify(form.request, null, 4); + done(form); + } + if (form.response) { + form.response = JSON.stringify(form.response, null, 4); + done(form); + } + }; + const tableActionbar: IActionbar = { + width: 60, + hiddenEditButton: true, + hiddenDeleteButton: true, + hiddenDetailButton: !validatePermission(permissionBtn?.detail), + }; + /** + * 表格 + */ + const tableColumns: IColumn[] = [ + { + width: "50", + type: "selection", + align: "center", + }, + { + label: "日志时间", + prop: "createTime", + width: "200", + }, + { + label: "IP", + prop: "ip", + width: "120", + }, + { + label: "耗时(ms)", + prop: "duration", + width: "150", + }, + { + label: "操作人", + prop: "operateId", + width: "200", + }, + { + label: "请求类型", + prop: "request", + render: (value: any) => { + return value.method; + }, + width: "100", + }, + { + label: "请求接口", + prop: "request", + render: (value: any) => { + return value.url; + }, + }, + ]; + /** + * 加载数据 + */ + const loadData = (params: any) => { + let obj = {}; + const { logTime } = params; + if (logTime) { + obj = { + ...params, + type: 0, + startTime: logTime[0], + endTime: logTime[1], + }; + } else { + obj = { ...params, type: 0, logTime: null }; + } + setLoading(true); + getLogPageList(obj) + .then((res) => { + setLoading(false); + const { data: logList, total } = res; + console.log("logList", logList); + if (logList) { + setDataList([...logList]); + } + page.total = total; + }) + .catch(() => { + setLoading(false); + }); + }; + /** + * 表单 + */ + const dialogTitle = { + detail: "日志详情", + }; + const formModel: ILog = { + id: undefined, + type: 1, + ip: "", + request: "", + response: "", + duration: 0, + operateId: "", + createTime: "", + }; + const formItems: IFormItem[] = [ + { + label: "编号", + labelWidth: "80px", + vModel: "id", + }, + { + label: "日志时间", + labelWidth: "80px", + vModel: "createTime", + }, + { + label: "IP", + labelWidth: "80px", + vModel: "ip", + }, + { + label: "耗时", + labelWidth: "80px", + vModel: "duration", + }, + { + label: "操作人ID", + labelWidth: "80px", + vModel: "operateId", + }, + { + label: "操作人", + labelWidth: "80px", + vModel: "operator", + }, + { + label: "请求参数", + labelWidth: "80px", + vModel: "request", + type: "textarea", + }, + { + label: "响应", + labelWidth: "80px", + vModel: "response", + type: "textarea", + }, + ]; + useEffect(() => { + dispatch(getPermissionBtns(activeTab)); + }, []); + return ( +
+ +
+ ); }; -export default Operate; \ No newline at end of file +export default Operate;