staging #23

Merged
hy merged 38 commits from staging into master 2025-10-14 11:13:16 +08:00
6 changed files with 304 additions and 221 deletions
Showing only changes of commit 85a4ee0ef6 - Show all commits

View File

@ -93,13 +93,18 @@ export enum ConditionalType {
}
/** 字段设置项 */
export interface FieldSetting {
export class FieldSetting {
constructor() {
this.datasource = [];
this.mapValue= "value",
this.maplabel= "text"
}
/**map 时Value的取值的属性 */
mapValue?: string;
/**map 时label的取值的属性 */
maplabel?: string;
/** 数据源 请求方式 */
datasourceStr?: string;
/**
*
* @param value
@ -116,44 +121,152 @@ export interface ComboModel {
value: any;
text: string;
}
/** 表格列配置 */
export interface TableColumn {
/** 显示标签 */
label: string;
/** 是否可搜索 */
search: boolean;
/** 搜索类型 */
searchType?: ConditionalType;
/** 新增修改的配置 */
export class TableColumnEdit {
/**
*
* @param add
* @param edit
* @param multiple [type=dropdown]
* @param editShow
* @param editRows [type=textarea]
* @param rules
*/
constructor(
add: boolean = false,
edit: boolean = false,
multiple: boolean = false,
editShow: boolean = true,
editRows: number = 3,
editDefault: any = "",
rules: any | Array<any> = null,
change: () => void = null
) {
this.add = add;
this.edit = edit;
this.multiple = multiple;
this.editShow = editShow;
this.editRows = editRows;
this.editDefault = editDefault;
this.rules = rules;
this.change = change;
}
/** 是否允许添加 [false]*/
add?: boolean;
/** 是否允许修改 [false]*/
edit?: boolean;
/** 列宽度 [auto]*/
width?: string;
/** 字段类型 */
type?: "string" | "dropdown" | "switch" | "img" | "datetime" | "textarea";
/** 是否多选 */
/** [type=dropdown]是否多选 */
multiple?: boolean;
/** 编辑时显示列 */
editShow?: boolean;
/**校验规则 */
rules?: any | Array<any>;
/** 显示列 */
/** [type=textarea]编辑时的行数 */
editRows?: number;
/** 新增编辑时的缓存值 */
valueE?: Array<string> | string | number | boolean | Date;
/** 新增编辑时的默认 */
editDefault?: Array<string> | string | number | boolean | Date;
/**编辑时值发生变化 */
change?: () => void;
}
/** 查询的配置 */
export class TableColumnSearch {
/**
*
* @param yes
* @param sort
* @param searchType
*/
constructor(yes: boolean = false,
searchType: ConditionalType = ConditionalType.Like,sort: boolean = false,){
this.yes = yes;
this.sort = sort;
this.searchType = searchType;
}
/**可以查询 [false] */
yes?: boolean;
/** 可以排序 [false]*/
sort?: boolean;
/** 搜索类型 */
searchType?: ConditionalType;
/** 查询缓存值 */
value?: Array<string> | string | number | boolean | Date;
}
/** 表格列配置 */
export class TableColumn {
constructor(
) {
this.type = "string";
this.show = true;
this.search = new TableColumnSearch();
this.edit = new TableColumnEdit();
this.setting = {};
}
/** 显示标签 */
label: string;
/** 查询配置 */
search?: TableColumnSearch;
/** 编辑配置 */
edit?: TableColumnEdit;
/** Table中展示宽度 [auto]*/
width?: string;
/** 字段类型 */
type?: "string" | "dropdown" | "switch" | "img" | "datetime" | "textarea";
/** 显示列 [不会动态计算]*/
show?: boolean;
/** 字段设置 */
setting?: FieldSetting;
/** 修改时的编辑值 */
valueE?: Array<string> | string | number | boolean | Date;
/** 查询值 */
value?: Array<string> | string | number | boolean | Date;
/** textarea编辑时的行数 */
editRows?: number;
/**编辑时值发生变化 */
change?: () => void;
/**列值初始化时 如何获取默认取对应列*/
custom?: (row: any) => string;
}
/** 表格列配置 */
// export interface TableColumn {
// /** 显示标签 */
// label: string;
// /** 是否可搜索 */
// search: boolean;
// /** 搜索类型 */
// searchType?: ConditionalType;
// /** 是否允许添加 [false]*/
// add?: boolean;
// /** 是否允许修改 [false]*/
// edit?: boolean;
// /** Table中展示宽度 [auto]*/
// width?: string;
// /** 字段类型 */
// type?: "string" | "dropdown" | "switch" | "img" | "datetime" | "textarea";
// /** 是否多选 */
// multiple?: boolean;
// /** 编辑时显示列 */
// editShow?: boolean;
// /**校验规则 */
// rules?: any | Array<any>;
// /** 显示列 */
// show?: boolean;
// /** 字段设置 */
// setting?: FieldSetting;
// /** 修改时的编辑值 */
// valueE?: Array<string> | string | number | boolean | Date;
// /** 查询值 */
// value?: Array<string> | string | number | boolean | Date;
// /** textarea编辑时的行数 */
// editRows?: number;
// /**编辑时值发生变化 */
// change?: () => void;
// /**列值初始化时 如何获取默认取对应列*/
// custom?: (row: any) => string;
// }
/** 分页数据 */
export interface PageData {
/** 总条数 */
@ -224,3 +337,49 @@ export interface TableConfig {
/**是否显示 */
show?: boolean;
}
/** 初始化表格数据 */
export function intTableData(tValue: TableConfig): TableConfig {
if (!tValue.data) tValue.data = [];
if (!tValue.selectRows) tValue.selectRows = [];
if (tValue.border == null) tValue.border = true;
if (!tValue.pageData) tValue.pageData = { total: 0 };
if (tValue.operationTop === undefined) tValue.operationTop = true;
// 处理 column 的属性
for (const key in tValue.column) {
tValue.column[key] = { ...new TableColumn(), ...tValue.column[key] };
const element = tValue.column[key];
element.edit = { ...new TableColumnEdit(), ...element.edit };
element.search = { ...new TableColumnSearch(), ...element.search };
element.setting = { ...new FieldSetting(), ...element.setting };
if (
element.custom == undefined &&
(element.type === "switch" ||
element.type === "dropdown" ||
element.type === "string" ||
element.type === undefined)
) {
if (element.type === "string" || element.type === undefined)
element.custom = row => row[key];
else {
element.custom = row => {
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) {
element.custom = row => row[key];
}
}
// 处理 operationColumnData 的属性
for (const key in tValue.operationColumnData) {
const element = tValue.operationColumnData[key];
if (element.show === undefined) element.show = true;
}
return tValue;
}

View File

@ -55,11 +55,11 @@ function intiColumn() {
for (const key in editData.value.table.column) {
const element = editData.value.table.column[key];
if (editData.value.isedit) {
if (element.edit) {
if (element.edit.edit) {
column.value[key] = element;
}
} else {
if (element.add) {
if (element.edit.add) {
column.value[key] = element;
}
}
@ -81,8 +81,8 @@ function handleSubmitForm() {
} else form.id = 0;
for (const key in column.value) {
const element = column.value[key];
if (element.valueE !== null && element.valueE !== "") {
form[key] = element.valueE;
if (element.edit.valueE !== null && element.edit.valueE !== "") {
form[key] = element.edit.valueE;
}
}
if (editData.value.table.editCallback) {
@ -102,14 +102,15 @@ function handleSubmitForm() {
function handleResetForm() {
for (const key in column.value) {
let item = column.value[key];
if (Array.isArray(item.valueE)) {
item.valueE = [];
} else if (typeof item.valueE === "number") {
item.valueE = "";
} else if (typeof item.valueE === "boolean") {
item.valueE = false;
if (item.edit.editDefault != null) item.edit.valueE = item.edit.editDefault;
else if (Array.isArray(item.edit.valueE)) {
item.edit.valueE = [];
} else if (typeof item.edit.valueE === "number") {
item.edit.valueE = "";
} else if (typeof item.edit.valueE === "boolean") {
item.edit.valueE = false;
} else {
item.valueE = "";
item.edit.valueE = "";
}
}
}
@ -123,7 +124,7 @@ function fetchFormData() {
editData.value.frorm = res.data;
for (const key in column.value) {
const element = column.value[key];
element.valueE = res.data[key];
element.edit.valueE = res.data[key];
}
}
editData.value.loading = true;
@ -145,32 +146,32 @@ function fetchFormData() {
>
<el-form-item
v-for="(o, k, i) in column"
v-show="execute(o['editShow'], o)"
v-show="execute(o.edit['editShow'], o)"
:key="i"
:rules="o.rules"
:prop="'' + k + '.valueE'"
:rules="o.edit.rules"
:prop="'' + k + '.edit.valueE'"
:label="o.label"
>
<div v-if="o.type.trim() == 'datetime'">
<el-date-picker
v-model="o.valueE as Date"
v-model="o.edit.valueE as Date"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:placeholder="o.label"
class="elWidth"
@change="o.change"
@change="o.edit.change"
/>
</div>
<div v-else-if="o.type.trim() == 'dropdown'">
<el-select
v-model="o.valueE"
:multiple="o.multiple"
v-model="o.edit.valueE"
:multiple="o.edit.multiple"
clearable
filterable
:placeholder="o.label"
class="elWidth"
@change="o.change"
@change="o.edit.change"
>
<el-option
v-for="item in o.setting.datasource"
@ -183,25 +184,29 @@ function fetchFormData() {
</div>
<div v-else-if="o.type.trim() == 'textarea'">
<el-input
v-model="o.valueE as string"
:rows="o.editRows || 4"
v-model="o.edit.valueE as string"
:rows="o.edit.editRows || 4"
type="textarea"
:placeholder="o.label"
class="elWidth"
@change="o.change"
@change="o.edit.change"
/>
</div>
<div v-else-if="o.type.trim() == 'switch'">
<el-switch
v-model="o.valueE as boolean"
v-model="o.edit.valueE as boolean"
active-text="启用"
inactive-text="禁用"
class="elWidth"
@change="o.change"
@change="o.edit.change"
/>
</div>
<div v-else>
<el-input v-model="o.valueE as string" class="elWidth" :placeholder="o.label" />
<el-input
v-model="o.edit.valueE as string"
class="elWidth"
:placeholder="o.label"
/>
</div>
</el-form-item>

View File

@ -21,7 +21,10 @@ import {
ButtonCustomConfig,
ConditionalType,
Dialog,
intTableData,
TableColumn,
TableColumnEdit,
TableColumnSearch,
TableConfig,
} from "./hTable";
import hTableEdit from "./hTableEdit.vue";
@ -107,36 +110,7 @@ function appStyle() {
}
function intdata() {
if (!table.value.data) table.value.data = [];
if (!table.value.selectRows) table.value.selectRows = [];
if (table.value.border == null) table.value.border = true;
if (!table.value.pageData) table.value.pageData = { total: 0 };
if (table.value.operationTop === undefined) table.value.operationTop = true;
// column
for (const key in table.value.column) {
const element = table.value.column[key];
if (element.add === undefined) element.add = false;
if (element.edit === undefined) element.edit = false;
// Vue 3 $set
if (element.valueE === undefined) element.valueE = element.multiple ? [] : "";
if (element.value === undefined) element.value = element.multiple ? [] : "";
if (!element.type) element.type = "string";
if (element.show === undefined) element.show = true;
if (element.editShow === undefined) element.editShow = true;
if (!element.setting)
element.setting = { datasource: [], mapValue: "value", maplabel: "text" };
if (!element.setting.mapValue) element.setting.mapValue = "value";
if (!element.setting.maplabel) element.setting.maplabel = "text";
if (!element.change) element.change = () => {};
}
// operationColumnData
for (const key in table.value.operationColumnData) {
const element = table.value.operationColumnData[key];
if (element.show === undefined) element.show = true;
}
intTableData(table.value);
}
function rowKeyFun(row) {
@ -256,13 +230,13 @@ function handleAddCallback() {
function handleResetForm() {
for (const key in table.value.column) {
let item = table.value.column[key];
if (Array.isArray(item.valueE)) {
item.valueE = [];
} else if (typeof item.valueE === "number") {
item.valueE = "";
} else if (typeof item.valueE === "boolean") {
if (Array.isArray(item.edit.valueE)) {
item.edit.valueE = [];
} else if (typeof item.edit.valueE === "number") {
item.edit.valueE = "";
} else if (typeof item.edit.valueE === "boolean") {
} else {
item.valueE = "";
item.edit.valueE = "";
}
}
}
@ -287,13 +261,13 @@ function searchReload() {
for (let name in table.value.column) {
if (
!table.value.column[name].search ||
table.value.column[name].value === undefined ||
table.value.column[name].value === null ||
table.value.column[name].value === ""
table.value.column[name].search.value === undefined ||
table.value.column[name].search.value === null ||
table.value.column[name].search.value === ""
) {
continue;
}
table.value.column[name].value = "";
table.value.column[name].search.value = "";
}
}
//
@ -306,9 +280,9 @@ function handleReloadPaged(reload = true) {
for (let name in table.value.column) {
if (
!table.value.column[name].search ||
table.value.column[name].value === undefined ||
table.value.column[name].value === null ||
table.value.column[name].value === ""
table.value.column[name].search.value === undefined ||
table.value.column[name].search.value === null ||
table.value.column[name].search.value === ""
) {
continue;
}
@ -323,10 +297,10 @@ function handleReloadPaged(reload = true) {
} else data.ConditionalType = ConditionalType.Equal;
data.FieldName = name.charAt(0).toUpperCase() + name.slice(1);
data.FieldValue = table.value.column[name].value.toString();
data.FieldValue = table.value.column[name].search.value.toString();
if (table.value.column[name].searchType != undefined) {
let v: number = table.value.column[name].searchType || 0;
if (table.value.column[name].search.searchType != undefined) {
let v: number = table.value.column[name].search.searchType || 0;
data.ConditionalType = v;
}
table.value.search.Conditions.push(data);
@ -342,37 +316,6 @@ function handleReloadPaged(reload = true) {
}
//
async function fetchInitData() {
for (const key in table.value.column) {
const element = table.value.column[key];
if (element.type === "dropdown") {
if (!element.setting.datasource) {
//
// let rdata = await eval(element.setting.datasourceStr);
// element.setting.datasource = rdata.data;
// console.log(key + " " + element.setting.datasourceStr, rdata);
}
}
if (
element.custom == undefined &&
(element.type === "switch" ||
element.type === "dropdown" ||
element.type === "string" ||
element.type === undefined)
) {
if (element.type === "string" || element.type === undefined)
element.custom = (row) => row[key];
else {
element.custom = (row) => {
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) {
element.custom = (row) => row[key];
}
}
setTimeout(() => {
init.value = true;
appStyle();
@ -418,7 +361,7 @@ function fetchPagedData() {
<el-form-item v-for="(o, n, i) in table.column" v-show="o.search" :key="i">
<el-date-picker
v-if="o.type.trim() == 'datetime'"
v-model="o.value as Date"
v-model="o.search.value as Date"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
@ -427,8 +370,8 @@ function fetchPagedData() {
/>
<el-select
v-else-if="o.type.trim() == 'dropdown'"
v-model="o.value"
:multiple="o.multiple"
v-model="o.search.value"
:multiple="o.edit.multiple"
clearable
filterable
:placeholder="o.label"
@ -444,7 +387,7 @@ function fetchPagedData() {
</el-select>
<el-select
v-else-if="o.type.trim() == 'switch'"
v-model="o.value"
v-model="o.search.value"
clearable
filterable
:placeholder="o.label"
@ -454,7 +397,7 @@ function fetchPagedData() {
<el-option autocomplete="off" :label="'禁用'" :value="false" />
</el-select>
<div v-else-if="o.type.trim() == 'img'" v-show="false" />
<el-input v-else v-model="o.value as string" :placeholder="o.label" />
<el-input v-else v-model="o.search.value as string" :placeholder="o.label" />
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleReloadPaged(false)"

View File

@ -40,6 +40,14 @@ export const ruleNumber = [
trigger: "blur"
}
];
export const ruleClassName = [
{
pattern: /^[1-9]\d*班$/,
message: "请输入正确班级名称[例:101班]",
trigger: "blur"
},
...ruleRequired
];
export const ruleRequiredNumber = [
{ required: true, message: "不能为空", trigger: "blur" },
{

View File

@ -1,11 +1,18 @@
<script setup lang="ts">
import ahTable from "@/components/hTable/index.vue";
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
import {
ConditionalType,
intTableData,
TableColumn,
TableColumnEdit,
TableColumnSearch,
TableConfig,
} from "@/components/hTable/hTable";
import { onMounted, ref, defineOptions } from "vue";
import { fa } from "element-plus/es/locales.mjs";
import { hTableAPI } from "@/api/hTable";
import { getenum } from "@/api/enum";
import { ruleRequired } from "@/utils/rules";
import { ruleClassName, ruleRequired } from "@/utils/rules";
const ControllerName = "classes";
defineOptions({
@ -16,7 +23,7 @@ const SchoolApi = new hTableAPI("usercenter/back/schools");
function searchCallback(data) {}
const table = ref<{ initTable: (config: TableConfig) => void }>();
const tableData: TableConfig = {
const tableData: TableConfig = intTableData({
apiUrl: "usercenter/back/classes",
selectColumn: false, //
border: false, //
@ -66,98 +73,57 @@ const tableData: TableConfig = {
//
id: {
label: "编号",
search: true,
add: false, //
edit: false, //
width: "150px",
},
schoolId: {
label: "学校",
rules: ruleRequired,
width: "180px",
search: true,
type: "dropdown",
add: true, //
edit: true, //
setting: {},
},
name: {
label: "名称",
search: new TableColumnSearch(true),
edit: {
rules: ruleRequired,
width: "180px",
search: true,
searchType: ConditionalType.Like, //
add: true, //
edit: true, //
},
},
Grade: {
label: "年级",
rules: ruleRequired,
width: "180px",
width: "220px",
type: "dropdown",
custom: (row) => `${row.grade ?? ""}`,
// `${row.grade ?? ""} ${row.gradeLevel + row.graduationYear}`,
search: true,
setting: {},
add: true, //
edit: false, //
custom: (row) => `${row.grade ?? ""} [${row.gradeLevel + row.graduationYear}]`,
search: new TableColumnSearch(true),
edit: { add: true, edit: false, rules: ruleRequired },
},
name: {
label: "名称",
width: "180px",
search: {
yes: true,
searchType: ConditionalType.Like, //
},
edit: {
add: true,
edit: true,
rules: ruleClassName,
},
},
// GradeLevel: {
// label: "",
// search: false,
// type: "dropdown",
// searchType: ConditionalType.Like,
// add: true, //
// edit: true, //
// width: "70px",
// setting: {
// datasource: [
// { text: "", value: "" },
// { text: "", value: "" },
// { text: "", value: "" }
// ]
// }
// },
// GraduationYear: {
// label: "",
// search: false,
// add: true, //
// edit: true, //
// width: "80px"
// },
type: {
label: "类型",
rules: ruleRequired,
// width: "150px",
type: "dropdown",
search: true,
add: true, //
edit: true, //
setting: {},
search: {
yes: true,
},
edit: {
add: true,
edit: true,
rules: ruleRequired,
},
},
// createTime: {
// label: "",
// width: "180px",
// type: "datetime",
// search: true,
// add: false, //
// edit: false //
// },
// remark: {
// label: "",
// type: "textarea",
// editRows: 3,
// search: false,
// add: true, //
// edit: true //
// }
},
data: [],
pageData: {
total: 0,
},
selectRows: [],
};
});
const showTable = ref(false);
onMounted(async () => {

View File

@ -1,6 +1,10 @@
<script setup lang="ts">
import ahTable from "@/components/hTable/index.vue";
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
import {
ConditionalType,
TableColumnSearch,
TableConfig,
} from "@/components/hTable/hTable";
import { onMounted, ref } from "vue";
import { fa } from "element-plus/es/locales.mjs";
defineOptions({
@ -52,34 +56,32 @@ const tableData: TableConfig = {
//
id: {
label: "编号",
search: true,
add: false, //
edit: false, //
width: "150px",
search: new TableColumnSearch(true),
},
name: {
label: "学校名称",
width: "300px",
search: true,
searchType: ConditionalType.Like,
add: true, //
edit: true, //
search: new TableColumnSearch(true),
edit: {
add: true,
edit: true,
},
},
pname: {
label: "地区",
width: "300px",
search: false,
custom: (row) => `${row.pname}-${row.cname}-${row.rname}`,
add: false, //
edit: false, //
},
enable: {
label: "启用",
type: "switch",
search: true,
custom: (row) => (row.enable ? "启用" : "禁用"),
add: true, //
edit: true, //
search: new TableColumnSearch(true),
edit: {
add: true,
edit: true,
},
},
},
data: [],