修复 动态edit页面
This commit is contained in:
parent
78d85e8aac
commit
e113af5378
|
|
@ -1,5 +1,6 @@
|
||||||
import { http } from "@/utils/http";
|
import { http } from "@/utils/http";
|
||||||
import type { Res } from "@/utils/http/types";
|
import type { Res } from "@/utils/http/types";
|
||||||
|
import type { ComboModel } from "@/components/hTable/hTable";
|
||||||
|
|
||||||
export class hTableAPI {
|
export class hTableAPI {
|
||||||
url = "";
|
url = "";
|
||||||
|
|
@ -10,8 +11,8 @@ export class hTableAPI {
|
||||||
PageList(data = {}) {
|
PageList(data = {}) {
|
||||||
return http.request<Res<any>>("post", `${this.url}/PageList`, { data });
|
return http.request<Res<any>>("post", `${this.url}/PageList`, { data });
|
||||||
}
|
}
|
||||||
Info(id, tag = {}) {
|
Info(tag = {}) {
|
||||||
const pUrl = `${this.url}/${id}`;
|
const pUrl = `${this.url}/Info`;
|
||||||
let getUrl = pUrl;
|
let getUrl = pUrl;
|
||||||
for (const key in tag) {
|
for (const key in tag) {
|
||||||
const el = tag[key];
|
const el = tag[key];
|
||||||
|
|
@ -26,6 +27,8 @@ export class hTableAPI {
|
||||||
return http.request<Res<any>>("post", `${this.url}/Del`, { data });
|
return http.request<Res<any>>("post", `${this.url}/Del`, { data });
|
||||||
}
|
}
|
||||||
querycombo(data) {
|
querycombo(data) {
|
||||||
return http.request<Res<any>>("post", `${this.url}/QueryCombo`, { data });
|
return http.request<Res<ComboModel[]>>("post", `${this.url}/QueryCombo`, {
|
||||||
|
data
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import type { Res } from "@/utils/http/types";
|
||||||
|
|
||||||
// 定义菜单项接口
|
// 定义菜单项接口
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
id: number;
|
id?: number;
|
||||||
name: string;
|
name: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
isButton: boolean;
|
isButton: boolean;
|
||||||
|
|
@ -22,3 +22,11 @@ export interface MenuItem {
|
||||||
export function MenuAll() {
|
export function MenuAll() {
|
||||||
return http.request<Res<MenuItem[]>>("get", `Menu/All`);
|
return http.request<Res<MenuItem[]>>("get", `Menu/All`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取所有的菜单
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function Edit(info: MenuItem) {
|
||||||
|
return http.request<Res<MenuItem[]>>("post", `Menu/Edit`, { data: info });
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { http } from "@/utils/http";
|
||||||
|
import type { Res } from "@/utils/http/types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取枚举下拉
|
||||||
|
* @param {string} type 枚举类型 type=StatusEnum
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function getenum(type) {
|
||||||
|
return http.request<Res<any>>("get", `public/enum/${type}`);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 获取枚举对象
|
||||||
|
* @param {string} type 枚举类型 type=StatusEnum
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function getenumDic(type) {
|
||||||
|
return http.request<Res<any>>("get", `public/enum/${type}/Dic`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProvince() {
|
||||||
|
return http.request<Res<any>>("get", `address/province`);
|
||||||
|
}
|
||||||
|
export function getcity(c) {
|
||||||
|
return http.request<Res<any>>("get", `address/${c}/city`);
|
||||||
|
}
|
||||||
|
export function getregion(r) {
|
||||||
|
return http.request<Res<any>>("get", `address/${r}/region`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 编辑学校
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
export function EditSchool(data: any) {
|
||||||
|
return http.request<Res<any>>("post", `School/Edit`, { data });
|
||||||
|
}
|
||||||
|
|
@ -78,14 +78,14 @@ export interface FieldSetting {
|
||||||
*/
|
*/
|
||||||
imgUrl?: (value: any, row: any) => string;
|
imgUrl?: (value: any, row: any) => string;
|
||||||
/* 数据源 */
|
/* 数据源 */
|
||||||
datasource?: Array<{
|
datasource?: ComboModel[];
|
||||||
Value: any;
|
|
||||||
Text: string;
|
|
||||||
}>;
|
|
||||||
}
|
}
|
||||||
///* 表格列配置 */
|
///* 表格列配置 */
|
||||||
//export interface TableEditColumn {}
|
//export interface TableEditColumn {}
|
||||||
|
export interface ComboModel {
|
||||||
|
Value: any;
|
||||||
|
Text: string;
|
||||||
|
}
|
||||||
/* 表格列配置 */
|
/* 表格列配置 */
|
||||||
export interface TableColumn {
|
export interface TableColumn {
|
||||||
/* 显示标签 */
|
/* 显示标签 */
|
||||||
|
|
@ -103,7 +103,7 @@ export interface TableColumn {
|
||||||
/* 是否允许添加 */
|
/* 是否允许添加 */
|
||||||
add: boolean;
|
add: boolean;
|
||||||
/* 是否允许修改 */
|
/* 是否允许修改 */
|
||||||
edit: boolean;
|
edit?: boolean;
|
||||||
/* 列宽度 */
|
/* 列宽度 */
|
||||||
width?: string;
|
width?: string;
|
||||||
/* 字段类型 */
|
/* 字段类型 */
|
||||||
|
|
@ -118,9 +118,9 @@ export interface TableColumn {
|
||||||
/* 字段设置 */
|
/* 字段设置 */
|
||||||
setting?: FieldSetting;
|
setting?: FieldSetting;
|
||||||
/* 修改时的编辑值 */
|
/* 修改时的编辑值 */
|
||||||
valueE?: Array<string> | string;
|
valueE?: Array<string> | string | number | boolean | Date;
|
||||||
/* 查询值 */
|
/* 查询值 */
|
||||||
value?: Array<string> | string;
|
value?: Array<string> | string | number | boolean | Date;
|
||||||
/** textarea编辑时的行数 */
|
/** textarea编辑时的行数 */
|
||||||
editRows?: number;
|
editRows?: number;
|
||||||
/**编辑时值发生变化 */
|
/**编辑时值发生变化 */
|
||||||
|
|
@ -179,4 +179,6 @@ export interface TableConfig {
|
||||||
selectRows: any[];
|
selectRows: any[];
|
||||||
/* 是否显示边框 */
|
/* 是否显示边框 */
|
||||||
border: boolean;
|
border: boolean;
|
||||||
|
/**是否显示 */
|
||||||
|
show?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const props = defineProps({
|
||||||
});
|
});
|
||||||
const emit = defineEmits(["handlePagedCallback"]);
|
const emit = defineEmits(["handlePagedCallback"]);
|
||||||
const editFormRef = ref<FormInstance>();
|
const editFormRef = ref<FormInstance>();
|
||||||
const column: Record<string, TableColumn> = {};
|
const column = ref<Record<string, TableColumn>>({});
|
||||||
const editData = ref({
|
const editData = ref({
|
||||||
frorm: {},
|
frorm: {},
|
||||||
isedit: props.id !== -1,
|
isedit: props.id !== -1,
|
||||||
|
|
@ -118,7 +118,7 @@ function fetchFormData() {
|
||||||
editData.value.loading = false;
|
editData.value.loading = false;
|
||||||
handleResetForm();
|
handleResetForm();
|
||||||
if (editData.value.isedit) {
|
if (editData.value.isedit) {
|
||||||
Api.Info(props.id).then(res => {
|
Api.Info({ id: props.id }).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
editData.value.frorm = res.data;
|
editData.value.frorm = res.data;
|
||||||
for (const key in column.value) {
|
for (const key in column.value) {
|
||||||
|
|
@ -141,7 +141,6 @@ function fetchFormData() {
|
||||||
ref="editFormRef"
|
ref="editFormRef"
|
||||||
:model="editData.table.column"
|
:model="editData.table.column"
|
||||||
:label-width="editData.formLabelWidth"
|
:label-width="editData.formLabelWidth"
|
||||||
size="small"
|
|
||||||
clearable
|
clearable
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
|
@ -154,7 +153,7 @@ function fetchFormData() {
|
||||||
>
|
>
|
||||||
<div v-if="o.type.trim() == 'datetime'">
|
<div v-if="o.type.trim() == 'datetime'">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="o.valueE"
|
v-model="o.valueE as Date"
|
||||||
format="yyyy-MM-dd HH:mm:ss"
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
value-format="yyyy-MM-dd HH:mm:ss"
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
import { Search } from "@element-plus/icons-vue";
|
import { Search } from "@element-plus/icons-vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { defineAsyncComponent, AsyncComponentLoader } from "vue";
|
import { defineAsyncComponent, AsyncComponentLoader } from "vue";
|
||||||
import { Dialog, TableConfig } from "./hTable";
|
import { Dialog, TableColumn, TableConfig } from "./hTable";
|
||||||
import hTableEdit from "./hTableEdit.vue";
|
import hTableEdit from "./hTableEdit.vue";
|
||||||
import { hTableAPI } from "@/api/hTable";
|
import { hTableAPI } from "@/api/hTable";
|
||||||
import { getenum } from "@/api/enum";
|
import { getenum } from "@/api/enum";
|
||||||
|
|
@ -33,10 +33,16 @@ const props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const table = ref<TableConfig>(props.tableConfig);
|
const table = ref<TableConfig>(props.tableConfig);
|
||||||
|
const tableShowColumn = ref<Record<string, TableColumn>>();
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
/* 初始化系统配置 */
|
/* 初始化系统配置 */
|
||||||
nextTick(async () => {
|
nextTick(async () => {
|
||||||
intdata();
|
intdata();
|
||||||
|
//过滤无法显示的列
|
||||||
|
tableShowColumn.value = Object.fromEntries(
|
||||||
|
Object.entries(table.value.column).filter(([_, s]) => s.show)
|
||||||
|
);
|
||||||
|
|
||||||
Api = new hTableAPI(table.value.apiUrl);
|
Api = new hTableAPI(table.value.apiUrl);
|
||||||
init.value = true;
|
init.value = true;
|
||||||
tableShow.value = true;
|
tableShow.value = true;
|
||||||
|
|
@ -55,7 +61,6 @@ onUnmounted(() => {});
|
||||||
// });
|
// });
|
||||||
const tableShow = ref(false);
|
const tableShow = ref(false);
|
||||||
let Api: hTableAPI = null;
|
let Api: hTableAPI = null;
|
||||||
const instance = getCurrentInstance();
|
|
||||||
|
|
||||||
const init = ref(false);
|
const init = ref(false);
|
||||||
const tableHeight = ref(0);
|
const tableHeight = ref(0);
|
||||||
|
|
@ -109,9 +114,9 @@ function intdata() {
|
||||||
if (element.show === undefined) element.show = true;
|
if (element.show === undefined) element.show = true;
|
||||||
if (element.editShow === undefined) element.editShow = true;
|
if (element.editShow === undefined) element.editShow = true;
|
||||||
if (!element.setting)
|
if (!element.setting)
|
||||||
element.setting = { datasource: [], mapValue: "Value", maplabel: "Text" };
|
element.setting = { datasource: [], mapValue: "value", maplabel: "text" };
|
||||||
if (!element.setting.mapValue) element.setting.mapValue = "Value";
|
if (!element.setting.mapValue) element.setting.mapValue = "value";
|
||||||
if (!element.setting.maplabel) element.setting.maplabel = "Text";
|
if (!element.setting.maplabel) element.setting.maplabel = "text";
|
||||||
|
|
||||||
if (!element.change) element.change = () => {};
|
if (!element.change) element.change = () => {};
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +176,7 @@ function handleAdd() {
|
||||||
dialog.value.width = "500px";
|
dialog.value.width = "500px";
|
||||||
}
|
}
|
||||||
function handleEdit(obj, row) {
|
function handleEdit(obj, row) {
|
||||||
dialog.value.edit.id = row[0].Id;
|
dialog.value.edit.id = row[0].id;
|
||||||
dialog.value.edit.row = row[0];
|
dialog.value.edit.row = row[0];
|
||||||
dialog.value.edit.tagData = obj.tagData;
|
dialog.value.edit.tagData = obj.tagData;
|
||||||
dialog.value.title = obj.label || "修改";
|
dialog.value.title = obj.label || "修改";
|
||||||
|
|
@ -185,7 +190,7 @@ function handleCustom(obj, row, custom) {
|
||||||
dialog.value.custom.custom = custom || [];
|
dialog.value.custom.custom = custom || [];
|
||||||
// 异步加载组件
|
// 异步加载组件
|
||||||
dialog.value.custom.component = defineAsyncComponent({
|
dialog.value.custom.component = defineAsyncComponent({
|
||||||
loader: () => import(/* @vite-ignore */ `../${custom.src}.vue`)
|
loader: () => import(/* @vite-ignore */ `../../views/${custom.src}.vue`)
|
||||||
});
|
});
|
||||||
dialog.value.width = custom.width;
|
dialog.value.width = custom.width;
|
||||||
dialog.value.title = custom.title;
|
dialog.value.title = custom.title;
|
||||||
|
|
@ -206,7 +211,7 @@ function handleDelete(obj, row) {
|
||||||
}
|
}
|
||||||
const ids: any[] = [];
|
const ids: any[] = [];
|
||||||
row.forEach(it => {
|
row.forEach(it => {
|
||||||
ids.push(it.Id);
|
ids.push(it.id);
|
||||||
});
|
});
|
||||||
ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?").then(() => {
|
ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?").then(() => {
|
||||||
Api.delete(ids).then(res => {
|
Api.delete(ids).then(res => {
|
||||||
|
|
@ -309,12 +314,16 @@ async function fetchInitData() {
|
||||||
element.type === "string" ||
|
element.type === "string" ||
|
||||||
element.type === undefined)
|
element.type === undefined)
|
||||||
) {
|
) {
|
||||||
element.custom = row => {
|
if (element.type === "string" || element.type === undefined)
|
||||||
let sc = element.setting.datasource.find(
|
element.custom = row => row[key];
|
||||||
s => s[element.setting.mapValue] + "" == row[key] + ""
|
else {
|
||||||
);
|
element.custom = row => {
|
||||||
return !sc ? row[key] : sc[element.setting.maplabel];
|
let sc = element.setting.datasource.find(
|
||||||
};
|
s => s[element.setting.mapValue] + "" == row[key] + ""
|
||||||
|
);
|
||||||
|
return !sc ? row[key] : sc[element.setting.maplabel];
|
||||||
|
};
|
||||||
|
}
|
||||||
} else if (element.custom == undefined) {
|
} else if (element.custom == undefined) {
|
||||||
element.custom = row => row[key];
|
element.custom = row => row[key];
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +379,7 @@ function fetchPagedData() {
|
||||||
>
|
>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-if="o.type.trim() == 'datetime'"
|
v-if="o.type.trim() == 'datetime'"
|
||||||
v-model="o.value"
|
v-model="o.value as Date"
|
||||||
format="yyyy-MM-dd"
|
format="yyyy-MM-dd"
|
||||||
value-format="yyyy-MM-dd"
|
value-format="yyyy-MM-dd"
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -417,6 +426,39 @@ function fetchPagedData() {
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
<div class="dialog-container">
|
||||||
|
<el-dialog
|
||||||
|
v-if="dialog.visible"
|
||||||
|
v-model="dialog.visible"
|
||||||
|
:class="dialog.title ? '' : 'noHeader'"
|
||||||
|
:title="dialog.title"
|
||||||
|
:width="dialog.width"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="dialog.close"
|
||||||
|
:before-close="tableClose"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
|
<hTableEdit
|
||||||
|
v-if="dialog.edit.visible"
|
||||||
|
:id="dialog.edit.id"
|
||||||
|
:tableData="table"
|
||||||
|
:row="dialog.edit.row"
|
||||||
|
:tagData="dialog.edit.tagData"
|
||||||
|
@handlePagedCallback="handleAddCallback"
|
||||||
|
/>
|
||||||
|
<component
|
||||||
|
:is="dialog.custom.component"
|
||||||
|
v-if="dialog.custom.visible"
|
||||||
|
:style="{ height: 'calc( ' + dialog.custom.height + ' - 84px )' }"
|
||||||
|
:iscomponent="true"
|
||||||
|
:custom="dialog.custom.custom"
|
||||||
|
:CancelCallback="handleAddCallback"
|
||||||
|
:data="dialog.custom.data"
|
||||||
|
@handlePagedCallback="handleAddCallback"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="table.operationTop" class="toolbar-container">
|
<div v-if="table.operationTop" class="toolbar-container">
|
||||||
|
|
@ -427,7 +469,8 @@ function fetchPagedData() {
|
||||||
:key="i"
|
:key="i"
|
||||||
:type="e.btnStyle || 'info'"
|
:type="e.btnStyle || 'info'"
|
||||||
@click="getbtnClick(e, null)"
|
@click="getbtnClick(e, null)"
|
||||||
>{{ e.label }}</el-button>
|
>{{ e.label }}</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
v-if="init"
|
v-if="init"
|
||||||
|
|
@ -467,8 +510,7 @@ function fetchPagedData() {
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="(item, name, i) of table.column"
|
v-for="(item, name, i) of tableShowColumn"
|
||||||
v-show="item.show"
|
|
||||||
:key="i"
|
:key="i"
|
||||||
:prop="name"
|
:prop="name"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
|
|
@ -480,12 +522,6 @@ function fetchPagedData() {
|
||||||
<div v-if="item.type.trim() == 'math'">
|
<div v-if="item.type.trim() == 'math'">
|
||||||
{{ item.custom(scope.row) }}
|
{{ item.custom(scope.row) }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <ShowMathJax
|
|
||||||
v-if="item.type.trim() == 'math'"
|
|
||||||
style="zoom: 0.8"
|
|
||||||
:str="item.custom(scope.row)"
|
|
||||||
:divId="'MathJax_' + scope.row.Id"
|
|
||||||
/> -->
|
|
||||||
<el-image
|
<el-image
|
||||||
v-else-if="item.type.trim() == 'img'"
|
v-else-if="item.type.trim() == 'img'"
|
||||||
style="width: 300px; height: 100px"
|
style="width: 300px; height: 100px"
|
||||||
|
|
@ -513,7 +549,6 @@ function fetchPagedData() {
|
||||||
{{ item.custom(scope.row) }}
|
{{ item.custom(scope.row) }}
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- <p ></p> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -529,41 +564,6 @@ function fetchPagedData() {
|
||||||
@current-change="pageIndexChange"
|
@current-change="pageIndexChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-container">
|
|
||||||
<el-dialog
|
|
||||||
v-if="dialog.visible"
|
|
||||||
ref="elDialog"
|
|
||||||
v-model:visible="dialog.visible"
|
|
||||||
:class="dialog.title ? '' : 'noHeader'"
|
|
||||||
:title="dialog.title"
|
|
||||||
:width="dialog.width"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="dialog.close"
|
|
||||||
:before-close="tableClose"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<hTableEdit
|
|
||||||
v-if="dialog.edit.visible"
|
|
||||||
:id="dialog.edit.id"
|
|
||||||
:data="table"
|
|
||||||
:tagData="dialog.edit.tagData"
|
|
||||||
:row="dialog.edit.row"
|
|
||||||
@handlePagedCallback="handleAddCallback"
|
|
||||||
/>
|
|
||||||
/>
|
|
||||||
<component
|
|
||||||
:is="dialog.custom.component"
|
|
||||||
v-if="dialog.custom.visible"
|
|
||||||
ref="custom"
|
|
||||||
:style="{ height: 'calc( ' + dialog.custom.height + ' - 84px )' }"
|
|
||||||
:iscomponent="true"
|
|
||||||
:custom="dialog.custom.custom"
|
|
||||||
:CancelCallback="handleAddCallback"
|
|
||||||
:data="dialog.custom.data"
|
|
||||||
@handlePagedCallback="handleAddCallback"
|
|
||||||
/>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,6 @@ export default {
|
||||||
title: "学校",
|
title: "学校",
|
||||||
showLink: true
|
showLink: true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/menu",
|
|
||||||
name: "Menu",
|
|
||||||
component: () => import("@/views/menu/index.vue"),
|
|
||||||
meta: {
|
|
||||||
title: "菜单",
|
|
||||||
showLink: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
} satisfies RouteConfigsTable;
|
} satisfies RouteConfigsTable;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ahTable from "@/components/hTable/index.vue";
|
||||||
|
import { TableConfig } from "@/components/hTable/hTable";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
|
import { hTableAPI } from "@/api/hTable";
|
||||||
|
const ControllerName = "Admin";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: ControllerName
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchCallback(data) {
|
||||||
|
// let c = data.Conditions.find(s => s.FieldName === "Enable");
|
||||||
|
// if (c) {
|
||||||
|
// if (c.FieldValue == "true") {
|
||||||
|
// c.FieldValue = 1;
|
||||||
|
// } else {
|
||||||
|
// c.FieldValue = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
const RoleApi = new hTableAPI("AdminRole");
|
||||||
|
const table = ref<{ initTable: (config: TableConfig) => void }>(null);
|
||||||
|
const tableData: TableConfig = {
|
||||||
|
apiUrl: ControllerName,
|
||||||
|
selectColumn: false, // 列表选择
|
||||||
|
border: false, // 是否显示表格边框
|
||||||
|
searchCallback: searchCallback,
|
||||||
|
search: {
|
||||||
|
// 查询条件
|
||||||
|
show: true,
|
||||||
|
PageIndex: 0,
|
||||||
|
PageSize: 20,
|
||||||
|
OrderBy: "CreateTime", // 排序
|
||||||
|
defaultConditions: [], // 默认查询条件
|
||||||
|
Conditions: []
|
||||||
|
},
|
||||||
|
operationColumn: true, // 显示操作按钮
|
||||||
|
operationColumnData: [
|
||||||
|
{
|
||||||
|
// 操作按钮
|
||||||
|
topBtn: false, // 是头部按钮
|
||||||
|
label: "修改",
|
||||||
|
btnType: "edit" // 按钮类型 add edit del custom
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 操作按钮
|
||||||
|
topBtn: true, // 是头部按钮
|
||||||
|
label: "添加",
|
||||||
|
btnStyle: "success",
|
||||||
|
btnType: "add" // 按钮类型 add edit del custom
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topBtn: false, // 头部按钮
|
||||||
|
show: true,
|
||||||
|
label: "删除",
|
||||||
|
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||||
|
btnStyle: "danger" // topBtn: true才生效 success danger
|
||||||
|
}
|
||||||
|
],
|
||||||
|
column: {
|
||||||
|
// 行数据
|
||||||
|
id: {
|
||||||
|
label: "编号",
|
||||||
|
search: true,
|
||||||
|
add: false, // 字段允许添加
|
||||||
|
edit: false, // 字段允许修改
|
||||||
|
width: "150px"
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
label: "名称",
|
||||||
|
width: "180px",
|
||||||
|
search: true,
|
||||||
|
searchType: "Like",
|
||||||
|
add: true, // 字段允许添加
|
||||||
|
edit: true // 字段允许修改
|
||||||
|
},
|
||||||
|
Phone: {
|
||||||
|
label: "手机号",
|
||||||
|
width: "200px",
|
||||||
|
search: true,
|
||||||
|
add: true, // 字段允许添加
|
||||||
|
edit: true // 字段允许修改
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
label: "账号",
|
||||||
|
search: true,
|
||||||
|
add: true, // 字段允许添加
|
||||||
|
edit: false // 字段允许修改
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
label: "密码",
|
||||||
|
show: false,
|
||||||
|
search: false,
|
||||||
|
add: true, // 字段允许添加
|
||||||
|
edit: false // 字段允许修改
|
||||||
|
},
|
||||||
|
enable: {
|
||||||
|
label: "启用",
|
||||||
|
type: "switch",
|
||||||
|
search: false,
|
||||||
|
add: false, // 字段允许添加
|
||||||
|
edit: true, // 字段允许修改
|
||||||
|
valueE: true // 编辑时的默认值
|
||||||
|
},
|
||||||
|
roleId: {
|
||||||
|
label: "角色",
|
||||||
|
type: "dropdown",
|
||||||
|
search: true,
|
||||||
|
add: true, // 字段允许添加
|
||||||
|
edit: false, // 字段允许修改
|
||||||
|
setting: {
|
||||||
|
datasource: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [],
|
||||||
|
pageData: {
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
|
selectRows: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const showTable = ref(false);
|
||||||
|
onMounted(async () => {
|
||||||
|
//初始化数据原
|
||||||
|
tableData.column.roleId.setting.datasource = (
|
||||||
|
await RoleApi.querycombo({ TextName: "Name", ValueName: "Id" })
|
||||||
|
).data;
|
||||||
|
|
||||||
|
showTable.value = true;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,371 @@
|
||||||
|
<template>
|
||||||
|
<div class="menu-edit-container">
|
||||||
|
<el-form
|
||||||
|
ref="menuFormRef"
|
||||||
|
:model="menuForm"
|
||||||
|
:rules="formRules"
|
||||||
|
label-position="top"
|
||||||
|
class="menu-form"
|
||||||
|
>
|
||||||
|
<el-row :gutter="30">
|
||||||
|
<!-- 左侧表单区域 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="路由名称" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="menuForm.name"
|
||||||
|
placeholder="请输入路由唯一名称"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="菜单标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="menuForm.title"
|
||||||
|
placeholder="请输入菜单标题"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="路由路径" prop="path">
|
||||||
|
<el-input
|
||||||
|
v-model="menuForm.path"
|
||||||
|
placeholder="请输入路由路径,如 /dashboard"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<div class="form-tip">如果是按钮权限,可留空</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="图标" prop="icon">
|
||||||
|
<el-input
|
||||||
|
v-model="menuForm.icon"
|
||||||
|
placeholder="请输入图标类名,如 el-icon-menu"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
<div v-if="menuForm.icon" class="icon-preview">
|
||||||
|
<i
|
||||||
|
:class="menuForm.icon"
|
||||||
|
style="font-size: 24px; margin-top: 8px"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="授权码" prop="auths">
|
||||||
|
<el-input
|
||||||
|
v-model="menuForm.auths"
|
||||||
|
placeholder="请输入授权码,多个用逗号分隔"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<div class="form-tip">按钮权限需要的授权码</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 右侧表单区域 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="父级菜单" prop="parentId">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="menuForm.parentId"
|
||||||
|
:data="menuTreeData"
|
||||||
|
:props="treeProps"
|
||||||
|
check-strictly
|
||||||
|
placeholder="请选择父级菜单"
|
||||||
|
clearable
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:render-after-expand="false"
|
||||||
|
:default-expand-all="true"
|
||||||
|
:highlight-current="true"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="排序排名" prop="rank">
|
||||||
|
<el-input-number
|
||||||
|
v-model="menuForm.rank"
|
||||||
|
:min="0"
|
||||||
|
:max="100"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<div class="form-tip">数值越小排名越靠前</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="菜单类型">
|
||||||
|
<el-switch
|
||||||
|
v-model="menuForm.isButton"
|
||||||
|
active-text="按钮权限"
|
||||||
|
inactive-text="常规菜单"
|
||||||
|
style="
|
||||||
|
--el-switch-on-color: #13ce66;
|
||||||
|
--el-switch-off-color: #409eff;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="显示状态">
|
||||||
|
<el-switch
|
||||||
|
v-model="menuForm.showLink"
|
||||||
|
active-text="显示"
|
||||||
|
inactive-text="隐藏"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div v-if="menuForm.isButton" class="button-permission-info">
|
||||||
|
<el-alert title="按钮权限说明" type="info" :closable="false">
|
||||||
|
<p>1. 按钮权限不会显示在导航菜单中</p>
|
||||||
|
<p>2. 需要填写授权码用于权限控制</p>
|
||||||
|
<p>3. 路由路径可留空</p>
|
||||||
|
</el-alert>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-divider />
|
||||||
|
<div class="header">
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button @click="resetForm">重置</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm" :loading="submitting">
|
||||||
|
{{ isEditMode ? "更新菜单" : "创建菜单" }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { defineComponent, ref, reactive, onMounted, onBeforeMount } from "vue";
|
||||||
|
import { MenuItem, Edit } from "@/api/menu";
|
||||||
|
import {
|
||||||
|
ElMessage,
|
||||||
|
ElMessageBox,
|
||||||
|
FormInstance,
|
||||||
|
FormValidateCallback
|
||||||
|
} from "element-plus";
|
||||||
|
import propTypes from "@/utils/propTypes";
|
||||||
|
defineOptions({
|
||||||
|
name: "MenuEdit"
|
||||||
|
});
|
||||||
|
const props = defineProps({
|
||||||
|
treeData: {
|
||||||
|
type: Object as PropType<MenuItem[]>
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<MenuItem>,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["callbackFun"]);
|
||||||
|
const menuFormRef = ref<FormInstance>();
|
||||||
|
const menuForm = reactive<MenuItem>({
|
||||||
|
name: "",
|
||||||
|
path: "",
|
||||||
|
isButton: false,
|
||||||
|
title: "",
|
||||||
|
icon: "",
|
||||||
|
auths: "",
|
||||||
|
rank: 50,
|
||||||
|
showLink: true,
|
||||||
|
parentId: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const menuTreeData = ref<MenuItem[]>(props.treeData);
|
||||||
|
|
||||||
|
const treeProps = {
|
||||||
|
value: "id",
|
||||||
|
label: "title",
|
||||||
|
children: "children"
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEditMode = ref(false);
|
||||||
|
const submitting = ref(false);
|
||||||
|
const iconDialogVisible = ref(false);
|
||||||
|
|
||||||
|
// 模拟一些常用图标
|
||||||
|
const icons = ref([
|
||||||
|
"el-icon-menu",
|
||||||
|
"el-icon-setting",
|
||||||
|
"el-icon-user",
|
||||||
|
"el-icon-s-home",
|
||||||
|
"el-icon-s-data",
|
||||||
|
"el-icon-s-check",
|
||||||
|
"el-icon-s-opportunity",
|
||||||
|
"el-icon-s-order",
|
||||||
|
"el-icon-s-platform",
|
||||||
|
"el-icon-s-promotion",
|
||||||
|
"el-icon-s-shop",
|
||||||
|
"el-icon-s-marketing",
|
||||||
|
"el-icon-s-flag",
|
||||||
|
"el-icon-s-comment",
|
||||||
|
"el-icon-s-finance"
|
||||||
|
]);
|
||||||
|
|
||||||
|
const formRules = {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: "请输入菜单名称", trigger: "blur" },
|
||||||
|
{ min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
|
||||||
|
],
|
||||||
|
title: [
|
||||||
|
{ required: true, message: "请输入菜单标题", trigger: "blur" },
|
||||||
|
{ min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
|
||||||
|
],
|
||||||
|
path: [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: string, callback: any) => {
|
||||||
|
if (!menuForm.isButton && !value) {
|
||||||
|
callback(new Error("常规菜单必须填写路由路径"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "blur"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
auths: [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: string, callback: any) => {
|
||||||
|
if (menuForm.isButton && !value) {
|
||||||
|
callback(new Error("按钮权限必须填写授权码"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "blur"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rank: [{ required: true, message: "请输入排序值", trigger: "blur" }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
onMounted(() => {
|
||||||
|
Object.assign(menuForm, props.info);
|
||||||
|
if (props.info != null && props.info.id > 0) {
|
||||||
|
isEditMode.value = true;
|
||||||
|
} else menuForm.id = 0;
|
||||||
|
});
|
||||||
|
const submitForm = () => {
|
||||||
|
menuFormRef.value?.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
submitting.value = true;
|
||||||
|
Edit(menuForm).then(res => {
|
||||||
|
submitting.value = false;
|
||||||
|
ElMessage.success(
|
||||||
|
isEditMode.value ? "菜单更新成功!" : "菜单创建成功!"
|
||||||
|
);
|
||||||
|
goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.warning("请正确填写表单内容");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const resetForm = () => {
|
||||||
|
ElMessageBox.confirm("确定要重置表单内容吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
menuFormRef.value?.resetFields();
|
||||||
|
if (!isEditMode.value) {
|
||||||
|
Object.assign(menuForm, {
|
||||||
|
isButton: false,
|
||||||
|
showLink: true,
|
||||||
|
rank: 50,
|
||||||
|
parentId: menuForm.parentId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 返回菜单列表
|
||||||
|
const goBack = () => emit("callbackFun"); // 传参给父组件;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.menu-edit-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 24px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-form {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-permission-info {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f4f4f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
gap: 15px;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 10px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item:hover {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item.selected {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
border-color: #409eff;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item i {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-name {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-alert p {
|
||||||
|
margin: 5px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div style="padding-bottom: 5px;">
|
<div style="padding-bottom: 5px">
|
||||||
|
<el-button type="success" @click="() => showDialog(null)">
|
||||||
|
新增根菜单
|
||||||
|
</el-button>
|
||||||
<el-button type="primary"> 分配权限 </el-button>
|
<el-button type="primary"> 分配权限 </el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-tree
|
<el-tree
|
||||||
|
|
@ -9,6 +12,7 @@
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:default-expand-all="true"
|
:default-expand-all="true"
|
||||||
:highlight-current="true"
|
:highlight-current="true"
|
||||||
|
:expand-on-click-node="false"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
class="menu-tree"
|
class="menu-tree"
|
||||||
>
|
>
|
||||||
|
|
@ -16,82 +20,75 @@
|
||||||
<div class="menu-node">
|
<div class="menu-node">
|
||||||
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
||||||
<span class="menu-title">{{ data.title }}</span>
|
<span class="menu-title">{{ data.title }}</span>
|
||||||
|
<span class="menu-path-Rank" v-if="data.rank"
|
||||||
|
>排序[{{ data.rank }}]</span
|
||||||
|
>
|
||||||
<span class="menu-path" v-if="data.path">{{ data.path }}</span>
|
<span class="menu-path" v-if="data.path">{{ data.path }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; gap: 6px">
|
<div style="display: flex; gap: 6px">
|
||||||
<el-button type="success" link @click="() => {}"> 添加 </el-button>
|
<el-button
|
||||||
<el-button type="primary" link @click="() => {}"> 编辑 </el-button>
|
type="success"
|
||||||
|
link
|
||||||
|
@click="() => showDialog({ parentId: data.id } as MenuItem)"
|
||||||
|
>
|
||||||
|
添加
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" link @click="() => showDialog(data)">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
<el-button type="danger" link @click="() => {}"> 删除 </el-button>
|
<el-button type="danger" link @click="() => {}"> 删除 </el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
|
<el-dialog
|
||||||
|
v-if="dialogData.visible"
|
||||||
|
v-model="dialogData.visible"
|
||||||
|
title="菜单编辑"
|
||||||
|
width="800"
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<MenuEdit
|
||||||
|
@callbackFun="EditCallback"
|
||||||
|
:info="dialogData.info"
|
||||||
|
:treeData="treeData"
|
||||||
|
></MenuEdit>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MenuAll, MenuItem } from "@/api/menu";
|
import { MenuAll, MenuItem } from "@/api/menu";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
|
import MenuEdit from "./edit.vue";
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "Menu"
|
name: "Menu"
|
||||||
});
|
});
|
||||||
|
|
||||||
// 模拟从API获取的菜单数据
|
/** 显示弹窗 */
|
||||||
const mockMenuData: MenuItem[] = [
|
const dialogData = ref({
|
||||||
{
|
visible: false,
|
||||||
id: 1,
|
info: null
|
||||||
name: "dashboard",
|
});
|
||||||
path: "/dashboard",
|
function showDialog(info: MenuItem) {
|
||||||
isButton: false,
|
dialogData.value.visible = true;
|
||||||
title: "控制台",
|
dialogData.value.info = info;
|
||||||
icon: "el-icon-monitor",
|
}
|
||||||
rank: 1,
|
async function EditCallback(info: MenuItem) {
|
||||||
showLink: true,
|
await fetchInitData();
|
||||||
parentId: 0
|
dialogData.value.visible = false;
|
||||||
},
|
}
|
||||||
{
|
const handleClose = (done: () => void) => {
|
||||||
id: 2,
|
done();
|
||||||
name: "system",
|
// ElMessageBox.confirm("确定要关闭对话框?")
|
||||||
path: "/system",
|
// .then(() => {
|
||||||
isButton: false,
|
// done();
|
||||||
title: "系统管理",
|
// })
|
||||||
icon: "el-icon-setting",
|
// .catch(() => {
|
||||||
rank: 2,
|
// // catch error
|
||||||
showLink: true,
|
// });
|
||||||
parentId: 0
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "user",
|
|
||||||
path: "/system/user",
|
|
||||||
isButton: false,
|
|
||||||
title: "用户管理",
|
|
||||||
icon: "el-icon-user",
|
|
||||||
rank: 1,
|
|
||||||
showLink: true,
|
|
||||||
parentId: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "role",
|
|
||||||
path: "/system/role",
|
|
||||||
isButton: false,
|
|
||||||
title: "角色管理",
|
|
||||||
icon: "el-icon-s-custom",
|
|
||||||
rank: 2,
|
|
||||||
showLink: true,
|
|
||||||
parentId: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "createUser",
|
|
||||||
isButton: true,
|
|
||||||
title: "创建用户",
|
|
||||||
rank: 1,
|
|
||||||
showLink: true,
|
|
||||||
parentId: 3
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 将扁平数据转换为树形结构
|
// 将扁平数据转换为树形结构
|
||||||
const convertToTree = (menus: MenuItem[]): MenuItem[] => {
|
const convertToTree = (menus: MenuItem[]): MenuItem[] => {
|
||||||
|
|
@ -137,26 +134,16 @@ const treeProps = {
|
||||||
label: "title",
|
label: "title",
|
||||||
children: "children"
|
children: "children"
|
||||||
};
|
};
|
||||||
|
async function fetchInitData() {
|
||||||
// 模拟API请求
|
|
||||||
const fetchMenuData = async (): Promise<MenuItem[]> => {
|
|
||||||
// 实际项目中替换为API调用:
|
|
||||||
// const response = await fetch('/api/menus')
|
|
||||||
// return await response.json()
|
|
||||||
|
|
||||||
// 这里使用模拟数据
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => resolve(mockMenuData), 300);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const flatData = await MenuAll();
|
const flatData = await MenuAll();
|
||||||
if (flatData.code === 200) {
|
if (flatData.code === 200) {
|
||||||
treeData.value = convertToTree(flatData.data);
|
treeData.value = convertToTree(flatData.data);
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(flatData.message);
|
ElMessage.error(flatData.message);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await fetchInitData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -185,11 +172,16 @@ onMounted(async () => {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-path-Rank {
|
||||||
|
font-size: 13px;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
.menu-path {
|
.menu-path {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
flex-grow: 1;
|
flex-grow: 0;
|
||||||
}
|
}
|
||||||
.menu-tree {
|
.menu-tree {
|
||||||
padding: 20px; /* 增加内边距 */
|
padding: 20px; /* 增加内边距 */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form
|
||||||
|
ref="schoolAddForm"
|
||||||
|
:model="eData.form"
|
||||||
|
:label-width="eData.formLabelWidth"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="学校名称:"
|
||||||
|
prop="Name"
|
||||||
|
:rules="eData.rules.Required"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
@change="inputChange"
|
||||||
|
type="text"
|
||||||
|
v-model="eData.form.Name"
|
||||||
|
autocomplete="off"
|
||||||
|
maxlength="20"
|
||||||
|
:show-word-limit="true"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="地区" :rules="eData.rules.Required" prop="pname">
|
||||||
|
<el-col :span="24">
|
||||||
|
<div style="display: flex; gap: 10px">
|
||||||
|
<el-select
|
||||||
|
v-model="eData.form.pid"
|
||||||
|
clearable
|
||||||
|
@change="v => selectChange(v, 1)"
|
||||||
|
filterable
|
||||||
|
placeholder="省份"
|
||||||
|
style="width: 180px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in eData.LocaArr1"
|
||||||
|
:key="item.id"
|
||||||
|
autocomplete="off"
|
||||||
|
:label="item.Text"
|
||||||
|
:value="item.Value"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-select
|
||||||
|
v-model="eData.form.cid"
|
||||||
|
clearable
|
||||||
|
@change="v => selectChange(v, 2)"
|
||||||
|
filterable
|
||||||
|
placeholder="市"
|
||||||
|
style="width: 180px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in eData.LocaArr2"
|
||||||
|
:key="item.id"
|
||||||
|
autocomplete="off"
|
||||||
|
:label="item.Text"
|
||||||
|
:value="item.Value"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-select
|
||||||
|
v-model="eData.form.rid"
|
||||||
|
clearable
|
||||||
|
@change="v => selectChange(v, 3)"
|
||||||
|
filterable
|
||||||
|
placeholder="区"
|
||||||
|
style="width: 180px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in eData.LocaArr3"
|
||||||
|
:key="item.id"
|
||||||
|
autocomplete="off"
|
||||||
|
:label="item.Text"
|
||||||
|
:value="item.Value"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="启用:" prop="Enable">
|
||||||
|
<el-switch
|
||||||
|
v-model="eData.form.Enable"
|
||||||
|
active-text="启用"
|
||||||
|
inactive-text="禁用"
|
||||||
|
>
|
||||||
|
</el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<div style="padding-left: 4rem">
|
||||||
|
创建学校会生成一个默认管理员账号
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="eData.loading"
|
||||||
|
@click="handleSubmitForm()"
|
||||||
|
>立即提交</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="handleResetForm()">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getregion, getcity, getProvince, EditSchool } from "@/api/school";
|
||||||
|
import { ElMessage, FormInstance } from "element-plus";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
type: Object as PropType<any[]>,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const eData = ref({
|
||||||
|
LocaArr1: [],
|
||||||
|
LocaArr2: [],
|
||||||
|
LocaArr3: [],
|
||||||
|
rules: {
|
||||||
|
Required: {
|
||||||
|
required: true,
|
||||||
|
message: "必填项",
|
||||||
|
trigger: "blur"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formLabelWidth: "120px",
|
||||||
|
size: "small",
|
||||||
|
loading: false,
|
||||||
|
form: {
|
||||||
|
Name: "",
|
||||||
|
id: props.id,
|
||||||
|
pid: "",
|
||||||
|
cid: "",
|
||||||
|
rid: "",
|
||||||
|
pname: "",
|
||||||
|
cname: "",
|
||||||
|
rname: "",
|
||||||
|
Enable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
fetchInitData();
|
||||||
|
fetchFormData();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function selectChange(value, index) {
|
||||||
|
let nid = value;
|
||||||
|
let GetInfo = getcity;
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let loc = eData.value.LocaArr2;
|
||||||
|
if (index == 1) {
|
||||||
|
eData.value.form.pname =
|
||||||
|
value == "" ? "" : eData.value.LocaArr1.find(s => s.Value == value).Text;
|
||||||
|
eData.value.form.cname = "";
|
||||||
|
eData.value.form.rname = "";
|
||||||
|
eData.value.form.cid = "";
|
||||||
|
eData.value.form.rid = "";
|
||||||
|
} else if (index == 2) {
|
||||||
|
loc = eData.value.LocaArr3;
|
||||||
|
GetInfo = getregion;
|
||||||
|
eData.value.form.cname =
|
||||||
|
value == "" ? "" : eData.value.LocaArr2.find(s => s.Value == value).Text;
|
||||||
|
eData.value.form.rname = "";
|
||||||
|
eData.value.form.rid = "";
|
||||||
|
} else {
|
||||||
|
eData.value.form.rname =
|
||||||
|
value == "" ? "" : eData.value.LocaArr3.find(s => s.Value == value).Text;
|
||||||
|
}
|
||||||
|
if (value == "" && index == 3) return;
|
||||||
|
let nodes = (await GetInfo(nid)).data.map(item => ({
|
||||||
|
Value: item.rid || item.cid || item.pid,
|
||||||
|
Text: item.rname || item.cname || item.pname
|
||||||
|
}));
|
||||||
|
loc.splice(0, loc.length);
|
||||||
|
loc.push(...nodes);
|
||||||
|
}
|
||||||
|
async function inputChange() {
|
||||||
|
if (eData.value.form.pname == "") {
|
||||||
|
let p = eData.value.LocaArr1.find(s =>
|
||||||
|
eData.value.form.Name.includes(s.Text)
|
||||||
|
);
|
||||||
|
if (!p) return;
|
||||||
|
eData.value.form.pid = p.Value;
|
||||||
|
await selectChange(eData.value.form.pid, 1);
|
||||||
|
|
||||||
|
let p1 = eData.value.LocaArr2.find(s =>
|
||||||
|
eData.value.form.Name.includes(s.Text)
|
||||||
|
);
|
||||||
|
if (!p1) return;
|
||||||
|
eData.value.form.cid = p1.Value;
|
||||||
|
await selectChange(eData.value.form.cid, 2);
|
||||||
|
|
||||||
|
let p2 = eData.value.LocaArr3.find(s =>
|
||||||
|
eData.value.form.Name.includes(s.Text)
|
||||||
|
);
|
||||||
|
if (!p2) return;
|
||||||
|
eData.value.form.rid = p2.Value;
|
||||||
|
await selectChange(eData.value.form.rid, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits(["handlePagedCallback"]);
|
||||||
|
function handlePagedCallback() {
|
||||||
|
emit("handlePagedCallback");
|
||||||
|
}
|
||||||
|
const schoolAddForm = ref<FormInstance>();
|
||||||
|
function handleSubmitForm() {
|
||||||
|
schoolAddForm.value.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
eData.value.loading = true;
|
||||||
|
let ids = ["pid", "cid", "rid"];
|
||||||
|
for (const key of ids) {
|
||||||
|
eData.value.form[key] =
|
||||||
|
eData.value.form[key] == "" ? 0 : eData.value.form[key];
|
||||||
|
}
|
||||||
|
if (!(props.id !== -1)) {
|
||||||
|
eData.value.form.id = 0;
|
||||||
|
}
|
||||||
|
EditSchool(eData.value.form).then(res => {
|
||||||
|
eData.value.loading = false;
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
handlePagedCallback();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function handleResetForm() {}
|
||||||
|
async function fetchInitData() {
|
||||||
|
eData.value.LocaArr1 = (await getProvince()).data.map(item => ({
|
||||||
|
Value: item.rid || item.cid || item.pid,
|
||||||
|
Text: item.rname || item.cname || item.pname
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchFormData() {
|
||||||
|
handleResetForm();
|
||||||
|
if (props.id !== -1) {
|
||||||
|
eData.value.form = props.row[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import ahTable from "@/components/hTable/index.vue";
|
import ahTable from "@/components/hTable/index.vue";
|
||||||
import { TableConfig } from "@/components/hTable/hTable";
|
import { TableConfig } from "@/components/hTable/hTable";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "School"
|
name: "School"
|
||||||
});
|
});
|
||||||
|
|
@ -42,24 +43,17 @@ const tableData: TableConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
topBtn: true, // 头部按钮
|
topBtn: true, // 头部按钮
|
||||||
show: true,
|
label: "新增学校",
|
||||||
label: "新增",
|
btnType: "custom", // 按钮类型 add edit del custom
|
||||||
btnType: "add", // 按钮类型 add edit del custom
|
btnStyle: "success", // topBtn: true才生效 success danger
|
||||||
btnStyle: "success" // topBtn: true才生效 success danger
|
custom: {
|
||||||
|
// 按钮类型 custom 专用
|
||||||
|
title: "新增学校", // 弹出框title
|
||||||
|
src: "school/SchoolEdit", // 组件路径
|
||||||
|
width: "550px", // 弹框宽度
|
||||||
|
height: "300px" // 弹框高度
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// topBtn: true, // 头部按钮
|
|
||||||
// label: "新增学校",
|
|
||||||
// btnType: "custom", // 按钮类型 add edit del custom
|
|
||||||
// btnStyle: "success", // topBtn: true才生效 success danger
|
|
||||||
// custom: {
|
|
||||||
// // 按钮类型 custom 专用
|
|
||||||
// title: "新增学校", // 弹出框title
|
|
||||||
// src: "school/SchoolEdit", // 组件路径
|
|
||||||
// width: "550px", // 弹框宽度
|
|
||||||
// height: "300px" // 弹框高度
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
topBtn: false, // 头部按钮
|
topBtn: false, // 头部按钮
|
||||||
show: true,
|
show: true,
|
||||||
|
|
@ -73,8 +67,8 @@ const tableData: TableConfig = {
|
||||||
id: {
|
id: {
|
||||||
label: "编号",
|
label: "编号",
|
||||||
search: true,
|
search: true,
|
||||||
add: true, // 字段允许添加
|
add: false, // 字段允许添加
|
||||||
edit: true, // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
width: "150px"
|
width: "150px"
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue