xiangbo #1
|
|
@ -8,3 +8,7 @@ VITE_PUBLIC_PATH = /
|
|||
VITE_ROUTER_HISTORY = "hash"
|
||||
|
||||
VITE_API_BASEURL = "http://192.168.2.33:5199/api"
|
||||
# 接口地址
|
||||
# VITE_API_BASEURL = "http://localhost:5199/api"
|
||||
#数据中心后台地址
|
||||
VITE_API_USERCENTER_URL = "https://dca.w.23544.com:8843/api"
|
||||
|
|
|
|||
|
|
@ -11,3 +11,9 @@ VITE_CDN = false
|
|||
# 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
|
||||
# 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
|
||||
VITE_COMPRESSION = "none"
|
||||
|
||||
|
||||
# 接口地址
|
||||
VITE_API_BASEURL = "http://localhost:5199/api"
|
||||
#数据中心后台地址
|
||||
VITE_API_USERCENTER_URL = "https://dcb.23544.com/api"
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# shellcheck source=./_/husky.sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
PATH="/usr/local/bin:$PATH"
|
||||
|
||||
npx --no-install commitlint --edit "$1"
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/sh
|
||||
command_exists () {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Workaround for Windows 10, Git Bash and Pnpm
|
||||
if command_exists winpty && test -t 1; then
|
||||
exec < /dev/tty
|
||||
fi
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
. "$(dirname "$0")/common.sh"
|
||||
|
||||
[ -n "$CI" ] && exit 0
|
||||
|
||||
PATH="/usr/local/bin:$PATH"
|
||||
|
||||
# Perform lint check on files in the staging area through .lintstagedrc configuration
|
||||
pnpm exec lint-staged
|
||||
|
|
@ -7,7 +7,7 @@ import type { Res } from "@/utils/http/types";
|
|||
* @return {object}
|
||||
*/
|
||||
export function getenum(type) {
|
||||
return http.request<Res<any>>("get", `public/enum/${type}`);
|
||||
return http.request<Res<any>>("get", `Public/enum/${type}`);
|
||||
}
|
||||
/**
|
||||
* @description 获取枚举对象
|
||||
|
|
@ -15,5 +15,5 @@ export function getenum(type) {
|
|||
* @return {object}
|
||||
*/
|
||||
export function getenumDic(type) {
|
||||
return http.request<Res<any>>("get", `public/enum/${type}/Dic`);
|
||||
return http.request<Res<any>>("get", `Public/enum/${type}/Dic`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { http } from "@/utils/http";
|
||||
// import type { Res } from "@/utils/http/types";
|
||||
|
||||
/**
|
||||
* @description 导入表单
|
||||
* @return {object}
|
||||
*/
|
||||
export function ImportExamInfo(id: number, file: File) {
|
||||
let formData = new FormData();
|
||||
formData.append("eId", id.toString());
|
||||
formData.append("file", file);
|
||||
return http.request<any>(
|
||||
"post",
|
||||
`ExamClassInfo/Import`,
|
||||
{
|
||||
data: formData
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -11,13 +11,9 @@ export class hTableAPI {
|
|||
PageList(data = {}) {
|
||||
return http.request<Res<any>>("post", `${this.url}/PageList`, { data });
|
||||
}
|
||||
Info(tag = {}) {
|
||||
const pUrl = `${this.url}/Info`;
|
||||
Info(tag) {
|
||||
const pUrl = `${this.url}/${tag}`;
|
||||
let getUrl = pUrl;
|
||||
for (const key in tag) {
|
||||
const el = tag[key];
|
||||
getUrl += (getUrl === pUrl ? "?" : "&") + key + "=" + el;
|
||||
}
|
||||
return http.request<Res<any>>("get", getUrl);
|
||||
}
|
||||
edit(data) {
|
||||
|
|
@ -32,3 +28,4 @@ export class hTableAPI {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,3 +30,10 @@ export function MenuAll() {
|
|||
export function Edit(info: MenuItem) {
|
||||
return http.request<Res<MenuItem[]>>("post", `Menu/Edit`, { data: info });
|
||||
}
|
||||
/**
|
||||
* @description 获取所有的菜单
|
||||
* @return {object}
|
||||
*/
|
||||
export function Del(ids: number[]) {
|
||||
return http.request<Res<MenuItem[]>>("post", `Menu/Del`, { data: ids });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,3 @@ 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 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
import { http } from "@/utils/http";
|
||||
import type { Res, ResPage } from "@/utils/http/types";
|
||||
/**
|
||||
* @description 获取枚举下拉
|
||||
* @param {string} type 枚举类型 type=StatusEnum
|
||||
* @return {object}
|
||||
*/
|
||||
export function getPageUserList(data: any) {
|
||||
return http.request<ResPage<UserDetail[]>>(
|
||||
"post",
|
||||
`userCenter/back/users/getpageuserlist`,
|
||||
{
|
||||
data
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description 编辑学校
|
||||
* @return {void}
|
||||
*/
|
||||
export function EditSchool(data: any) {
|
||||
return http.request<Res<any>>("post", `userCenter/back/schools/add`, {
|
||||
data
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @description 获取学校
|
||||
* @return {void}
|
||||
*/
|
||||
export function getSchoolData() {
|
||||
return http.request<Res<ComboModel[]>>(
|
||||
"get",
|
||||
`userCenter/public/getschooldata`
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description 获取职位列表
|
||||
* @return {void}
|
||||
*/
|
||||
export function getPositionList(data: any) {
|
||||
return http.request<Res<any>>(
|
||||
"post",
|
||||
`userCenter/back/positions/getpositionlist`,
|
||||
{ data }
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description 云校下拉框数据
|
||||
* @return {object}
|
||||
*/
|
||||
export function cloudSchoolCombo() {
|
||||
let data = {
|
||||
ValueName: "Id",
|
||||
TextName: "Name"
|
||||
};
|
||||
return http.request<Res<any>>(
|
||||
"post",
|
||||
`userCenter/back/cloudschool/querycombo`,
|
||||
{
|
||||
data
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description 获取用户信息
|
||||
* @return {object}
|
||||
*/
|
||||
export function getUserInfo(id) {
|
||||
return http.request<Res<any>>(
|
||||
"get",
|
||||
`userCenter/back/users/getuserinfo?id=${id}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 添加班级
|
||||
* @return {object}
|
||||
*/
|
||||
export function addClasses(info: any) {
|
||||
return http.request<Res<any>>("post", `userCenter/back/classes/addclass`, {
|
||||
data: info
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 添加班级
|
||||
* @return {object}
|
||||
*/
|
||||
export function editUser(data: any) {
|
||||
return http.request<Res<any>>("post", `userCenter/back/users/edituser`, {
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 添加班级
|
||||
* @return {object}
|
||||
*/
|
||||
export function getClassCombo(info: any) {
|
||||
return http.request<Res<any>>("post", `userCenter/public/getclasscombo`, {
|
||||
data: info
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取科目
|
||||
* @return {object}
|
||||
*/
|
||||
export function getSubjectData() {
|
||||
return http.request<Res<any>>("get", `userCenter/public/getsubjectdata`);
|
||||
}
|
||||
/**
|
||||
* @description 获取职位列表
|
||||
* @return {object}
|
||||
*/
|
||||
export function getPositions(data) {
|
||||
return http.request<Res<any>>("post", `userCenter/back/positions/positions`, {
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------interface----------------------------
|
||||
|
||||
/**
|
||||
* 职位信息
|
||||
*/
|
||||
export interface Position {
|
||||
userId: number;
|
||||
id: number;
|
||||
name: string;
|
||||
schoolId: number;
|
||||
enable: boolean;
|
||||
endTime: string | null;
|
||||
schoolName: string;
|
||||
graduationYear: number;
|
||||
grade: string;
|
||||
classId: number;
|
||||
className: string;
|
||||
subjectId: number;
|
||||
subjectName: string;
|
||||
positionType: number;
|
||||
positionLevel: number;
|
||||
status: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户详细信息
|
||||
*/
|
||||
export interface UserDetail {
|
||||
id: number;
|
||||
templateId: number;
|
||||
phone: string;
|
||||
edited: boolean;
|
||||
userType: number;
|
||||
cloudSchoolId: number;
|
||||
account: string;
|
||||
studentId: string;
|
||||
realName: string;
|
||||
sex: number;
|
||||
subjectLevel: any;
|
||||
birthDate: string;
|
||||
residence: string;
|
||||
national: string;
|
||||
headImage: string;
|
||||
idCard: string | null;
|
||||
pid: number;
|
||||
pname: string;
|
||||
cid: number;
|
||||
cname: string;
|
||||
rid: number;
|
||||
rname: string;
|
||||
wx: string;
|
||||
isPerfectInfo: number;
|
||||
level: number;
|
||||
state: number;
|
||||
meetingAccount: string | null;
|
||||
gkSubject: string | null;
|
||||
glSubject: string | null;
|
||||
gSubject1: string | null;
|
||||
gSubject2: string | null;
|
||||
thirdPartyId: string | null;
|
||||
pointPenSN: string | null;
|
||||
subjectLevels: null;
|
||||
positions: Position[];
|
||||
}
|
||||
|
|
@ -1,68 +1,98 @@
|
|||
export interface Dialog {
|
||||
/* 对话框是否可见 */
|
||||
/** 对话框是否可见 */
|
||||
visible: boolean;
|
||||
/* 是否显示关闭按钮 */
|
||||
/** 是否显示关闭按钮 */
|
||||
close: boolean;
|
||||
/* 对话框标题 */
|
||||
/** 对话框标题 */
|
||||
title: string;
|
||||
/* 对话框宽度 */
|
||||
/** 对话框宽度 */
|
||||
width: string;
|
||||
/**自定义弹窗数据 */
|
||||
custom: {
|
||||
/* 自定义对话框高度 */
|
||||
/** 自定义对话框高度 */
|
||||
height: string;
|
||||
/* 自定义对话框数据 */
|
||||
/** 自定义对话框数据 */
|
||||
data: any[];
|
||||
/* 自定义组件路径 */
|
||||
/** 自定义组件路径 */
|
||||
src?: string;
|
||||
/* 自定义配置项 */
|
||||
/** 自定义配置项 */
|
||||
custom: Record<string, any>;
|
||||
/* 自定义对话框是否可见 */
|
||||
/** 自定义对话框是否可见 */
|
||||
visible: boolean;
|
||||
/* 异步加载组件 */
|
||||
/** 异步加载组件 */
|
||||
component: any;
|
||||
};
|
||||
edit: {
|
||||
/* 编辑项ID */
|
||||
/** 编辑项ID */
|
||||
id: number;
|
||||
/* 编辑对话框标题 */
|
||||
/** 编辑对话框标题 */
|
||||
title: string;
|
||||
/* 编辑对话框是否可见 */
|
||||
/** 编辑对话框是否可见 */
|
||||
visible: boolean;
|
||||
row?: any;
|
||||
tagData?: any;
|
||||
};
|
||||
}
|
||||
|
||||
/* 按钮自定义配置 */
|
||||
/** 按钮自定义配置 */
|
||||
export interface ButtonCustomConfig {
|
||||
/* 弹出框标题 */
|
||||
/** 弹出框标题 */
|
||||
title: string;
|
||||
/* 组件路径 */
|
||||
/** 组件路径 */
|
||||
src: string;
|
||||
/* 弹框宽度 */
|
||||
/** 弹框宽度 */
|
||||
width: string;
|
||||
/* 弹框高度 */
|
||||
/** 弹框高度 */
|
||||
height: string;
|
||||
}
|
||||
|
||||
/* 操作按钮配置 */
|
||||
/** 操作按钮配置 */
|
||||
export interface OperationButton {
|
||||
/* 是否为头部按钮 */
|
||||
/** 是否为头部按钮 */
|
||||
topBtn: boolean;
|
||||
/* 是否显示 */
|
||||
/** 按钮权限码 */
|
||||
perms?: string;
|
||||
/** 是否显示 */
|
||||
show?: boolean;
|
||||
/* 按钮文本 */
|
||||
/** 按钮文本 */
|
||||
label: string;
|
||||
/* 按钮类型 */
|
||||
btnType: "add" | "edit" | "del" | "custom";
|
||||
/* 按钮样式 */
|
||||
btnStyle?: "success" | "danger";
|
||||
/* 自定义按钮配置 */
|
||||
/** 按钮点击事件
|
||||
* @tips btnType 为空时触发
|
||||
* @param obj 当前按钮配置对象
|
||||
* @param row 当前行数据
|
||||
* @param handleReloadPaged 父表单刷新函数
|
||||
*/
|
||||
click?: (obj, row, handleReloadPaged: (reload: boolean) => void) => void;
|
||||
/** 按钮类型 */
|
||||
btnType?: "add" | "edit" | "del" | "custom";
|
||||
/** 按钮样式 */
|
||||
btnStyle?: "success" | "info" | "primary" | "danger" | "warning";
|
||||
/** 自定义按钮配置 */
|
||||
custom?: ButtonCustomConfig;
|
||||
}
|
||||
|
||||
/* 字段设置项 */
|
||||
/** 类型判断枚举 */
|
||||
export enum ConditionalType {
|
||||
Equal,
|
||||
Like,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
In,
|
||||
NotIn,
|
||||
LikeLeft,
|
||||
LikeRight,
|
||||
NoEqual,
|
||||
IsNullOrEmpty,
|
||||
IsNot,
|
||||
NoLike,
|
||||
EqualNull,
|
||||
InLike,
|
||||
Range
|
||||
}
|
||||
|
||||
/** 字段设置项 */
|
||||
export interface FieldSetting {
|
||||
/**map 时Value的取值的属性 */
|
||||
mapValue?: string;
|
||||
|
|
@ -77,49 +107,44 @@ export interface FieldSetting {
|
|||
* @returns 预期返回有效图片地址url
|
||||
*/
|
||||
imgUrl?: (value: any, row: any) => string;
|
||||
/* 数据源 */
|
||||
/** 数据源 */
|
||||
datasource?: ComboModel[];
|
||||
}
|
||||
///* 表格列配置 */
|
||||
///** 表格列配置 */
|
||||
//export interface TableEditColumn {}
|
||||
export interface ComboModel {
|
||||
Value: any;
|
||||
Text: string;
|
||||
value: any;
|
||||
text: string;
|
||||
}
|
||||
/* 表格列配置 */
|
||||
/** 表格列配置 */
|
||||
export interface TableColumn {
|
||||
/* 显示标签 */
|
||||
/** 显示标签 */
|
||||
label: string;
|
||||
/* 是否可搜索 */
|
||||
/** 是否可搜索 */
|
||||
search: boolean;
|
||||
/* 搜索类型 */
|
||||
searchType?:
|
||||
| "Equal"
|
||||
| "NoEqual"
|
||||
| "Like"
|
||||
| "GreaterThan"
|
||||
| "LessThan"
|
||||
| "NoLike";
|
||||
/* 是否允许添加 */
|
||||
add: boolean;
|
||||
/* 是否允许修改 */
|
||||
/** 搜索类型 */
|
||||
searchType?: ConditionalType;
|
||||
/** 是否允许添加 [false]*/
|
||||
add?: boolean;
|
||||
/** 是否允许修改 [false]*/
|
||||
edit?: boolean;
|
||||
/* 列宽度 */
|
||||
/** 列宽度 [auto]*/
|
||||
width?: string;
|
||||
/* 字段类型 */
|
||||
type?: 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;
|
||||
|
|
@ -129,55 +154,67 @@ export interface TableColumn {
|
|||
custom?: (row: any) => string;
|
||||
}
|
||||
|
||||
/* 分页数据 */
|
||||
/** 分页数据 */
|
||||
export interface PageData {
|
||||
/* 总条数 */
|
||||
/** 总条数 */
|
||||
total: number;
|
||||
}
|
||||
|
||||
/* 搜索条件 */
|
||||
/** 分页数据 */
|
||||
export interface ConditionalModel {
|
||||
/** 字段名称 */
|
||||
FieldName: string;
|
||||
/** 字段查询值 */
|
||||
FieldValue: string;
|
||||
/** 查询方式 */
|
||||
ConditionalType?: ConditionalType;
|
||||
/** C#类型名称 */
|
||||
CSharpTypeName?: string;
|
||||
}
|
||||
|
||||
/** 搜索条件 */
|
||||
export interface SearchConditions {
|
||||
/* 是否显示搜索 */
|
||||
/** 是否显示搜索 */
|
||||
show: boolean;
|
||||
/* 当前页码 */
|
||||
/** 当前页码 */
|
||||
PageIndex: number;
|
||||
/* 每页大小 */
|
||||
/** 每页大小 */
|
||||
PageSize: number;
|
||||
/* 排序字段 */
|
||||
/** 排序字段 */
|
||||
OrderBy: string;
|
||||
/* 默认查询条件 */
|
||||
defaultConditions: any[];
|
||||
/* 查询条件 */
|
||||
/** 默认查询条件 */
|
||||
defaultConditions: ConditionalModel[];
|
||||
/** 查询条件 */
|
||||
Conditions: any[];
|
||||
}
|
||||
|
||||
/* 表格配置 */
|
||||
/** 表格配置 */
|
||||
export interface TableConfig {
|
||||
/* 搜索回调函数 */
|
||||
/** 搜索回调函数 */
|
||||
searchCallback?: (s: SearchConditions) => void;
|
||||
/* 新增/修改回调函数 */
|
||||
/** 新增/修改回调函数 */
|
||||
editCallback?: (from: any) => void;
|
||||
/* API地址 */
|
||||
/** API地址 */
|
||||
apiUrl: string;
|
||||
/* 是否显示选择列 */
|
||||
/** 是否显示选择列 */
|
||||
selectColumn: boolean;
|
||||
/* 搜索配置 */
|
||||
/** 搜索配置 */
|
||||
search: SearchConditions;
|
||||
/* 是否显示操作列 */
|
||||
/** 是否显示操作列 */
|
||||
operationColumn: boolean;
|
||||
/* 操作按钮配置 */
|
||||
/** 操作按钮配置 */
|
||||
operationColumnData: OperationButton[];
|
||||
/* 列配置 */
|
||||
/** 列配置 */
|
||||
column: Record<string, TableColumn>;
|
||||
/* 表格数据 */
|
||||
/** 表格数据 */
|
||||
data: any[];
|
||||
/**显示头部操作按钮 */
|
||||
operationTop?: boolean;
|
||||
/* 分页数据 */
|
||||
/** 分页数据 */
|
||||
pageData: PageData;
|
||||
/* 选中行 */
|
||||
/** 选中行 */
|
||||
selectRows: any[];
|
||||
/* 是否显示边框 */
|
||||
/** 是否显示边框 */
|
||||
border: boolean;
|
||||
/**是否显示 */
|
||||
show?: boolean;
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ function handleSubmitForm() {
|
|||
}
|
||||
|
||||
editData.value.loading = true;
|
||||
let form = {};
|
||||
let form: any = {};
|
||||
if (editData.value.isedit) {
|
||||
form = props.row;
|
||||
}
|
||||
} else form.id = 0;
|
||||
for (const key in column.value) {
|
||||
const element = column.value[key];
|
||||
if (element.valueE !== null && element.valueE !== "") {
|
||||
|
|
@ -116,9 +116,9 @@ function handleResetForm() {
|
|||
function fetchInitData() {}
|
||||
function fetchFormData() {
|
||||
editData.value.loading = false;
|
||||
handleResetForm();
|
||||
if (editData.value.isedit) {
|
||||
Api.Info({ id: props.id }).then(res => {
|
||||
handleResetForm();
|
||||
Api.Info(props.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
editData.value.frorm = res.data;
|
||||
for (const key in column.value) {
|
||||
|
|
@ -154,11 +154,11 @@ function fetchFormData() {
|
|||
<div v-if="o.type.trim() == 'datetime'">
|
||||
<el-date-picker
|
||||
v-model="o.valueE as Date"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:placeholder="o.label"
|
||||
style="width: 100%"
|
||||
class="elWidth"
|
||||
@change="o.change"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -169,12 +169,12 @@ function fetchFormData() {
|
|||
clearable
|
||||
filterable
|
||||
:placeholder="o.label"
|
||||
style="width: 100%"
|
||||
class="elWidth"
|
||||
@change="o.change"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in o.setting.datasource"
|
||||
:key="item.Value"
|
||||
:key="item.value"
|
||||
autocomplete="off"
|
||||
:label="item[o.setting.maplabel]"
|
||||
:value="item[o.setting.mapValue]"
|
||||
|
|
@ -187,19 +187,25 @@ function fetchFormData() {
|
|||
:rows="o.editRows || 4"
|
||||
type="textarea"
|
||||
:placeholder="o.label"
|
||||
class="elWidth"
|
||||
@change="o.change"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="o.type.trim() == 'switch'">
|
||||
<el-switch
|
||||
v-model="o.valueE as string"
|
||||
v-model="o.valueE as boolean"
|
||||
active-text="启用"
|
||||
inactive-text="禁用"
|
||||
class="elWidth"
|
||||
@change="o.change"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-input v-model="o.valueE as string" :placeholder="o.label" />
|
||||
<el-input
|
||||
v-model="o.valueE as string"
|
||||
class="elWidth"
|
||||
:placeholder="o.label"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
|
|
@ -215,3 +221,9 @@ function fetchFormData() {
|
|||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.elWidth {
|
||||
width: 100%;
|
||||
min-width: 220px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { Search } from "@element-plus/icons-vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { defineAsyncComponent, AsyncComponentLoader } from "vue";
|
||||
import { Dialog, TableColumn, TableConfig } from "./hTable";
|
||||
import { ConditionalType, Dialog, TableColumn, TableConfig } from "./hTable";
|
||||
import hTableEdit from "./hTableEdit.vue";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { getenum } from "@/api/enum";
|
||||
|
|
@ -108,7 +108,8 @@ function intdata() {
|
|||
// 处理 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 ? [] : "";
|
||||
|
|
@ -274,17 +275,19 @@ function handleReloadPaged(reload = true) {
|
|||
let data: any = { ConditionalType: 0 };
|
||||
if (table.value.column[name].type === "datetime") {
|
||||
// data.CSharpTypeName = 'DateTime'
|
||||
data.ConditionalType = 8; // '2023-10-07%'
|
||||
data.ConditionalType = ConditionalType.LikeLeft; // '2023-10-07%'
|
||||
} else if (table.value.column[name].type === "switch") {
|
||||
data.CSharpTypeName = "Boolean";
|
||||
} else if (table.value.column[name].type === "string") {
|
||||
data.ConditionalType = "Like";
|
||||
}
|
||||
data.ConditionalType = ConditionalType.Like;
|
||||
} else data.ConditionalType = ConditionalType.Equal;
|
||||
|
||||
data.FieldName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
data.FieldValue = table.value.column[name].value.toString();
|
||||
|
||||
if (table.value.column[name].searchType != undefined) {
|
||||
data.ConditionalType = table.value.column[name].searchType || 0;
|
||||
let v: number = table.value.column[name].searchType || 0;
|
||||
data.ConditionalType = v;
|
||||
}
|
||||
table.value.search.Conditions.push(data);
|
||||
}
|
||||
|
|
@ -559,7 +562,14 @@ function fetchPagedData() {
|
|||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="display: flex; align-items: center; justify-content: center">
|
||||
<div
|
||||
style="
|
||||
padding-top: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<el-pagination
|
||||
:current-page="table.search.PageIndex + 1"
|
||||
:page-sizes="[20, 40, 80, 100]"
|
||||
|
|
|
|||
|
|
@ -166,7 +166,11 @@ router.beforeEach((to: ToRouteType, _from, next) => {
|
|||
getTopMenu(true);
|
||||
// query、params模式路由传参数的标签页不在此处处理
|
||||
if (route && route.meta?.title) {
|
||||
if (isAllEmpty(route.parentId) && route.meta?.backstage) {
|
||||
if (
|
||||
isAllEmpty(route.parentId) &&
|
||||
route.meta?.backstage &&
|
||||
route.children
|
||||
) {
|
||||
// 此处为动态顶级路由(目录)
|
||||
const { path, name, meta } = route.children[0];
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@ export default {
|
|||
title: "首页",
|
||||
showLink: VITE_HIDE_HOME === "true" ? false : true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/school",
|
||||
name: "school",
|
||||
component: () => import("@/views/school/index.vue"),
|
||||
meta: {
|
||||
title: "学校",
|
||||
showLink: true
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies RouteConfigsTable;
|
||||
|
|
|
|||
|
|
@ -84,8 +84,7 @@ export function setToken(data: DataInfo<Date>) {
|
|||
permissions
|
||||
});
|
||||
}
|
||||
|
||||
if (data.userName && data.roles) {
|
||||
if (data.userName && data.permissions) {
|
||||
const { userName, roles } = data;
|
||||
setUserKey({
|
||||
avatar: data?.avatar ?? "",
|
||||
|
|
@ -129,7 +128,7 @@ export const formatToken = (token: string): string => {
|
|||
|
||||
/** 是否有按钮级别的权限(根据登录接口返回的`permissions`字段进行判断)*/
|
||||
export const hasPerms = (value: string | Array<string>): boolean => {
|
||||
if (!value) return false;
|
||||
if (!value) return true;
|
||||
const allPerms = "*:*:*";
|
||||
const { permissions } = useUserStoreHook();
|
||||
if (!permissions) return false;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,62 @@ import { stringify } from "qs";
|
|||
import NProgress from "../progress";
|
||||
import { getToken, formatToken } from "@/utils/auth";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
// import { string } from "vue-types";
|
||||
import router from "@/router";
|
||||
|
||||
/**请求后端的地址 未配置则访问BaseURL */
|
||||
const apiServiceConfig = {
|
||||
userCenter: import.meta.env.VITE_API_USERCENTER_URL,
|
||||
usercenter: import.meta.env.VITE_API_USERCENTER_URL
|
||||
};
|
||||
|
||||
function setAPIUrl(c: PureHttpRequestConfig): void {
|
||||
let url = c.url;
|
||||
let token = url.startsWith("/") ? url.split("/")[1] : url.split("/")[0];
|
||||
if (apiServiceConfig[token] != null) {
|
||||
c.url = url.replaceAll(token, "");
|
||||
c.baseURL = apiServiceConfig[token];
|
||||
} else c.baseURL = import.meta.env.VITE_API_BASEURL;
|
||||
}
|
||||
|
||||
const snakeToCamel = (str: string): string => {
|
||||
// 处理蛇形命名(user_id → userId)
|
||||
let result = str.replace(/_([a-zA-Z0-9])/g, (_, letter) =>
|
||||
letter.toUpperCase()
|
||||
);
|
||||
|
||||
// 处理大驼峰命名(UserName → userName)
|
||||
if (result.length > 0) {
|
||||
result = result.charAt(0).toLowerCase() + result.slice(1);
|
||||
}
|
||||
|
||||
// 特殊场景:处理连续下划线(__type → Type)
|
||||
result = result.replace(/^_+/, "");
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 递归转换对象/数组的键名为小驼峰格式
|
||||
*/
|
||||
const convertKeysToCamelCase = <T>(data: any): T => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(item => convertKeysToCamelCase(item)) as unknown as T;
|
||||
}
|
||||
|
||||
if (data !== null && typeof data === "object") {
|
||||
return Object.keys(data).reduce((result, key) => {
|
||||
const camelKey = snakeToCamel(key);
|
||||
const value = data[key];
|
||||
return {
|
||||
...result,
|
||||
[camelKey]: convertKeysToCamelCase(value)
|
||||
};
|
||||
}, {}) as T;
|
||||
}
|
||||
|
||||
return data as T;
|
||||
};
|
||||
|
||||
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
||||
const defaultConfig: AxiosRequestConfig = {
|
||||
|
|
@ -64,6 +120,9 @@ class PureHttp {
|
|||
async (config: PureHttpRequestConfig): Promise<any> => {
|
||||
// 开启进度条动画
|
||||
NProgress.start();
|
||||
if (config.url.indexOf("http") === -1) {
|
||||
setAPIUrl(config);
|
||||
}
|
||||
// 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
||||
if (typeof config.beforeRequestCallback === "function") {
|
||||
config.beforeRequestCallback(config);
|
||||
|
|
@ -124,6 +183,7 @@ class PureHttp {
|
|||
const $config = response.config;
|
||||
// 关闭进度条动画
|
||||
NProgress.done();
|
||||
response.data = convertKeysToCamelCase(response.data);
|
||||
// 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
||||
if (typeof $config.beforeResponseCallback === "function") {
|
||||
$config.beforeResponseCallback(response);
|
||||
|
|
@ -140,6 +200,12 @@ class PureHttp {
|
|||
$error.isCancelRequest = Axios.isCancel($error);
|
||||
// 关闭进度条动画
|
||||
NProgress.done();
|
||||
if (error.response?.status === 403) {
|
||||
// 跳转到403页面
|
||||
router.push({
|
||||
path: "/error/403"
|
||||
});
|
||||
}
|
||||
// 所有的响应异常 区分来源为取消请求/非取消请求
|
||||
return Promise.reject($error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,14 @@ export interface PureHttpError extends AxiosError {
|
|||
isCancelRequest?: boolean;
|
||||
}
|
||||
|
||||
export type ResPage<T> = {
|
||||
code: number;
|
||||
data: {
|
||||
data: T;
|
||||
total: number;
|
||||
};
|
||||
message: string;
|
||||
};
|
||||
export type Res<T> = {
|
||||
code: number;
|
||||
data: T;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
export const ruleRequired = [
|
||||
{ required: true, message: "不能为空", trigger: "blur" }
|
||||
];
|
||||
export const ruleRequiredNumber = [
|
||||
{ required: true, message: "不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: /^\d*\.?\d+$/,
|
||||
message: "请输入正确数字",
|
||||
trigger: "blur"
|
||||
}
|
||||
];
|
||||
export const rulePassword = [
|
||||
{ required: true, message: "不能为空", trigger: "blur" },
|
||||
{ min: 6, message: "长度必须大于5", trigger: "blur" }
|
||||
];
|
||||
export const ruleAccount = [
|
||||
{ required: true, message: "不能为空", trigger: "blur" },
|
||||
{ min: 13, message: "长度必须大于12", trigger: "blur" }
|
||||
];
|
||||
|
||||
export const rulePhone = [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: "请输入正确的手机号",
|
||||
trigger: "blur"
|
||||
}
|
||||
];
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ConditionalType, 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 {
|
||||
ruleAccount,
|
||||
rulePassword,
|
||||
rulePhone,
|
||||
ruleRequired
|
||||
} from "@/utils/rules";
|
||||
const ControllerName = "Admin";
|
||||
|
||||
defineOptions({
|
||||
|
|
@ -71,13 +77,15 @@ const tableData: TableConfig = {
|
|||
name: {
|
||||
label: "名称",
|
||||
width: "180px",
|
||||
rules: ruleRequired,
|
||||
search: true,
|
||||
searchType: "Like",
|
||||
searchType: ConditionalType.Like,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
Phone: {
|
||||
label: "手机号",
|
||||
rules: rulePhone,
|
||||
width: "200px",
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
|
|
@ -85,6 +93,7 @@ const tableData: TableConfig = {
|
|||
},
|
||||
account: {
|
||||
label: "账号",
|
||||
rules: ruleAccount,
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
|
|
@ -92,6 +101,8 @@ const tableData: TableConfig = {
|
|||
password: {
|
||||
label: "密码",
|
||||
show: false,
|
||||
/**长度必须大于6 */
|
||||
rules: rulePassword,
|
||||
search: false,
|
||||
add: true, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
|
|
@ -100,13 +111,15 @@ const tableData: TableConfig = {
|
|||
label: "启用",
|
||||
type: "switch",
|
||||
search: false,
|
||||
add: false, // 字段允许添加
|
||||
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
valueE: true // 编辑时的默认值
|
||||
},
|
||||
roleId: {
|
||||
label: "角色",
|
||||
type: "dropdown",
|
||||
rules: ruleRequired,
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
edit: false, // 字段允许修改
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref,defineOptions } from "vue";
|
||||
import { fa } from "element-plus/es/locales.mjs";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
const ControllerName = "AdminRole";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
function searchCallback(data) {}
|
||||
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, // 头部按钮
|
||||
show: true,
|
||||
label: "角色授权",
|
||||
perms: "角色授权", //按钮显示需要的权限码
|
||||
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||
btnStyle: "success" // topBtn: true才生效 success danger
|
||||
},
|
||||
{
|
||||
// 操作按钮
|
||||
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: ConditionalType.Like,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
enable: {
|
||||
label: "启用",
|
||||
type: "switch",
|
||||
search: false,
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
valueE: true // 编辑时的默认值
|
||||
},
|
||||
createTime: {
|
||||
label: "创建时间",
|
||||
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 () => {
|
||||
//初始化数据原
|
||||
|
||||
showTable.value = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form
|
||||
ref="classesAddForm"
|
||||
:model="form"
|
||||
:label-width="formLabelWidth"
|
||||
clearable
|
||||
>
|
||||
<el-form-item label="学校" prop="SchoolId" :rules="ruleRequired">
|
||||
<el-select
|
||||
v-model="form.SchoolId"
|
||||
filterable
|
||||
placeholder="学校"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, id) in schoolList"
|
||||
:key="id"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="年级" prop="Grade" :rules="ruleRequired">
|
||||
<el-select
|
||||
v-model="form.Grade"
|
||||
filterable
|
||||
placeholder="年级"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in gradeList"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="班级类型" prop="Type" :rules="ruleRequired">
|
||||
<el-select
|
||||
v-model="form.Type"
|
||||
filterable
|
||||
placeholder="班级类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in TypeList"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="选修方向">
|
||||
<el-col :span="24">
|
||||
<div style="display: flex; gap: 10px">
|
||||
<el-select
|
||||
v-model="form.Elective1"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="历史/地理"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, id) in subject1"
|
||||
:key="id"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.Elective2"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, id) in subject2"
|
||||
:key="id"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.Elective3"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, id) in subject2"
|
||||
:key="id"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
label="班级名称"
|
||||
v-if="isEdit"
|
||||
prop="Name"
|
||||
:rules="ruleRequired"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.Name"
|
||||
filterable
|
||||
placeholder="班级名称"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in ClassNameList"
|
||||
:key="i"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="添加班级" v-if="!isEdit">
|
||||
<el-col :span="21">
|
||||
<el-select
|
||||
v-model="form.Name"
|
||||
filterable
|
||||
placeholder="班级名称"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in filteredClassNameList"
|
||||
:key="i"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<el-button type="success" @click="ClassNameAdd" round>添加</el-button>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="班级列表" :rules="ruleRequired" v-if="!isEdit">
|
||||
<span v-show="ClassNames.length === 0">暂未添加!</span>
|
||||
<el-tag
|
||||
v-for="tag in ClassNames"
|
||||
:key="tag"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="TagClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="handleSubmitForm">
|
||||
立即提交
|
||||
</el-button>
|
||||
<el-button @click="handleResetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type { FormInstance } from "element-plus";
|
||||
import { getenum } from "@/api/enum";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { ruleRequired } from "@/utils/rules";
|
||||
import { addClasses } from "@/api/userCenter";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
interface Formdata {
|
||||
Id: number;
|
||||
Name: string;
|
||||
SchoolId: string;
|
||||
Grade: string;
|
||||
Type: number;
|
||||
Elective1: string;
|
||||
Elective2: string;
|
||||
Elective3: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
id: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["handlePagedCallback"]);
|
||||
|
||||
// 表单引用
|
||||
const classesAddForm = ref<FormInstance>();
|
||||
|
||||
// 数据定义
|
||||
const form = ref<Formdata>({
|
||||
Id: props.id,
|
||||
Name: "",
|
||||
SchoolId: "",
|
||||
Grade: "",
|
||||
Type: 0,
|
||||
Elective1: "",
|
||||
Elective2: "",
|
||||
Elective3: ""
|
||||
});
|
||||
|
||||
const subject1 = ref<ComboModel[]>([
|
||||
{ value: 4, text: "物理" },
|
||||
{ value: 8, text: "历史" }
|
||||
]);
|
||||
|
||||
const subject2 = ref<ComboModel[]>([
|
||||
{ value: 5, text: "化学" },
|
||||
{ value: 6, text: "生物" },
|
||||
{ value: 9, text: "地理" },
|
||||
{ value: 7, text: "政治" }
|
||||
]);
|
||||
|
||||
const formLabelWidth = "120px";
|
||||
const size = "small";
|
||||
const loading = ref(false);
|
||||
const ClassNames = ref<string[]>([]);
|
||||
const ClassNameList = ref<string[]>([]);
|
||||
const schoolList = ref<ComboModel[]>([]);
|
||||
const TypeList = ref<ComboModel[]>([]);
|
||||
const gradeList = ref<ComboModel[]>([]);
|
||||
|
||||
// 计算属性
|
||||
const isEdit = computed(() => props.id > 0);
|
||||
const filteredClassNameList = computed(() =>
|
||||
ClassNameList.value.filter(s => !ClassNames.value.includes(s))
|
||||
);
|
||||
|
||||
// 方法
|
||||
const TagClose = (tag: string) => {
|
||||
ClassNames.value = ClassNames.value.filter(t => t !== tag);
|
||||
};
|
||||
|
||||
const ClassNameAdd = () => {
|
||||
if (form.value.Name === "") {
|
||||
ElMessage.error("添加的班级名称不能为空");
|
||||
return;
|
||||
}
|
||||
ClassNames.value.push(form.value.Name);
|
||||
form.value.Name = "";
|
||||
};
|
||||
|
||||
const handlePagedCallback = () => {
|
||||
emit("handlePagedCallback");
|
||||
};
|
||||
|
||||
const handleSubmitForm = async () => {
|
||||
debugger;
|
||||
if (props.id <= 0 || ClassNames.value.length < 1) {
|
||||
ElMessage.error("班级列表为空!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!classesAddForm.value) return;
|
||||
|
||||
await classesAddForm.value.validate(valid => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
let dataf = {
|
||||
...form.value,
|
||||
Id: props.id,
|
||||
Name: ClassNames.value.join()
|
||||
};
|
||||
addClasses(dataf).then(res => {
|
||||
loading.value = false;
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("操作成功");
|
||||
handlePagedCallback();
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
ClassNames.value = [];
|
||||
classesAddForm.value?.resetFields();
|
||||
};
|
||||
|
||||
const SchoolApi = new hTableAPI("usercenter/back/schools");
|
||||
const fetchInitdata = async () => {
|
||||
// 初始化班级列表
|
||||
ClassNameList.value = Array.from({ length: 500 }, (_, i) => `${i + 1}班`);
|
||||
|
||||
// 获取年级枚举
|
||||
const gradeRes = await getenum("GradeEnum");
|
||||
gradeList.value = gradeRes.data.map((s: ComboModel) => ({
|
||||
text: s.text,
|
||||
value: s.text
|
||||
}));
|
||||
|
||||
// 获取学校数据
|
||||
SchoolApi.querycombo({ TextName: "Name", ValueName: "Id" }).then(res => {
|
||||
if (res.code === 200) {
|
||||
schoolList.value = res.data;
|
||||
}
|
||||
});
|
||||
|
||||
// 获取班级类型
|
||||
const typeRes = await getenum("ClassTypeEnum");
|
||||
TypeList.value = typeRes.data;
|
||||
};
|
||||
|
||||
const fetchFormdata = () => {
|
||||
handleResetForm();
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
fetchInitdata();
|
||||
fetchFormdata();
|
||||
});
|
||||
|
||||
// 监听props变化
|
||||
watch(
|
||||
() => props.id,
|
||||
newVal => {
|
||||
form.value.Id = newVal;
|
||||
fetchFormdata();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag {
|
||||
margin-top: 4px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, 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";
|
||||
const ControllerName = "classes";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
const SchoolApi = new hTableAPI("usercenter/back/schools");
|
||||
function searchCallback(data) {}
|
||||
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||
const tableData: TableConfig = {
|
||||
apiUrl: "usercenter/back/classes",
|
||||
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: "新增",
|
||||
btnType: "custom", // 按钮类型 add edit del custom
|
||||
btnStyle: "success", // topBtn: true才生效 success danger
|
||||
custom: {
|
||||
// 按钮类型 custom 专用
|
||||
title: "新增班级", // 弹出框title
|
||||
src: "class/edit", // 组件路径
|
||||
width: "550px", // 弹框宽度
|
||||
height: "520px" // 弹框高度
|
||||
}
|
||||
},
|
||||
{
|
||||
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"
|
||||
},
|
||||
schoolId: {
|
||||
label: "学校",
|
||||
rules: ruleRequired,
|
||||
width: "180px",
|
||||
search: true,
|
||||
type: "dropdown",
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
setting: {}
|
||||
},
|
||||
name: {
|
||||
label: "名称",
|
||||
rules: ruleRequired,
|
||||
width: "180px",
|
||||
search: true,
|
||||
searchType: ConditionalType.Like, // 搜索类型
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
Grade: {
|
||||
label: "年级",
|
||||
rules: ruleRequired,
|
||||
width: "180px",
|
||||
type: "dropdown",
|
||||
custom: row => `${row.grade ?? ""}`,
|
||||
// `${row.grade ?? ""} ${row.gradeLevel + row.graduationYear}`,
|
||||
search: true,
|
||||
setting: {},
|
||||
add: true, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
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: {}
|
||||
}
|
||||
// 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 () => {
|
||||
//初始化数据原
|
||||
|
||||
tableData.column.Grade.setting.datasource = [
|
||||
{ text: "初一", value: "初一" },
|
||||
{ text: "初二", value: "初二" },
|
||||
{ text: "初三", value: "初三" },
|
||||
{ text: "高一", value: "高一" },
|
||||
{ text: "高二", value: "高二" },
|
||||
{ text: "高三", value: "高三" },
|
||||
{ text: "一年级", value: "一年级" },
|
||||
{ text: "二年级", value: "二年级" },
|
||||
{ text: "三年级", value: "三年级" },
|
||||
{ text: "四年级", value: "四年级" },
|
||||
{ text: "五年级", value: "五年级" },
|
||||
{ text: "六年级", value: "六年级" }
|
||||
];
|
||||
tableData.column.type.setting.datasource = (
|
||||
await getenum("ClassTypeEnum")
|
||||
).data;
|
||||
tableData.column.schoolId.setting.datasource = (
|
||||
await SchoolApi.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,143 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, 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, ruleRequiredNumber } from "@/utils/rules";
|
||||
const ControllerName = "ExamClassInfo";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
data: any;
|
||||
}>();
|
||||
|
||||
function searchCallback(data) {}
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||
const tableData: TableConfig = {
|
||||
apiUrl: ControllerName,
|
||||
selectColumn: false, // 列表选择
|
||||
border: false, // 是否显示表格边框
|
||||
searchCallback: searchCallback,
|
||||
search: {
|
||||
// 查询条件
|
||||
show: true,
|
||||
PageIndex: 0,
|
||||
PageSize: 20,
|
||||
OrderBy: "Id", // 排序
|
||||
defaultConditions: [
|
||||
{
|
||||
FieldName: "ExamId",
|
||||
FieldValue: props.data[0].id + "",
|
||||
ConditionalType: ConditionalType.Equal
|
||||
}
|
||||
], // 默认查询条件
|
||||
Conditions: []
|
||||
},
|
||||
operationColumn: true, // 显示操作按钮
|
||||
operationColumnData: [
|
||||
{
|
||||
// 操作按钮
|
||||
topBtn: true, // 是头部按钮
|
||||
label: "添加",
|
||||
btnStyle: "success",
|
||||
btnType: "custom"
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
show: true,
|
||||
label: "删除",
|
||||
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||
btnStyle: "danger" // topBtn: true才生效 success danger
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
show: true,
|
||||
label: "重新录入",
|
||||
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||
btnStyle: "primary" // topBtn: true才生效 success danger
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
show: true,
|
||||
label: "学生成绩详情",
|
||||
btnType: "custom",
|
||||
btnStyle: "primary",
|
||||
custom: {
|
||||
title: "考试班级详情", // 弹出框title
|
||||
src: "exam/userDetails", // 组件路径
|
||||
width: "1600px", // 弹框宽度
|
||||
height: "800px" // 弹框高度
|
||||
}
|
||||
}
|
||||
],
|
||||
column: {
|
||||
// 行数据
|
||||
schoolName: {
|
||||
label: "学校",
|
||||
search: true,
|
||||
searchType: ConditionalType.Like, // 搜索类型
|
||||
add: false, // 字段允许添加
|
||||
edit: false, // 字段允许修改
|
||||
width: "180px"
|
||||
},
|
||||
grade: {
|
||||
label: "年级",
|
||||
width: "100px",
|
||||
custom: s => `${s.gradeYear}${s.gradeLevel}`,
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
className: {
|
||||
label: "班级",
|
||||
width: "150px",
|
||||
search: true,
|
||||
searchType: ConditionalType.Like, // 搜索类型
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
peopleCount: {
|
||||
label: "参考人数",
|
||||
width: "100px",
|
||||
search: false,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
entryPerson: {
|
||||
label: "录入人",
|
||||
width: "200px",
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
createTime: {
|
||||
label: "录入时间",
|
||||
width: "200px",
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
pageData: {
|
||||
total: 0
|
||||
},
|
||||
selectRows: []
|
||||
};
|
||||
|
||||
const showTable = ref(false);
|
||||
onMounted(async () => {
|
||||
//初始化数据原
|
||||
|
||||
showTable.value = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { fa } from "element-plus/es/locales.mjs";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { getenum } from "@/api/enum";
|
||||
import { ruleRequired, ruleRequiredNumber } from "@/utils/rules";
|
||||
import { ImportExamInfo } from "@/api/exam";
|
||||
import { ElMessage } from "element-plus";
|
||||
const ControllerName = "Exam";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
function searchCallback(data) {}
|
||||
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||
const tableData: TableConfig = {
|
||||
apiUrl: ControllerName,
|
||||
selectColumn: false, // 列表选择
|
||||
border: false, // 是否显示表格边框
|
||||
searchCallback: searchCallback,
|
||||
search: {
|
||||
// 查询条件
|
||||
show: true,
|
||||
PageIndex: 0,
|
||||
PageSize: 20,
|
||||
OrderBy: "Id", // 排序
|
||||
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
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
show: true,
|
||||
label: "详情",
|
||||
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||
btnStyle: "primary",
|
||||
custom: {
|
||||
title: "考试班级详情", // 弹出框title
|
||||
src: "exam/classDetails", // 组件路径
|
||||
width: "1300px", // 弹框宽度
|
||||
height: "800px" // 弹框高度
|
||||
}
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
show: true,
|
||||
label: "录入成绩",
|
||||
click: entryExam,
|
||||
btnStyle: "primary" // topBtn: true才生效 success danger
|
||||
}
|
||||
],
|
||||
column: {
|
||||
// 行数据
|
||||
id: {
|
||||
label: "编号",
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false, // 字段允许修改
|
||||
width: "150px"
|
||||
},
|
||||
name: {
|
||||
label: "考试名称",
|
||||
rules: ruleRequired,
|
||||
width: "200px",
|
||||
search: true,
|
||||
searchType: ConditionalType.Like, // 搜索类型
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
setting: {}
|
||||
},
|
||||
level: {
|
||||
label: "年级",
|
||||
rules: ruleRequired,
|
||||
width: "100px",
|
||||
type: "dropdown",
|
||||
setting: {},
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
testPaperType: {
|
||||
label: "试卷类型",
|
||||
rules: ruleRequired,
|
||||
width: "100px",
|
||||
type: "dropdown",
|
||||
setting: {},
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
type: {
|
||||
label: "考试类型",
|
||||
rules: ruleRequired,
|
||||
width: "100px",
|
||||
type: "dropdown",
|
||||
setting: {},
|
||||
search: true,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
scoreLine: {
|
||||
label: "划线分数",
|
||||
rules: ruleRequiredNumber,
|
||||
search: true,
|
||||
width: "100px",
|
||||
setting: {},
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
startTime: {
|
||||
label: "考试时间",
|
||||
width: "210px",
|
||||
rules: ruleRequired,
|
||||
search: true,
|
||||
type: "datetime",
|
||||
setting: {},
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
createTime: {
|
||||
label: "创建时间",
|
||||
type: "datetime",
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
pageData: {
|
||||
total: 0
|
||||
},
|
||||
selectRows: []
|
||||
};
|
||||
function entryExam(obj, row, callBack) {
|
||||
let fileE = document.createElement("input");
|
||||
fileE.type = "file";
|
||||
var formData = new window.FormData();
|
||||
fileE.onchange = async function () {
|
||||
formData.append("File", fileE.files[0]);
|
||||
let res = await ImportExamInfo(row[0].id, fileE.files[0]);
|
||||
if (res.code != undefined) {
|
||||
if (res.code !== 200) return ElMessage.error(res.message);
|
||||
else return ElMessage.success("所有数据录入成功");
|
||||
} else if (res.type === "application/json") {
|
||||
let json = await res.text();
|
||||
if (json !== undefined && json.Code !== 200) {
|
||||
return ElMessage.error(json.Message);
|
||||
} else {
|
||||
return ElMessage.success("操所有数据录入成功作成功");
|
||||
}
|
||||
} else if (res === undefined || res.size === 0)
|
||||
return ElMessage.success("所有数据录入成功");
|
||||
const url = res && window.URL.createObjectURL(res);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.setAttribute("download", "未成功导入的考试信息数据" + ".xlsx");
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
ElMessage.success("操作成功,已导出重复数据");
|
||||
};
|
||||
|
||||
try {
|
||||
fileE.click();
|
||||
} catch (error) {}
|
||||
}
|
||||
const showTable = ref(false);
|
||||
onMounted(async () => {
|
||||
//初始化数据原
|
||||
|
||||
tableData.column.level.setting.datasource = (await getenum("GradeEnum")).data;
|
||||
|
||||
tableData.column.testPaperType.setting.datasource = (
|
||||
await getenum("TestPaperTypeEnum")
|
||||
).data;
|
||||
tableData.column.type.setting.datasource = (
|
||||
await getenum("ExamTypeEnum")
|
||||
).data;
|
||||
|
||||
showTable.value = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { fa } from "element-plus/es/locales.mjs";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { getenum } from "@/api/enum";
|
||||
import { ruleRequired, ruleRequiredNumber } from "@/utils/rules";
|
||||
const ControllerName = "ExamUserInfo";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
data: any;
|
||||
}>();
|
||||
|
||||
function searchCallback(data) {}
|
||||
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||
const tableData: TableConfig = {
|
||||
apiUrl: ControllerName,
|
||||
selectColumn: false, // 列表选择
|
||||
border: false, // 是否显示表格边框
|
||||
searchCallback: searchCallback,
|
||||
search: {
|
||||
// 查询条件
|
||||
show: true,
|
||||
PageIndex: 0,
|
||||
PageSize: 20,
|
||||
OrderBy: "Id", // 排序
|
||||
defaultConditions: [], // 默认查询条件
|
||||
Conditions: []
|
||||
},
|
||||
operationColumn: true, // 显示操作按钮
|
||||
operationColumnData: [
|
||||
{
|
||||
// 操作按钮
|
||||
topBtn: true, // 是头部按钮
|
||||
label: "成绩升序",
|
||||
btnStyle: "primary"
|
||||
},
|
||||
{
|
||||
// 操作按钮
|
||||
topBtn: true, // 是头部按钮
|
||||
label: "成绩降序",
|
||||
btnStyle: "primary"
|
||||
},
|
||||
{
|
||||
topBtn: false, // 头部按钮
|
||||
label: "个人详情",
|
||||
btnType: "custom",
|
||||
btnStyle: "primary" // topBtn: true才生效 success danger
|
||||
}
|
||||
],
|
||||
column: {
|
||||
// 行数据
|
||||
userName: {
|
||||
label: "姓名",
|
||||
search: true,
|
||||
searchType: ConditionalType.Like, // 搜索类型
|
||||
width: "180px"
|
||||
},
|
||||
语文: {
|
||||
label: "语文",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.语文
|
||||
},
|
||||
数学: {
|
||||
label: "数学",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.数学
|
||||
},
|
||||
英语: {
|
||||
label: "英语",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.英语
|
||||
},
|
||||
物理: {
|
||||
label: "物理",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.物理
|
||||
},
|
||||
化学: {
|
||||
label: "化学",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.化学
|
||||
},
|
||||
生物: {
|
||||
label: "生物",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.生物
|
||||
},
|
||||
政治: {
|
||||
label: "政治",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.政治
|
||||
},
|
||||
历史: {
|
||||
label: "历史",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.历史
|
||||
},
|
||||
地理: {
|
||||
label: "地理",
|
||||
search: false,
|
||||
width: "100px",
|
||||
custom: row => row.subjectDic.地理 ?? "--"
|
||||
},
|
||||
assignScore: {
|
||||
label: "赋分总分",
|
||||
search: false,
|
||||
width: "180px"
|
||||
},
|
||||
assignRanking: {
|
||||
label: "赋分后的排名",
|
||||
search: false,
|
||||
width: "200px"
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
pageData: {
|
||||
total: 0
|
||||
},
|
||||
selectRows: []
|
||||
};
|
||||
|
||||
const showTable = ref(false);
|
||||
onMounted(async () => {
|
||||
//初始化数据原
|
||||
|
||||
showTable.value = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref } 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";
|
||||
const ControllerName = "Grade";
|
||||
|
||||
defineOptions({
|
||||
name: ControllerName
|
||||
});
|
||||
|
||||
const SchoolApi = new hTableAPI("usercenter/back/schools");
|
||||
function searchCallback(data) {}
|
||||
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||
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"
|
||||
},
|
||||
schoolId: {
|
||||
label: "学校",
|
||||
rules: ruleRequired,
|
||||
width: "200px",
|
||||
search: true,
|
||||
type: "dropdown",
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
setting: {}
|
||||
},
|
||||
name: {
|
||||
label: "名称[动态]",
|
||||
rules: ruleRequired,
|
||||
width: "100px",
|
||||
search: false,
|
||||
searchType: ConditionalType.Like,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
level: {
|
||||
label: "年级",
|
||||
rules: ruleRequired,
|
||||
width: "80px",
|
||||
type: "dropdown",
|
||||
search: true,
|
||||
setting: {},
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
year: {
|
||||
label: "毕业届",
|
||||
width: "80px",
|
||||
rules: ruleRequired,
|
||||
search: true,
|
||||
setting: {},
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
createTime: {
|
||||
label: "创建时间",
|
||||
type: "datetime",
|
||||
search: true,
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
pageData: {
|
||||
total: 0
|
||||
},
|
||||
selectRows: []
|
||||
};
|
||||
|
||||
const showTable = ref(false);
|
||||
onMounted(async () => {
|
||||
//初始化数据原
|
||||
|
||||
tableData.column.level.setting.datasource = (
|
||||
await getenum("GradeLevelEnum")
|
||||
).data;
|
||||
|
||||
tableData.column.schoolId.setting.datasource = (
|
||||
await SchoolApi.querycombo({ TextName: "Name", ValueName: "Id" })
|
||||
).data;
|
||||
|
||||
showTable.value = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||
</template>
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
class="menu-tree"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div v-if="!data.isButton" class="menu-node">
|
||||
<div class="menu-node">
|
||||
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
||||
<span class="menu-title">{{ data.title }}</span>
|
||||
|
|
@ -36,7 +37,27 @@
|
|||
<el-button type="primary" link @click="() => showDialog(data)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="danger" link @click="() => {}"> 删除 </el-button>
|
||||
<el-button type="danger" link @click.stop="() => delMenu(data.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="menu-node" style="background-color: #f7f7f7">
|
||||
<div>
|
||||
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
||||
<span>菜单按钮权限: </span>
|
||||
<el-button type="primary">
|
||||
{{ data.title }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div style="display: flex; gap: 6px">
|
||||
<el-button type="primary" link @click="() => showDialog(data)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="danger" link @click.stop="() => delMenu(data.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
|
@ -57,7 +78,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MenuAll, MenuItem } from "@/api/menu";
|
||||
import { MenuAll, MenuItem, Del } from "@/api/menu";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
import MenuEdit from "./edit.vue";
|
||||
|
|
@ -90,6 +111,23 @@ const handleClose = (done: () => void) => {
|
|||
// });
|
||||
};
|
||||
|
||||
async function delMenu(menuId: number) {
|
||||
try {
|
||||
await ElMessageBox.confirm("确定要删除此菜单?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
});
|
||||
const res = await Del([menuId]);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(res.message);
|
||||
await fetchInitData();
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
// 将扁平数据转换为树形结构
|
||||
const convertToTree = (menus: MenuItem[]): MenuItem[] => {
|
||||
const menuMap = new Map<number, MenuItem>();
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { hasAuth, getAuths } from "@/router/utils";
|
||||
|
||||
defineOptions({
|
||||
name: "PermissionButtonRouter"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="mb-2!">当前拥有的code列表:{{ getAuths() }}</p>
|
||||
|
||||
<el-card shadow="never" class="mb-2">
|
||||
<template #header>
|
||||
<div class="card-header">组件方式判断权限</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<Auth value="permission:btn:add">
|
||||
<el-button plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
</Auth>
|
||||
<Auth :value="['permission:btn:edit']">
|
||||
<el-button plain type="primary">
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
</Auth>
|
||||
<Auth
|
||||
:value="[
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
]"
|
||||
>
|
||||
<el-button plain type="danger">
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</Auth>
|
||||
</el-space>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-2">
|
||||
<template #header>
|
||||
<div class="card-header">函数方式判断权限</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<el-button v-if="hasAuth('permission:btn:add')" plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
<el-button v-if="hasAuth(['permission:btn:edit'])" plain type="primary">
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="
|
||||
hasAuth([
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
])
|
||||
"
|
||||
plain
|
||||
type="danger"
|
||||
>
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</el-space>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
指令方式判断权限(该方式不能动态修改权限)
|
||||
</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<el-button v-auth="'permission:btn:add'" plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
<el-button v-auth="['permission:btn:edit']" plain type="primary">
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
<el-button
|
||||
v-auth="[
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
]"
|
||||
plain
|
||||
type="danger"
|
||||
>
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</el-space>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { hasPerms } from "@/utils/auth";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
|
||||
const { permissions } = useUserStoreHook();
|
||||
|
||||
defineOptions({
|
||||
name: "PermissionButtonLogin"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="mb-2!">当前拥有的code列表:{{ permissions }}</p>
|
||||
<p v-show="permissions?.[0] === '*:*:*'" class="mb-2!">
|
||||
*:*:* 代表拥有全部按钮级别权限
|
||||
</p>
|
||||
|
||||
<el-card shadow="never" class="mb-2">
|
||||
<template #header>
|
||||
<div class="card-header">组件方式判断权限</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<Perms value="permission:btn:add">
|
||||
<el-button plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
</Perms>
|
||||
<Perms :value="['permission:btn:edit']">
|
||||
<el-button plain type="primary">
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
</Perms>
|
||||
<Perms
|
||||
:value="[
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
]"
|
||||
>
|
||||
<el-button plain type="danger">
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</Perms>
|
||||
</el-space>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-2">
|
||||
<template #header>
|
||||
<div class="card-header">函数方式判断权限</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<el-button v-if="hasPerms('permission:btn:add')" plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasPerms(['permission:btn:edit'])"
|
||||
plain
|
||||
type="primary"
|
||||
>
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="
|
||||
hasPerms([
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
])
|
||||
"
|
||||
plain
|
||||
type="danger"
|
||||
>
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</el-space>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
指令方式判断权限(该方式不能动态修改权限)
|
||||
</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<el-button v-perms="'permission:btn:add'" plain type="warning">
|
||||
拥有code:'permission:btn:add' 权限可见
|
||||
</el-button>
|
||||
<el-button v-perms="['permission:btn:edit']" plain type="primary">
|
||||
拥有code:['permission:btn:edit'] 权限可见
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="[
|
||||
'permission:btn:add',
|
||||
'permission:btn:edit',
|
||||
'permission:btn:delete'
|
||||
]"
|
||||
plain
|
||||
type="danger"
|
||||
>
|
||||
拥有code:['permission:btn:add', 'permission:btn:edit',
|
||||
'permission:btn:delete'] 权限可见
|
||||
</el-button>
|
||||
</el-space>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { initRouter } from "@/router/utils";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { type CSSProperties, ref, computed } from "vue";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
||||
defineOptions({
|
||||
name: "PermissionPage"
|
||||
});
|
||||
|
||||
const elStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: "85vw",
|
||||
justifyContent: "start"
|
||||
};
|
||||
});
|
||||
|
||||
const userName = ref(useUserStoreHook()?.userName);
|
||||
|
||||
const options = [
|
||||
{
|
||||
value: "admin",
|
||||
label: "管理员角色"
|
||||
},
|
||||
{
|
||||
value: "common",
|
||||
label: "普通角色"
|
||||
}
|
||||
];
|
||||
|
||||
function onChange() {
|
||||
useUserStoreHook()
|
||||
.loginByUsername({ userName: userName.value, password: "admin123" })
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
storageLocal().removeItem("async-routes");
|
||||
usePermissionStoreHook().clearAllCachePage();
|
||||
initRouter();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="mb-2!">
|
||||
模拟后台根据不同角色返回对应路由,观察左侧菜单变化(管理员角色可查看系统管理菜单、普通角色不可查看系统管理菜单)
|
||||
</p>
|
||||
<el-card shadow="never" :style="elStyle">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>当前角色:{{ userName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-select v-model="userName" class="w-[160px]!" @change="onChange">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -90,8 +90,6 @@
|
|||
</el-switch>
|
||||
</el-form-item>
|
||||
<div style="padding-left: 4rem">
|
||||
创建学校会生成一个默认管理员账号
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<el-form-item>
|
||||
|
|
@ -107,7 +105,8 @@
|
|||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getregion, getcity, getProvince, EditSchool } from "@/api/school";
|
||||
import { getregion, getcity, getProvince } from "@/api/school";
|
||||
import { EditSchool } from "@/api/userCenter";
|
||||
import { ElMessage, FormInstance } from "element-plus";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import ahTable from "@/components/hTable/index.vue";
|
||||
import { TableConfig } from "@/components/hTable/hTable";
|
||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { fa } from "element-plus/es/locales.mjs";
|
||||
defineOptions({
|
||||
|
|
@ -8,19 +8,10 @@ defineOptions({
|
|||
});
|
||||
|
||||
onMounted(() => {});
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
function searchCallback(data) {}
|
||||
const table = ref<{ initTable: (config: TableConfig) => void }>(null);
|
||||
const tableData: TableConfig = {
|
||||
apiUrl: "School",
|
||||
apiUrl: "usercenter/back/schools",
|
||||
selectColumn: false, // 列表选择
|
||||
border: false, // 是否显示表格边框
|
||||
searchCallback: searchCallback,
|
||||
|
|
@ -75,7 +66,7 @@ const tableData: TableConfig = {
|
|||
label: "学校名称",
|
||||
width: "300px",
|
||||
search: true,
|
||||
searchType: "Like",
|
||||
searchType: ConditionalType.Like,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
},
|
||||
|
|
@ -84,21 +75,16 @@ const tableData: TableConfig = {
|
|||
width: "300px",
|
||||
search: true,
|
||||
custom: row => `${row.pname}-${row.cname}-${row.rname}`,
|
||||
add: true, // 字段允许添加
|
||||
edit: true // 字段允许修改
|
||||
add: false, // 字段允许添加
|
||||
edit: false // 字段允许修改
|
||||
},
|
||||
enable: {
|
||||
label: "启用",
|
||||
type: "dropdown",
|
||||
type: "switch",
|
||||
search: true,
|
||||
custom: row => (row.enable ? "启用" : "禁用"),
|
||||
add: true, // 字段允许添加
|
||||
edit: true, // 字段允许修改
|
||||
setting: {
|
||||
datasource: [
|
||||
{ value: "true", text: "√" },
|
||||
{ value: "false", text: "X" }
|
||||
]
|
||||
}
|
||||
edit: true // 字段允许修改
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,555 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form
|
||||
ref="userEditForm"
|
||||
:model="form"
|
||||
:label-width="formLabelWidth"
|
||||
clearable
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账号:" prop="Account">
|
||||
<el-input
|
||||
type="text"
|
||||
v-model="form.account"
|
||||
autocomplete="off"
|
||||
minlength="6"
|
||||
maxlength="33"
|
||||
:show-word-limit="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="电话号码" :rules="rulePhone" prop="phone">
|
||||
<el-input type="text" v-model="form.phone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="姓名:" prop="realName" :rules="ruleRequired">
|
||||
<el-input
|
||||
type="text"
|
||||
v-model="form.realName"
|
||||
autocomplete="off"
|
||||
maxlength="20"
|
||||
:show-word-limit="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属云校" prop="cloudSchoolId">
|
||||
<el-select
|
||||
v-model="form.cloudSchoolId"
|
||||
filterable
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in CloudSchoolArr"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-show="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<div style="display: flex; gap: 10px">
|
||||
<label for="Level" class="el-form-item__label" style="width: 120px"
|
||||
>新高考:</label
|
||||
>
|
||||
<el-select
|
||||
v-model="form.gLSubject"
|
||||
filterable
|
||||
placeholder="历史/地理"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject1"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.gSubject1"
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject2"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.gSubject2"
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject2"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="学生层次:" prop="level">
|
||||
<el-radio-group v-model="form.subjectLevel.Level">
|
||||
<el-radio
|
||||
v-for="(item, i) in userLevelList"
|
||||
:key="i"
|
||||
:label="item.value"
|
||||
>{{ item.text }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="科目层次:">
|
||||
<ul class="userform_ul">
|
||||
<li
|
||||
v-for="(value, i) in getUserSubjectLevel(form.subjectLevel)"
|
||||
:key="i"
|
||||
>
|
||||
{{ userLevel2subject(value[0]) }}:
|
||||
<el-radio-group v-model="form.subjectLevel[value[0]]">
|
||||
<el-radio
|
||||
v-for="(level, j) in userLevelList"
|
||||
:key="j"
|
||||
:label="level.value"
|
||||
>{{ level.text }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</li>
|
||||
</ul>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12"> </el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="职位:" prop="positionIds" :rules="ruleRequired">
|
||||
<el-button type="success" @click="CheckPosition()"
|
||||
>分配职位</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div
|
||||
v-for="(position, index) in positionList"
|
||||
:key="index"
|
||||
style="padding-left: 120px; padding-bottom: 20px"
|
||||
>
|
||||
<div class="subjectTagEnableDiv" v-if="position.enable === false">
|
||||
<el-tag type="info">{{ "禁用" }}</el-tag>
|
||||
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.className || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.subjectName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.name || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.endTime }}</el-tag>
|
||||
</div>
|
||||
<div class="subjectTagEnableDiv" v-else>
|
||||
<el-tag>{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="warning">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="success">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="primary" class="classTag">{{
|
||||
position.className || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info" class="subjectTag">{{
|
||||
position.subjectName || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="handleSubmitForm()"
|
||||
>立即提交</el-button
|
||||
>
|
||||
<el-button @click="handleResetForm()">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-container">
|
||||
<el-dialog
|
||||
v-if="dialog.visible"
|
||||
ref="PositionCheckFromDialog"
|
||||
:title="dialog.title"
|
||||
v-model="dialog.visible"
|
||||
:width="dialog.width"
|
||||
:close-on-click-modal="dialog.close"
|
||||
:close-on-press-escape="dialog.close"
|
||||
append-to-body
|
||||
>
|
||||
<PositionForm
|
||||
:userType="form.userType"
|
||||
:positions="PositionFormIds"
|
||||
@handleCheckCallback="handleCheckCallback"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import {} from "@/api/user";
|
||||
import {
|
||||
cloudSchoolCombo,
|
||||
getUserInfo,
|
||||
editUser,
|
||||
Position
|
||||
} from "@/api/userCenter";
|
||||
import PositionForm from "../teacher/positionForm.vue";
|
||||
import { getenum, getenumDic } from "@/api/enum";
|
||||
import { ruleRequired, rulePhone } from "@/utils/rules";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
interface FormData {
|
||||
id: number;
|
||||
account: string;
|
||||
userType: number;
|
||||
level: number;
|
||||
passWord: string;
|
||||
realName: string;
|
||||
studentId: string;
|
||||
templateId: number;
|
||||
phone: string | number;
|
||||
cloudSchoolId: number;
|
||||
subjectLevels: any[];
|
||||
subjectLevel: Record<string, any>;
|
||||
positionIds: number[];
|
||||
positionFormIds?: number[];
|
||||
gLSubject?: number;
|
||||
gSubject1?: number;
|
||||
gSubject2?: number;
|
||||
idCard?: string;
|
||||
pointPenSN?: string;
|
||||
}
|
||||
|
||||
interface DialogConfig {
|
||||
close: boolean;
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
}
|
||||
defineOptions({
|
||||
name: "UserEditForm"
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
id: number;
|
||||
}>();
|
||||
|
||||
const formLabelWidth = "120px";
|
||||
const size = "small";
|
||||
const loading = ref(false);
|
||||
|
||||
const subject1 = ref<ComboModel[]>([
|
||||
{ value: 4, text: "物理" },
|
||||
{ value: 8, text: "历史" }
|
||||
]);
|
||||
|
||||
const subject2 = ref<ComboModel[]>([
|
||||
{ value: 5, text: "化学" },
|
||||
{ value: 6, text: "生物" },
|
||||
{ value: 9, text: "地理" },
|
||||
{ value: 7, text: "政治" }
|
||||
]);
|
||||
|
||||
const userTypeList = ref<ComboModel[]>([]);
|
||||
const userLevelList = ref<ComboModel[]>([]);
|
||||
const subjectLEnum = ref<Record<string, string>>({});
|
||||
const positionList = ref<Position[]>([]);
|
||||
const CloudSchoolArr = ref<ComboModel[]>([]);
|
||||
const Template = ref<any[]>([]);
|
||||
const PositionFormIds = ref<number[]>([]);
|
||||
|
||||
const defaultSubjectLevel = reactive({
|
||||
UserId: 0,
|
||||
Level: 0,
|
||||
Subject1: 0,
|
||||
Subject2: 0,
|
||||
Subject3: 0,
|
||||
Subject4: 0,
|
||||
Subject5: 0,
|
||||
Subject6: 0,
|
||||
Subject7: 0,
|
||||
Subject8: 0,
|
||||
Subject9: 0,
|
||||
CreatePositionId: 1
|
||||
});
|
||||
|
||||
const form = ref<FormData>({
|
||||
id: props.id,
|
||||
account: "",
|
||||
userType: 2,
|
||||
level: 0,
|
||||
passWord: "",
|
||||
realName: "",
|
||||
studentId: "",
|
||||
templateId: 0,
|
||||
phone: "",
|
||||
cloudSchoolId: 0,
|
||||
subjectLevels: [],
|
||||
subjectLevel: { ...defaultSubjectLevel },
|
||||
positionIds: [],
|
||||
positionFormIds: []
|
||||
});
|
||||
|
||||
const dialog = reactive<DialogConfig>({
|
||||
close: false,
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "1200px"
|
||||
});
|
||||
|
||||
const customeRules = reactive({
|
||||
mobile: [
|
||||
{ required: false, message: "手机号必填", trigger: "blur" },
|
||||
{
|
||||
pattern: /^1[3456789]\d{9}$/,
|
||||
message: "手机号码格式不正确",
|
||||
trigger: "blur"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const getUserSubjectLevel = (obj: Record<string, any>) => {
|
||||
if (!obj.id) {
|
||||
form.value.subjectLevel = { ...defaultSubjectLevel };
|
||||
obj = form.value.subjectLevel;
|
||||
}
|
||||
return Object.entries(obj).filter(s => s[0].includes("Subject"));
|
||||
};
|
||||
|
||||
const userLevel2subject = (str: string) => {
|
||||
const name = str.match(/[0-9]+/)?.[0] || "";
|
||||
return subjectLEnum.value[name];
|
||||
};
|
||||
|
||||
const handlePagedCallback = () => {
|
||||
// Emit event to parent if needed
|
||||
};
|
||||
|
||||
const handleSubmitForm = () => {
|
||||
// Form validation and submission logic
|
||||
loading.value = true;
|
||||
const formData = {
|
||||
id: form.value.id || 0,
|
||||
userType: form.value.userType || 1,
|
||||
level: form.value.level || 0,
|
||||
account: form.value.account || "",
|
||||
// PassWord: form.value.id === 0 ? md5(form.value.PassWord).toUpperCase() : "",
|
||||
realName: form.value.realName || "",
|
||||
studentId: form.value.studentId || "",
|
||||
templateId: form.value.templateId || 0,
|
||||
subjectLevels: form.value.subjectLevels || [],
|
||||
subjectLevel: form.value.subjectLevel || { ...defaultSubjectLevel },
|
||||
positionIds: form.value.positionIds || [],
|
||||
gLSubject: form.value.gLSubject,
|
||||
gSubject1: form.value.gSubject1,
|
||||
gSubject2: form.value.gSubject2,
|
||||
idCard: form.value.idCard,
|
||||
cloudSchoolId: form.value.cloudSchoolId,
|
||||
phone: form.value.phone,
|
||||
pointPenSN: form.value.pointPenSN
|
||||
};
|
||||
|
||||
editUser(formData).then(res => {
|
||||
loading.value = false;
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("操作成功");
|
||||
handlePagedCallback();
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
Object.assign(form, {
|
||||
id: props.id,
|
||||
account: "",
|
||||
userType: 1,
|
||||
level: 0,
|
||||
passWord: "",
|
||||
realName: "",
|
||||
studentId: "",
|
||||
subjectLevels: [],
|
||||
subjectLevel: { ...defaultSubjectLevel },
|
||||
positionIds: [],
|
||||
idCard: "",
|
||||
phone: "",
|
||||
cloudSchoolId: "",
|
||||
pointPenSN: ""
|
||||
});
|
||||
positionList.value = [];
|
||||
};
|
||||
|
||||
const fetchInitData = async () => {
|
||||
// 用户层次
|
||||
const levelRes = await getenum("StudentLevelEnum");
|
||||
userLevelList.value = levelRes.data;
|
||||
|
||||
const typeRes = await getenum("UserTypeEnum");
|
||||
userTypeList.value = typeRes.data;
|
||||
|
||||
// 云校
|
||||
const schoolRes = await cloudSchoolCombo();
|
||||
if (schoolRes.code === 200) {
|
||||
CloudSchoolArr.value = schoolRes.data;
|
||||
}
|
||||
|
||||
const enumDicRes = await getenumDic("SubjectEnum");
|
||||
subjectLEnum.value = enumDicRes.data;
|
||||
};
|
||||
|
||||
const fetchFormData = () => {
|
||||
handleResetForm();
|
||||
if (props.id !== 0) {
|
||||
getUserInfo(props.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data.SubjectLevel && res.data.SubjectLevel.CreatePositionId) {
|
||||
delete res.data.SubjectLevel.CreatePositionId;
|
||||
}
|
||||
|
||||
Object.assign(form.value, {
|
||||
id: res.data.id,
|
||||
userType: res.data.userType,
|
||||
level: res.data.level,
|
||||
account: res.data.account,
|
||||
passWord: res.data.passWord,
|
||||
realName: res.data.realName,
|
||||
studentId: res.data.studentId,
|
||||
templateId: res.data.templateId,
|
||||
subjectLevels: res.data.subjectLevels,
|
||||
subjectLevel: res.data.subjectLevel,
|
||||
positionIds: res.data.positions
|
||||
.filter((s: any) => s.enable !== false)
|
||||
.map((w: any) => w.id),
|
||||
gLSubject: res.data.gLSubject,
|
||||
gSubject1: res.data.gSubject1,
|
||||
gSubject2: res.data.gSubject2,
|
||||
idCard: res.data.idCard,
|
||||
phone: res.data.phone,
|
||||
cloudSchoolId: res.data.cloudSchoolId,
|
||||
pointPenSN: res.data.pointPenSN
|
||||
});
|
||||
|
||||
positionList.value = res.data.positions;
|
||||
PositionFormIds.value = res.data.positions
|
||||
.filter((s: any) => s.Enable !== false)
|
||||
.map((s: any) => s.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const userTypeChange = () => {
|
||||
if (form.value.userType === 2) {
|
||||
form.value.studentId = "";
|
||||
}
|
||||
customeRules.mobile[0].required = form.value.userType !== 1;
|
||||
};
|
||||
|
||||
const CheckPosition = () => {
|
||||
dialog.title = "选择职位";
|
||||
dialog.visible = true;
|
||||
PositionFormIds.value = positionList.value
|
||||
.filter(s => s.enable !== false)
|
||||
.map(s => s.id);
|
||||
};
|
||||
|
||||
const handleCheckCallback = (checkPosition: Position[]) => {
|
||||
dialog.visible = false;
|
||||
positionList.value = checkPosition;
|
||||
form.value.positionIds = positionList.value.map(w => w.id);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchInitData();
|
||||
fetchFormData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.userform_ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.userform_ul li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subjectTagEnableDiv {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.subjectTagEnableDiv .el-tag {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.classTag {
|
||||
background-color: #409eff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.subjectTag {
|
||||
background-color: #909399;
|
||||
color: white;
|
||||
}
|
||||
.classTag {
|
||||
color: #a3bf08 !important;
|
||||
background-color: #f4fbd1 !important;
|
||||
border-color: #f4fbd1 !important;
|
||||
}
|
||||
.subjectTagEnableDiv {
|
||||
padding: 1px;
|
||||
}
|
||||
.subjectTag {
|
||||
color: #eb0de4 !important;
|
||||
background-color: #fbd9ff !important;
|
||||
border-color: #fbd9ff !important;
|
||||
}
|
||||
|
||||
.userform_ul {
|
||||
list-style: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,855 @@
|
|||
<template>
|
||||
<div class="app-container" style="padding: 5px">
|
||||
<div class="search-container" style="padding-top: 5px">
|
||||
<!-- 搜索项目 -->
|
||||
<el-form :inline="true" :model="search">
|
||||
<el-form-item>
|
||||
<el-input v-model="search.searchStr" placeholder="姓名/账号/学号" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.userType"
|
||||
placeholder="用户类型"
|
||||
clearable
|
||||
filterable
|
||||
@change="userTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userTypeList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item v-show="search.userType === 1" style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.level"
|
||||
placeholder="学生层次"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userLevelList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.schoolId"
|
||||
placeholder="学校"
|
||||
clearable
|
||||
filterable
|
||||
@change="schoolChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in schoolList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.grade"
|
||||
placeholder="年级"
|
||||
clearable
|
||||
filterable
|
||||
@change="gradeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gradeList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.classId"
|
||||
placeholder="班级"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in classList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.subjectId"
|
||||
placeholder="科目"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in subjectList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleReloadPaged" :icon="Search"
|
||||
>查询</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="selectUser">
|
||||
<el-button
|
||||
type="success"
|
||||
@click="selectUserCallBack()"
|
||||
icon="el-icon-check"
|
||||
>选择用户</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="toolbar-container" v-show="!selectUser">
|
||||
<!-- 按钮组 -->
|
||||
<el-button type="success" @click="importData">导入用户</el-button>
|
||||
<el-button type="default" @click="downLoadImportUsersTemplate"
|
||||
>下载导入用户模板</el-button
|
||||
>
|
||||
<el-button title="根据当前筛选条件导出" type="success" @click="exportUser"
|
||||
>导出用户</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="toolbar-container" v-show="!selectUser">
|
||||
<!-- 按钮组 -->
|
||||
<el-button type="success" @click="AddDialog" plain>新增</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
@row-dblclick="setCurrent"
|
||||
@row-click="selectUserClick"
|
||||
ref="selectUserTable"
|
||||
:data="table.data"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
:max-height="maxTableHeight"
|
||||
>
|
||||
<!-- <el-table-column type="selection" width="40" /> -->
|
||||
<el-table-column label="操作" width="100">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" @click="EditDialog(scope.row)" plain
|
||||
>修改</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="id" label="用户Id" width="100" />
|
||||
<el-table-column label="用户信息" width="200">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="getUserTypeTag(scope.row.userType)"
|
||||
style="margin-right: 5px"
|
||||
>{{
|
||||
userTypeList.find(s => s.value == scope.row.userType)?.text
|
||||
}}</el-tag
|
||||
>
|
||||
<span>{{ scope.row.realName }} </span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="account" label="账号" width="120" />
|
||||
<el-table-column prop="phone" label="手机号" width="120" />
|
||||
|
||||
<!-- <el-table-column prop="studentId" label="学号" width="120" />
|
||||
<el-table-column prop="gKSubject" label="新高考学科" width="150" /> -->
|
||||
|
||||
<el-table-column label="所属班级">
|
||||
<template #default="scope">
|
||||
<div
|
||||
v-for="(position, index) in scope.row.positions"
|
||||
:key="'Position' + index"
|
||||
v-show="
|
||||
index < 3 || (index >= 3 && showAllPosition.includes(scope.row))
|
||||
"
|
||||
>
|
||||
<div v-if="position.enable === false">
|
||||
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.className || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
<div class="subjectTagEnableDiv" v-else>
|
||||
<el-tag>{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="warning">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="success">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="primary" class="classTag">{{
|
||||
position.className || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
scope.row.positions != undefined && scope.row.positions.length > 3
|
||||
"
|
||||
@click="showPosition(scope.row)"
|
||||
class="userTagRow"
|
||||
>
|
||||
<el-icon
|
||||
title="折叠职位"
|
||||
class="userTagRowItop"
|
||||
v-if="showAllPosition.includes(scope.row)"
|
||||
><ArrowDownBold
|
||||
/></el-icon>
|
||||
<el-icon v-else title="展开更多职位"><ArrowDownBold /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
@size-change="pageSizeChange"
|
||||
@current-change="pageIndexChange"
|
||||
:current-page="pagination.total + 1"
|
||||
:page-sizes="[10, 20, 40, 80, 100]"
|
||||
:page-size="pagination.size"
|
||||
layout="prev, pager, next,sizes, total"
|
||||
:total="pagination.total"
|
||||
/>
|
||||
<div class="dialog-container">
|
||||
<el-dialog
|
||||
v-if="dialog.update.visible"
|
||||
ref="UserEditFromDialog"
|
||||
:title="dialog.update.title"
|
||||
v-model="dialog.update.visible"
|
||||
:width="dialog.update.width"
|
||||
:close-on-click-modal="dialog.close"
|
||||
:close-on-press-escape="dialog.close"
|
||||
append-to-body
|
||||
>
|
||||
<UserForm :id="editId" @handlePagedCallback="handleAddCallback" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type { UploadProps } from "element-plus";
|
||||
import UserForm from "./edit.vue";
|
||||
|
||||
import {
|
||||
getSchoolData,
|
||||
getClassCombo,
|
||||
getSubjectData,
|
||||
getPageUserList,
|
||||
UserDetail,
|
||||
Position
|
||||
} from "@/api/userCenter";
|
||||
import { getenum } from "@/api/enum";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { text } from "stream/consumers";
|
||||
import {
|
||||
Check,
|
||||
Delete,
|
||||
Edit,
|
||||
Message,
|
||||
ArrowDownBold,
|
||||
Search,
|
||||
Star
|
||||
} from "@element-plus/icons-vue";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
const classAPI = new hTableAPI("usercenter/back/classes");
|
||||
const schoolsAPI = new hTableAPI("usercenter/back/schools");
|
||||
|
||||
interface SearchParams {
|
||||
searchStr: string;
|
||||
userType: string | number;
|
||||
level: string | number;
|
||||
schoolId: string | number;
|
||||
graduationYear: string | number;
|
||||
grade: string;
|
||||
classId: string | number;
|
||||
subjectId: string | number;
|
||||
positionId: string | number;
|
||||
}
|
||||
|
||||
interface TableData {
|
||||
data: UserDetail[];
|
||||
selectRows: UserDetail[];
|
||||
sort: string;
|
||||
border: boolean;
|
||||
}
|
||||
|
||||
interface PaginationData {
|
||||
index: number;
|
||||
size: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface DialogData {
|
||||
close: boolean;
|
||||
update: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
editLevel: {
|
||||
userIds: number[];
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
editSubjectLevel: {
|
||||
userIds: number[];
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
bindUser: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
height: string;
|
||||
};
|
||||
userBindInfo: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
height: string;
|
||||
};
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
selectUser: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
selectCallBack: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
maxTableHeight: {
|
||||
type: Number,
|
||||
default: 580
|
||||
},
|
||||
searchData: {
|
||||
type: Object as () => SearchParams,
|
||||
default: undefined
|
||||
}
|
||||
});
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||
const excelImportUsersUrl = `${baseUrl}api/back/users/downloadimportusersexceltemplate`;
|
||||
const excelImportMeetingUrl = `${baseUrl}api/back/users/downloadimportmeetingexceltemplate`;
|
||||
const excelImportOrdersUrl = `${baseUrl}api/back/users/downloadimportordersexceltemplate`;
|
||||
|
||||
const editId = ref(0);
|
||||
const showAllPosition = ref<UserDetail[]>([]);
|
||||
const selectUserTable = ref();
|
||||
|
||||
const search = reactive<SearchParams>({
|
||||
searchStr: "",
|
||||
userType: "",
|
||||
level: "",
|
||||
schoolId: "",
|
||||
graduationYear: "",
|
||||
grade: "",
|
||||
classId: "",
|
||||
subjectId: "",
|
||||
positionId: ""
|
||||
});
|
||||
|
||||
const userTypeList = ref<ComboModel[]>([
|
||||
{ value: 1, text: "学生" },
|
||||
{ value: 2, text: "教师" },
|
||||
{ value: 3, text: "管理员" }
|
||||
]);
|
||||
|
||||
const userLevelList = ref<ComboModel[]>([]);
|
||||
const schoolList = ref<ComboModel[]>([]);
|
||||
const gradeList = ref<ComboModel[]>([
|
||||
{ value: "初一", text: "初一" },
|
||||
{ value: "初二", text: "初二" },
|
||||
{ value: "初三", text: "初三" },
|
||||
{ value: "高一", text: "高一" },
|
||||
{ value: "高二", text: "高二" },
|
||||
{ value: "高三", text: "高三" }
|
||||
]);
|
||||
const classList = ref<ComboModel[]>([]);
|
||||
const subjectList = ref<ComboModel[]>([]);
|
||||
const positionList = ref<any[]>([]);
|
||||
|
||||
const table = reactive<TableData>({
|
||||
data: [],
|
||||
selectRows: [],
|
||||
sort: "",
|
||||
border: true
|
||||
});
|
||||
|
||||
const pagination = reactive<PaginationData>({
|
||||
index: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const dialog = reactive<DialogData>({
|
||||
close: false,
|
||||
update: {
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "800px"
|
||||
},
|
||||
editLevel: {
|
||||
userIds: [],
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "400px"
|
||||
},
|
||||
editSubjectLevel: {
|
||||
userIds: [],
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "450px"
|
||||
},
|
||||
bindUser: {
|
||||
title: "分配权限码",
|
||||
visible: false,
|
||||
width: "1150px",
|
||||
height: ""
|
||||
},
|
||||
userBindInfo: {
|
||||
title: "用户权限码",
|
||||
visible: false,
|
||||
width: "1150px",
|
||||
height: ""
|
||||
}
|
||||
});
|
||||
|
||||
const checkUserBindInfo = () => {
|
||||
if (table.selectRows.length != 1) {
|
||||
ElMessage.warning("请选择一个用户");
|
||||
return;
|
||||
}
|
||||
dialog.userBindInfo.visible = true;
|
||||
};
|
||||
|
||||
const showPosition = (row: UserDetail) => {
|
||||
if (showAllPosition.value.includes(row)) {
|
||||
showAllPosition.value.splice(showAllPosition.value.indexOf(row), 1);
|
||||
} else {
|
||||
showAllPosition.value.push(row);
|
||||
}
|
||||
};
|
||||
|
||||
const codeBindUser = () => {
|
||||
if (table.selectRows.length == 0) {
|
||||
ElMessage.warning("请选择需要分配权限的用户");
|
||||
return;
|
||||
}
|
||||
dialog.bindUser.visible = true;
|
||||
};
|
||||
|
||||
const initSearchData = () => {
|
||||
if (props.searchData !== undefined) {
|
||||
for (const key in props.searchData) {
|
||||
search[key] = props.searchData[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const selectUserClick = (row: UserDetail) => {
|
||||
if (props.selectUser) {
|
||||
selectUserTable.value.toggleRowSelection(row);
|
||||
}
|
||||
};
|
||||
|
||||
const setCurrent = (row: UserDetail) => {
|
||||
selectUserTable.value.toggleRowSelection(row);
|
||||
};
|
||||
|
||||
const selectUserCallBack = () => {
|
||||
const u = table.selectRows;
|
||||
props.selectCallBack(u);
|
||||
selectUserTable.value.clearSelection();
|
||||
};
|
||||
|
||||
const exportUser = async () => {
|
||||
const data = {
|
||||
SearchStr: search.searchStr,
|
||||
UserType: search.userType || 0,
|
||||
Level: search.level || 0,
|
||||
SchoolId: search.schoolId || 0,
|
||||
GraduationYear: search.graduationYear || 0,
|
||||
Grade: search.grade,
|
||||
ClassId: search.classId || 0,
|
||||
SubjectId: search.subjectId || 0,
|
||||
PositionId: search.positionId || 0,
|
||||
PageIndex: pagination.index,
|
||||
PageSize: pagination.size
|
||||
};
|
||||
|
||||
// const res = await exportUserApi(data);
|
||||
// if (res.type === "application/json") {
|
||||
// const json = await readerBlob(res);
|
||||
// if (json !== undefined && json.code !== 200) {
|
||||
// ElMessage.error(json.Message);
|
||||
// }
|
||||
// } else if (res !== undefined && res.size !== 0) {
|
||||
// ElMessage.success("导出成功,下载中🕖请稍等");
|
||||
// const url = window.URL.createObjectURL(res);
|
||||
// const link = document.createElement("a");
|
||||
// link.href = url;
|
||||
// link.setAttribute("download", "导出用户信息.xlsx");
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
// document.body.removeChild(link);
|
||||
// } else {
|
||||
// ElMessage.warning("导出失败,无有效数据");
|
||||
// }
|
||||
};
|
||||
|
||||
const fetchInitData = async () => {
|
||||
schoolList.value = (await getSchoolData()).data;
|
||||
subjectList.value = (await getenum("SubjectEnum")).data;
|
||||
userLevelList.value = (await getenum("StudentLevelEnum")).data;
|
||||
userTypeList.value = (await getenum("UserTypeEnum")).data;
|
||||
};
|
||||
|
||||
const userTypeChange = () => {
|
||||
search.level = "";
|
||||
};
|
||||
|
||||
const schoolChange = () => {
|
||||
search.graduationYear = "";
|
||||
search.grade = "";
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const gradeChange = () => {
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const getClass = () => {
|
||||
const data = {
|
||||
schoolId: search.schoolId || 0,
|
||||
graduationYear: search.graduationYear || 0,
|
||||
grade: search.grade
|
||||
};
|
||||
getClassCombo(data).then(res => {
|
||||
if (res.code === 200) {
|
||||
classList.value = res.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchPagedData = (searchUnUse = false) => {
|
||||
const data = {
|
||||
SearchStr: search.searchStr,
|
||||
UserType: 1, // 只查询学生
|
||||
Level: search.level || 0,
|
||||
SchoolId: search.schoolId || 0,
|
||||
GraduationYear: search.graduationYear || 0,
|
||||
Grade: search.grade,
|
||||
ClassId: search.classId || 0,
|
||||
SubjectId: search.subjectId || 0,
|
||||
PositionId: search.positionId || 0,
|
||||
PageIndex: pagination.index,
|
||||
PageSize: pagination.size,
|
||||
UnUsed: searchUnUse
|
||||
};
|
||||
getPageUserList(data).then(res => {
|
||||
if (res.code === 200) {
|
||||
pagination.total = res.data.total;
|
||||
res.data.data.forEach(item => {
|
||||
if (item.positions) {
|
||||
item.positions = PositionsSort(item.positions);
|
||||
}
|
||||
});
|
||||
table.data = res.data.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection: UserDetail[]) => {
|
||||
table.selectRows = selection;
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
// if (table.selectRows.length === 0) {
|
||||
// ElMessage.warning("未勾选记录");
|
||||
// return;
|
||||
// }
|
||||
// const ids: number[] = [];
|
||||
// table.selectRows.forEach(it => {
|
||||
// ids.push(it.Id);
|
||||
// });
|
||||
// ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?", "提示", {
|
||||
// confirmButtonText: "确定",
|
||||
// cancelButtonText: "取消",
|
||||
// type: "warning"
|
||||
// }).then(() => {
|
||||
// delUser(ids).then(res => {
|
||||
// if (res.code === 200) {
|
||||
// handleReloadPaged();
|
||||
// ElMessage.success("删除成功");
|
||||
// } else {
|
||||
// ElMessage.error(res.Message);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
};
|
||||
|
||||
const handleRestPass = async () => {
|
||||
// if (table.selectRows.length === 0) {
|
||||
// ElMessage.warning("未勾选记录");
|
||||
// } else {
|
||||
// const ids: number[] = [];
|
||||
// table.selectRows.forEach(it => {
|
||||
// ids.push(it.Id);
|
||||
// });
|
||||
// try {
|
||||
// await ElMessageBox.confirm("是否需要重置选中用户的密码?", "提示", {
|
||||
// confirmButtonText: "确定",
|
||||
// cancelButtonText: "取消",
|
||||
// type: "warning"
|
||||
// });
|
||||
// const res = await restUserPass(ids);
|
||||
// if (res.code === 200) {
|
||||
// ElMessage.success("重置成功");
|
||||
// } else {
|
||||
// ElMessage.error("重置失败");
|
||||
// }
|
||||
// } catch (error) {
|
||||
// // User cancelled
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
const getUserTypeTag = (type: number) => {
|
||||
return type === 1 ? "info" : "warning";
|
||||
};
|
||||
|
||||
const getUserLevelTag = (level: number) => {
|
||||
return level === 0
|
||||
? "info"
|
||||
: level === 1
|
||||
? "success"
|
||||
: level === 2
|
||||
? "warning"
|
||||
: "error";
|
||||
};
|
||||
|
||||
const getUserLevelText = (level: number) => {
|
||||
const r = userLevelList.value.filter(w => w.value === level);
|
||||
if (r.length > 0) {
|
||||
return r[0].text;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const PositionsSort = (arr: Position[]) => {
|
||||
arr.sort((a, b) => {
|
||||
if (a.enable === b.enable) {
|
||||
return 0;
|
||||
} else if (a.enable) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
|
||||
const handleReloadPaged = (event?: any, searchUnUse?: boolean) => {
|
||||
pagination.index = 1;
|
||||
table.selectRows = [];
|
||||
fetchPagedData(searchUnUse);
|
||||
};
|
||||
|
||||
function pageSizeChange(o) {
|
||||
pagination.size = o;
|
||||
fetchPagedData();
|
||||
}
|
||||
function pageIndexChange(o) {
|
||||
pagination.index = o - 1;
|
||||
fetchPagedData();
|
||||
}
|
||||
|
||||
const AddDialog = () => {
|
||||
editId.value = 0;
|
||||
dialog.update.title = "添加用户";
|
||||
dialog.update.visible = true;
|
||||
};
|
||||
|
||||
const EditDialog = (row?) => {
|
||||
if (row == null && table.selectRows.length !== 1) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.update.title = "修改用户";
|
||||
editId.value = row != null ? row.id : table.selectRows[0].id;
|
||||
dialog.update.visible = true;
|
||||
};
|
||||
|
||||
const handleAddCallback = () => {
|
||||
dialog.update.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const handleEditLevel = () => {
|
||||
if (table.selectRows.length === 0) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.editLevel.title = "修改学生层次";
|
||||
dialog.editLevel.userIds = table.selectRows.map(w => w.id);
|
||||
dialog.editLevel.visible = true;
|
||||
};
|
||||
|
||||
const handleEditLevelCallback = () => {
|
||||
dialog.editLevel.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const handleEditSubjectLevel = () => {
|
||||
if (table.selectRows.length === 0) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.editSubjectLevel.title = "修改学生科目层次";
|
||||
dialog.editSubjectLevel.userIds = table.selectRows.map(w => w.id);
|
||||
dialog.editSubjectLevel.visible = true;
|
||||
};
|
||||
|
||||
const handleEditSubjectLevelCallback = () => {
|
||||
dialog.editSubjectLevel.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const importData = () => {
|
||||
// const fileE = document.createElement("input");
|
||||
// fileE.type = "file";
|
||||
// const formData = new FormData();
|
||||
// fileE.onchange = async function () {
|
||||
// formData.append("File", fileE.files![0]);
|
||||
// const res = await ImporExportTemplate(formData);
|
||||
// if (res.type === "application/json") {
|
||||
// const json = await readerBlob(res);
|
||||
// if (json !== undefined && json.code !== 200) {
|
||||
// return ElMessage.error(json.Message);
|
||||
// } else {
|
||||
// return ElMessage.success("操作成功,没有重复数据");
|
||||
// }
|
||||
// } else if (res === undefined || res.size === 0) {
|
||||
// ElMessage.success("操作成功,没有重复数据");
|
||||
// return;
|
||||
// }
|
||||
// const url = res && window.URL.createObjectURL(res);
|
||||
// const link = document.createElement("a");
|
||||
// link.href = url;
|
||||
// link.setAttribute("download", "未成功导入的用户.xlsx");
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
// document.body.removeChild(link);
|
||||
// ElMessage.success("操作成功,已导出重复数据");
|
||||
// };
|
||||
// try {
|
||||
// fileE.click();
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
};
|
||||
|
||||
const readerBlob = (data: Blob): Promise<any> => {
|
||||
return new Promise(resolve => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(data, "utf-8");
|
||||
reader.onload = function () {
|
||||
const dd = JSON.parse(reader.result as string);
|
||||
resolve(dd);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const downLoadImportUsersTemplate = () => {
|
||||
window.open(excelImportUsersUrl, "_blank");
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await initSearchData();
|
||||
await fetchInitData();
|
||||
fetchPagedData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.userTagRowItop {
|
||||
transform: rotate(180deg) !important;
|
||||
}
|
||||
|
||||
.userTagRow i {
|
||||
padding-top: 3px;
|
||||
transform: rotate(0deg);
|
||||
font-size: 1.3rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.userTagRow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.subjectTagEnableDiv {
|
||||
display: flex;
|
||||
padding: 3px;
|
||||
gap: 5px;
|
||||
}
|
||||
.classTag {
|
||||
color: #a3bf08 !important;
|
||||
background-color: #f4fbd1 !important;
|
||||
border-color: #f4fbd1 !important;
|
||||
}
|
||||
|
||||
.subjectTag {
|
||||
color: #eb0de4 !important;
|
||||
background-color: #fbd9ff !important;
|
||||
border-color: #fbd9ff !important;
|
||||
}
|
||||
|
||||
.subjectlevel_ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.toolbar-container {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,555 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form
|
||||
ref="userEditForm"
|
||||
:model="form"
|
||||
:label-width="formLabelWidth"
|
||||
clearable
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账号:" prop="Account">
|
||||
<el-input
|
||||
type="text"
|
||||
v-model="form.account"
|
||||
autocomplete="off"
|
||||
minlength="6"
|
||||
maxlength="33"
|
||||
:show-word-limit="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="电话号码" :rules="rulePhone" prop="phone">
|
||||
<el-input type="text" v-model="form.phone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="姓名:" prop="realName" :rules="ruleRequired">
|
||||
<el-input
|
||||
type="text"
|
||||
v-model="form.realName"
|
||||
autocomplete="off"
|
||||
maxlength="20"
|
||||
:show-word-limit="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属云校" prop="cloudSchoolId">
|
||||
<el-select
|
||||
v-model="form.cloudSchoolId"
|
||||
filterable
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in CloudSchoolArr"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-show="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<div style="display: flex; gap: 10px">
|
||||
<label for="Level" class="el-form-item__label" style="width: 120px"
|
||||
>新高考:</label
|
||||
>
|
||||
<el-select
|
||||
v-model="form.gLSubject"
|
||||
filterable
|
||||
placeholder="历史/地理"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject1"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.gSubject1"
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject2"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="form.gSubject2"
|
||||
filterable
|
||||
placeholder="小学科"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in subject2"
|
||||
:key="i"
|
||||
autocomplete="off"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="学生层次:" prop="level">
|
||||
<el-radio-group v-model="form.subjectLevel.Level">
|
||||
<el-radio
|
||||
v-for="(item, i) in userLevelList"
|
||||
:key="i"
|
||||
:label="item.value"
|
||||
>{{ item.text }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="form.userType === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="科目层次:">
|
||||
<ul class="userform_ul">
|
||||
<li
|
||||
v-for="(value, i) in getUserSubjectLevel(form.subjectLevel)"
|
||||
:key="i"
|
||||
>
|
||||
{{ userLevel2subject(value[0]) }}:
|
||||
<el-radio-group v-model="form.subjectLevel[value[0]]">
|
||||
<el-radio
|
||||
v-for="(level, j) in userLevelList"
|
||||
:key="j"
|
||||
:label="level.value"
|
||||
>{{ level.text }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</li>
|
||||
</ul>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12"> </el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="职位:" prop="positionIds" :rules="ruleRequired">
|
||||
<el-button type="success" @click="CheckPosition()"
|
||||
>分配职位</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div
|
||||
v-for="(position, index) in positionList"
|
||||
:key="index"
|
||||
style="padding-left: 120px; padding-bottom: 20px"
|
||||
>
|
||||
<div class="subjectTagEnableDiv" v-if="position.enable === false">
|
||||
<el-tag type="info">{{ "禁用" }}</el-tag>
|
||||
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.className || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.subjectName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.name || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.endTime }}</el-tag>
|
||||
</div>
|
||||
<div class="subjectTagEnableDiv" v-else>
|
||||
<el-tag>{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="warning">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="success">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="primary" class="classTag">{{
|
||||
position.className || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info" class="subjectTag">{{
|
||||
position.subjectName || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="handleSubmitForm()"
|
||||
>立即提交</el-button
|
||||
>
|
||||
<el-button @click="handleResetForm()">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-container">
|
||||
<el-dialog
|
||||
v-if="dialog.visible"
|
||||
ref="PositionCheckFromDialog"
|
||||
:title="dialog.title"
|
||||
v-model="dialog.visible"
|
||||
:width="dialog.width"
|
||||
:close-on-click-modal="dialog.close"
|
||||
:close-on-press-escape="dialog.close"
|
||||
append-to-body
|
||||
>
|
||||
<PositionForm
|
||||
:userType="form.userType"
|
||||
:positions="PositionFormIds"
|
||||
@handleCheckCallback="handleCheckCallback"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import {} from "@/api/user";
|
||||
import {
|
||||
cloudSchoolCombo,
|
||||
getUserInfo,
|
||||
editUser,
|
||||
Position
|
||||
} from "@/api/userCenter";
|
||||
import PositionForm from "./positionForm.vue";
|
||||
import { getenum, getenumDic } from "@/api/enum";
|
||||
import { ruleRequired, rulePhone } from "@/utils/rules";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
interface FormData {
|
||||
id: number;
|
||||
account: string;
|
||||
userType: number;
|
||||
level: number;
|
||||
passWord: string;
|
||||
realName: string;
|
||||
studentId: string;
|
||||
templateId: number;
|
||||
phone: string | number;
|
||||
cloudSchoolId: number;
|
||||
subjectLevels: any[];
|
||||
subjectLevel: Record<string, any>;
|
||||
positionIds: number[];
|
||||
positionFormIds?: number[];
|
||||
gLSubject?: number;
|
||||
gSubject1?: number;
|
||||
gSubject2?: number;
|
||||
idCard?: string;
|
||||
pointPenSN?: string;
|
||||
}
|
||||
|
||||
interface DialogConfig {
|
||||
close: boolean;
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
}
|
||||
defineOptions({
|
||||
name: "UserEditForm"
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
id: number;
|
||||
}>();
|
||||
|
||||
const formLabelWidth = "120px";
|
||||
const size = "small";
|
||||
const loading = ref(false);
|
||||
|
||||
const subject1 = ref<ComboModel[]>([
|
||||
{ value: 4, text: "物理" },
|
||||
{ value: 8, text: "历史" }
|
||||
]);
|
||||
|
||||
const subject2 = ref<ComboModel[]>([
|
||||
{ value: 5, text: "化学" },
|
||||
{ value: 6, text: "生物" },
|
||||
{ value: 9, text: "地理" },
|
||||
{ value: 7, text: "政治" }
|
||||
]);
|
||||
|
||||
const userTypeList = ref<ComboModel[]>([]);
|
||||
const userLevelList = ref<ComboModel[]>([]);
|
||||
const subjectLEnum = ref<Record<string, string>>({});
|
||||
const positionList = ref<Position[]>([]);
|
||||
const CloudSchoolArr = ref<ComboModel[]>([]);
|
||||
const Template = ref<any[]>([]);
|
||||
const PositionFormIds = ref<number[]>([]);
|
||||
|
||||
const defaultSubjectLevel = reactive({
|
||||
UserId: 0,
|
||||
Level: 0,
|
||||
Subject1: 0,
|
||||
Subject2: 0,
|
||||
Subject3: 0,
|
||||
Subject4: 0,
|
||||
Subject5: 0,
|
||||
Subject6: 0,
|
||||
Subject7: 0,
|
||||
Subject8: 0,
|
||||
Subject9: 0,
|
||||
CreatePositionId: 1
|
||||
});
|
||||
|
||||
const form = ref<FormData>({
|
||||
id: props.id,
|
||||
account: "",
|
||||
userType: 2,
|
||||
level: 0,
|
||||
passWord: "",
|
||||
realName: "",
|
||||
studentId: "",
|
||||
templateId: 0,
|
||||
phone: "",
|
||||
cloudSchoolId: 0,
|
||||
subjectLevels: [],
|
||||
subjectLevel: { ...defaultSubjectLevel },
|
||||
positionIds: [],
|
||||
positionFormIds: []
|
||||
});
|
||||
|
||||
const dialog = reactive<DialogConfig>({
|
||||
close: false,
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "1200px"
|
||||
});
|
||||
|
||||
const customeRules = reactive({
|
||||
mobile: [
|
||||
{ required: false, message: "手机号必填", trigger: "blur" },
|
||||
{
|
||||
pattern: /^1[3456789]\d{9}$/,
|
||||
message: "手机号码格式不正确",
|
||||
trigger: "blur"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const getUserSubjectLevel = (obj: Record<string, any>) => {
|
||||
if (!obj.id) {
|
||||
form.value.subjectLevel = { ...defaultSubjectLevel };
|
||||
obj = form.value.subjectLevel;
|
||||
}
|
||||
return Object.entries(obj).filter(s => s[0].includes("Subject"));
|
||||
};
|
||||
|
||||
const userLevel2subject = (str: string) => {
|
||||
const name = str.match(/[0-9]+/)?.[0] || "";
|
||||
return subjectLEnum.value[name];
|
||||
};
|
||||
|
||||
const handlePagedCallback = () => {
|
||||
// Emit event to parent if needed
|
||||
};
|
||||
|
||||
const handleSubmitForm = () => {
|
||||
// Form validation and submission logic
|
||||
loading.value = true;
|
||||
const formData = {
|
||||
id: form.value.id || 0,
|
||||
userType: form.value.userType || 1,
|
||||
level: form.value.level || 0,
|
||||
account: form.value.account || "",
|
||||
// PassWord: form.value.id === 0 ? md5(form.value.PassWord).toUpperCase() : "",
|
||||
realName: form.value.realName || "",
|
||||
studentId: form.value.studentId || "",
|
||||
templateId: form.value.templateId || 0,
|
||||
subjectLevels: form.value.subjectLevels || [],
|
||||
subjectLevel: form.value.subjectLevel || { ...defaultSubjectLevel },
|
||||
positionIds: form.value.positionIds || [],
|
||||
gLSubject: form.value.gLSubject,
|
||||
gSubject1: form.value.gSubject1,
|
||||
gSubject2: form.value.gSubject2,
|
||||
idCard: form.value.idCard,
|
||||
cloudSchoolId: form.value.cloudSchoolId,
|
||||
phone: form.value.phone,
|
||||
pointPenSN: form.value.pointPenSN
|
||||
};
|
||||
|
||||
editUser(formData).then(res => {
|
||||
loading.value = false;
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("操作成功");
|
||||
handlePagedCallback();
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
Object.assign(form, {
|
||||
id: props.id,
|
||||
account: "",
|
||||
userType: 1,
|
||||
level: 0,
|
||||
passWord: "",
|
||||
realName: "",
|
||||
studentId: "",
|
||||
subjectLevels: [],
|
||||
subjectLevel: { ...defaultSubjectLevel },
|
||||
positionIds: [],
|
||||
idCard: "",
|
||||
phone: "",
|
||||
cloudSchoolId: "",
|
||||
pointPenSN: ""
|
||||
});
|
||||
positionList.value = [];
|
||||
};
|
||||
|
||||
const fetchInitData = async () => {
|
||||
// 用户层次
|
||||
const levelRes = await getenum("StudentLevelEnum");
|
||||
userLevelList.value = levelRes.data;
|
||||
|
||||
const typeRes = await getenum("UserTypeEnum");
|
||||
userTypeList.value = typeRes.data;
|
||||
|
||||
// 云校
|
||||
const schoolRes = await cloudSchoolCombo();
|
||||
if (schoolRes.code === 200) {
|
||||
CloudSchoolArr.value = schoolRes.data;
|
||||
}
|
||||
|
||||
const enumDicRes = await getenumDic("SubjectEnum");
|
||||
subjectLEnum.value = enumDicRes.data;
|
||||
};
|
||||
|
||||
const fetchFormData = () => {
|
||||
handleResetForm();
|
||||
if (props.id !== 0) {
|
||||
getUserInfo(props.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data.SubjectLevel && res.data.SubjectLevel.CreatePositionId) {
|
||||
delete res.data.SubjectLevel.CreatePositionId;
|
||||
}
|
||||
|
||||
Object.assign(form.value, {
|
||||
id: res.data.id,
|
||||
userType: res.data.userType,
|
||||
level: res.data.level,
|
||||
account: res.data.account,
|
||||
passWord: res.data.passWord,
|
||||
realName: res.data.realName,
|
||||
studentId: res.data.studentId,
|
||||
templateId: res.data.templateId,
|
||||
subjectLevels: res.data.subjectLevels,
|
||||
subjectLevel: res.data.subjectLevel,
|
||||
positionIds: res.data.positions
|
||||
.filter((s: any) => s.enable !== false)
|
||||
.map((w: any) => w.id),
|
||||
gLSubject: res.data.gLSubject,
|
||||
gSubject1: res.data.gSubject1,
|
||||
gSubject2: res.data.gSubject2,
|
||||
idCard: res.data.idCard,
|
||||
phone: res.data.phone,
|
||||
cloudSchoolId: res.data.cloudSchoolId,
|
||||
pointPenSN: res.data.pointPenSN
|
||||
});
|
||||
|
||||
positionList.value = res.data.positions;
|
||||
PositionFormIds.value = res.data.positions
|
||||
.filter((s: any) => s.Enable !== false)
|
||||
.map((s: any) => s.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const userTypeChange = () => {
|
||||
if (form.value.userType === 2) {
|
||||
form.value.studentId = "";
|
||||
}
|
||||
customeRules.mobile[0].required = form.value.userType !== 1;
|
||||
};
|
||||
|
||||
const CheckPosition = () => {
|
||||
dialog.title = "选择职位";
|
||||
dialog.visible = true;
|
||||
PositionFormIds.value = positionList.value
|
||||
.filter(s => s.enable !== false)
|
||||
.map(s => s.id);
|
||||
};
|
||||
|
||||
const handleCheckCallback = (checkPosition: Position[]) => {
|
||||
dialog.visible = false;
|
||||
positionList.value = checkPosition;
|
||||
form.value.positionIds = positionList.value.map(w => w.id);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchInitData();
|
||||
fetchFormData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.userform_ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.userform_ul li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subjectTagEnableDiv {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.subjectTagEnableDiv .el-tag {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.classTag {
|
||||
background-color: #409eff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.subjectTag {
|
||||
background-color: #909399;
|
||||
color: white;
|
||||
}
|
||||
.classTag {
|
||||
color: #a3bf08 !important;
|
||||
background-color: #f4fbd1 !important;
|
||||
border-color: #f4fbd1 !important;
|
||||
}
|
||||
.subjectTagEnableDiv {
|
||||
padding: 1px;
|
||||
}
|
||||
.subjectTag {
|
||||
color: #eb0de4 !important;
|
||||
background-color: #fbd9ff !important;
|
||||
border-color: #fbd9ff !important;
|
||||
}
|
||||
|
||||
.userform_ul {
|
||||
list-style: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,859 @@
|
|||
<template>
|
||||
<div class="app-container" style="padding: 5px">
|
||||
<div class="search-container" style="padding-top: 5px">
|
||||
<!-- 搜索项目 -->
|
||||
<el-form :inline="true" :model="search">
|
||||
<el-form-item>
|
||||
<el-input v-model="search.searchStr" placeholder="姓名/账号/学号" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.userType"
|
||||
placeholder="用户类型"
|
||||
clearable
|
||||
filterable
|
||||
@change="userTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userTypeList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item v-show="search.userType === 1" style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.level"
|
||||
placeholder="学生层次"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userLevelList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.schoolId"
|
||||
placeholder="学校"
|
||||
clearable
|
||||
filterable
|
||||
@change="schoolChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in schoolList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.grade"
|
||||
placeholder="年级"
|
||||
clearable
|
||||
filterable
|
||||
@change="gradeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gradeList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.classId"
|
||||
placeholder="班级"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in classList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 100px">
|
||||
<el-select
|
||||
v-model="search.subjectId"
|
||||
placeholder="科目"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in subjectList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleReloadPaged" :icon="Search"
|
||||
>查询</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="selectUser">
|
||||
<el-button
|
||||
type="success"
|
||||
@click="selectUserCallBack()"
|
||||
icon="el-icon-check"
|
||||
>选择用户</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="toolbar-container" v-show="!selectUser">
|
||||
<!-- 按钮组 -->
|
||||
<el-button type="success" @click="importData">导入用户</el-button>
|
||||
<el-button type="default" @click="downLoadImportUsersTemplate"
|
||||
>下载导入用户模板</el-button
|
||||
>
|
||||
<el-button title="根据当前筛选条件导出" type="success" @click="exportUser"
|
||||
>导出用户</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="toolbar-container" v-show="!selectUser">
|
||||
<!-- 按钮组 -->
|
||||
<el-button type="success" @click="AddDialog" plain>新增</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
@row-dblclick="setCurrent"
|
||||
@row-click="selectUserClick"
|
||||
ref="selectUserTable"
|
||||
:data="table.data"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
:max-height="maxTableHeight"
|
||||
>
|
||||
<!-- <el-table-column type="selection" width="40" /> -->
|
||||
<el-table-column label="操作" width="100">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" @click="EditDialog(scope.row)" plain
|
||||
>修改</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="id" label="用户Id" width="100" />
|
||||
<el-table-column label="用户信息" width="200">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="getUserTypeTag(scope.row.userType)"
|
||||
style="margin-right: 5px"
|
||||
>{{
|
||||
userTypeList.find(s => s.value == scope.row.userType)?.text
|
||||
}}</el-tag
|
||||
>
|
||||
<span>{{ scope.row.realName }} </span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="account" label="账号" width="120" />
|
||||
<el-table-column prop="phone" label="手机号" width="120" />
|
||||
|
||||
<!-- <el-table-column prop="studentId" label="学号" width="120" />
|
||||
<el-table-column prop="gKSubject" label="新高考学科" width="150" /> -->
|
||||
|
||||
<el-table-column label="职位">
|
||||
<template #default="scope">
|
||||
<div
|
||||
v-for="(position, index) in scope.row.positions"
|
||||
:key="'Position' + index"
|
||||
v-show="
|
||||
index < 3 || (index >= 3 && showAllPosition.includes(scope.row))
|
||||
"
|
||||
>
|
||||
<div v-if="position.enable === false">
|
||||
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.className || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.subjectName || "-" }}</el-tag>
|
||||
<el-tag type="info">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
<div class="subjectTagEnableDiv" v-else>
|
||||
<el-tag>{{ position.schoolName || "-" }}</el-tag>
|
||||
<el-tag type="warning">{{
|
||||
position.graduationYear ? position.graduationYear + "届" : "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="success">{{ position.grade || "-" }}</el-tag>
|
||||
<el-tag type="primary" class="classTag">{{
|
||||
position.className || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="info" class="subjectTag">{{
|
||||
position.subjectName || "-"
|
||||
}}</el-tag>
|
||||
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
scope.row.positions != undefined && scope.row.positions.length > 3
|
||||
"
|
||||
@click="showPosition(scope.row)"
|
||||
class="userTagRow"
|
||||
>
|
||||
<el-icon
|
||||
title="折叠职位"
|
||||
class="userTagRowItop"
|
||||
v-if="showAllPosition.includes(scope.row)"
|
||||
><ArrowDownBold
|
||||
/></el-icon>
|
||||
<el-icon v-else title="展开更多职位"><ArrowDownBold /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
@size-change="pageSizeChange"
|
||||
@current-change="pageIndexChange"
|
||||
:current-page="pagination.total + 1"
|
||||
:page-sizes="[10, 20, 40, 80, 100]"
|
||||
:page-size="pagination.size"
|
||||
layout="prev, pager, next,sizes, total"
|
||||
:total="pagination.total"
|
||||
/>
|
||||
<div class="dialog-container">
|
||||
<el-dialog
|
||||
v-if="dialog.update.visible"
|
||||
ref="UserEditFromDialog"
|
||||
:title="dialog.update.title"
|
||||
v-model="dialog.update.visible"
|
||||
:width="dialog.update.width"
|
||||
:close-on-click-modal="dialog.close"
|
||||
:close-on-press-escape="dialog.close"
|
||||
append-to-body
|
||||
>
|
||||
<UserForm :id="editId" @handlePagedCallback="handleAddCallback" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type { UploadProps } from "element-plus";
|
||||
import UserForm from "./edit.vue";
|
||||
|
||||
import {
|
||||
getSchoolData,
|
||||
getClassCombo,
|
||||
getSubjectData,
|
||||
getPageUserList,
|
||||
UserDetail,
|
||||
Position
|
||||
} from "@/api/userCenter";
|
||||
import { getenum } from "@/api/enum";
|
||||
import { hTableAPI } from "@/api/hTable";
|
||||
import { text } from "stream/consumers";
|
||||
import {
|
||||
Check,
|
||||
Delete,
|
||||
Edit,
|
||||
Message,
|
||||
ArrowDownBold,
|
||||
Search,
|
||||
Star
|
||||
} from "@element-plus/icons-vue";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
const classAPI = new hTableAPI("usercenter/back/classes");
|
||||
const schoolsAPI = new hTableAPI("usercenter/back/schools");
|
||||
|
||||
interface SearchParams {
|
||||
searchStr: string;
|
||||
userType: string | number;
|
||||
level: string | number;
|
||||
schoolId: string | number;
|
||||
graduationYear: string | number;
|
||||
grade: string;
|
||||
classId: string | number;
|
||||
subjectId: string | number;
|
||||
positionId: string | number;
|
||||
}
|
||||
|
||||
interface TableData {
|
||||
data: UserDetail[];
|
||||
selectRows: UserDetail[];
|
||||
sort: string;
|
||||
border: boolean;
|
||||
}
|
||||
|
||||
interface PaginationData {
|
||||
index: number;
|
||||
size: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface DialogData {
|
||||
close: boolean;
|
||||
update: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
editLevel: {
|
||||
userIds: number[];
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
editSubjectLevel: {
|
||||
userIds: number[];
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
};
|
||||
bindUser: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
height: string;
|
||||
};
|
||||
userBindInfo: {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
height: string;
|
||||
};
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
selectUser: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
selectCallBack: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
maxTableHeight: {
|
||||
type: Number,
|
||||
default: 580
|
||||
},
|
||||
searchData: {
|
||||
type: Object as () => SearchParams,
|
||||
default: undefined
|
||||
}
|
||||
});
|
||||
|
||||
const baseUrl = import.meta.env.VITE_API_USERCENTER_URL;
|
||||
const excelImportUsersUrl = `${baseUrl}/back/users/downloadimportusersexceltemplate`;
|
||||
const excelImportMeetingUrl = `${baseUrl}/back/users/downloadimportmeetingexceltemplate`;
|
||||
const excelImportOrdersUrl = `${baseUrl}/back/users/downloadimportordersexceltemplate`;
|
||||
|
||||
const editId = ref(0);
|
||||
const showAllPosition = ref<UserDetail[]>([]);
|
||||
const selectUserTable = ref();
|
||||
|
||||
const search = reactive<SearchParams>({
|
||||
searchStr: "",
|
||||
userType: "",
|
||||
level: "",
|
||||
schoolId: "",
|
||||
graduationYear: "",
|
||||
grade: "",
|
||||
classId: "",
|
||||
subjectId: "",
|
||||
positionId: ""
|
||||
});
|
||||
|
||||
const userTypeList = ref<ComboModel[]>([
|
||||
{ value: 1, text: "学生" },
|
||||
{ value: 2, text: "教师" },
|
||||
{ value: 3, text: "管理员" }
|
||||
]);
|
||||
|
||||
const userLevelList = ref<ComboModel[]>([]);
|
||||
const schoolList = ref<ComboModel[]>([]);
|
||||
const gradeList = ref<ComboModel[]>([
|
||||
{ value: "初一", text: "初一" },
|
||||
{ value: "初二", text: "初二" },
|
||||
{ value: "初三", text: "初三" },
|
||||
{ value: "高一", text: "高一" },
|
||||
{ value: "高二", text: "高二" },
|
||||
{ value: "高三", text: "高三" }
|
||||
]);
|
||||
const classList = ref<ComboModel[]>([]);
|
||||
const subjectList = ref<ComboModel[]>([]);
|
||||
const positionList = ref<any[]>([]);
|
||||
|
||||
const table = reactive<TableData>({
|
||||
data: [],
|
||||
selectRows: [],
|
||||
sort: "",
|
||||
border: true
|
||||
});
|
||||
|
||||
const pagination = reactive<PaginationData>({
|
||||
index: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const dialog = reactive<DialogData>({
|
||||
close: false,
|
||||
update: {
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "800px"
|
||||
},
|
||||
editLevel: {
|
||||
userIds: [],
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "400px"
|
||||
},
|
||||
editSubjectLevel: {
|
||||
userIds: [],
|
||||
title: "",
|
||||
visible: false,
|
||||
width: "450px"
|
||||
},
|
||||
bindUser: {
|
||||
title: "分配权限码",
|
||||
visible: false,
|
||||
width: "1150px",
|
||||
height: ""
|
||||
},
|
||||
userBindInfo: {
|
||||
title: "用户权限码",
|
||||
visible: false,
|
||||
width: "1150px",
|
||||
height: ""
|
||||
}
|
||||
});
|
||||
|
||||
const checkUserBindInfo = () => {
|
||||
if (table.selectRows.length != 1) {
|
||||
ElMessage.warning("请选择一个用户");
|
||||
return;
|
||||
}
|
||||
dialog.userBindInfo.visible = true;
|
||||
};
|
||||
|
||||
const showPosition = (row: UserDetail) => {
|
||||
if (showAllPosition.value.includes(row)) {
|
||||
showAllPosition.value.splice(showAllPosition.value.indexOf(row), 1);
|
||||
} else {
|
||||
showAllPosition.value.push(row);
|
||||
}
|
||||
};
|
||||
|
||||
const codeBindUser = () => {
|
||||
if (table.selectRows.length == 0) {
|
||||
ElMessage.warning("请选择需要分配权限的用户");
|
||||
return;
|
||||
}
|
||||
dialog.bindUser.visible = true;
|
||||
};
|
||||
|
||||
const initSearchData = () => {
|
||||
if (props.searchData !== undefined) {
|
||||
for (const key in props.searchData) {
|
||||
search[key] = props.searchData[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const selectUserClick = (row: UserDetail) => {
|
||||
if (props.selectUser) {
|
||||
selectUserTable.value.toggleRowSelection(row);
|
||||
}
|
||||
};
|
||||
|
||||
const setCurrent = (row: UserDetail) => {
|
||||
selectUserTable.value.toggleRowSelection(row);
|
||||
};
|
||||
|
||||
const selectUserCallBack = () => {
|
||||
const u = table.selectRows;
|
||||
props.selectCallBack(u);
|
||||
selectUserTable.value.clearSelection();
|
||||
};
|
||||
|
||||
const exportUser = async () => {
|
||||
const data = {
|
||||
SearchStr: search.searchStr,
|
||||
UserType: search.userType || 0,
|
||||
Level: search.level || 0,
|
||||
SchoolId: search.schoolId || 0,
|
||||
GraduationYear: search.graduationYear || 0,
|
||||
Grade: search.grade,
|
||||
ClassId: search.classId || 0,
|
||||
SubjectId: search.subjectId || 0,
|
||||
PositionId: search.positionId || 0,
|
||||
PageIndex: pagination.index,
|
||||
PageSize: pagination.size
|
||||
};
|
||||
|
||||
// const res = await exportUserApi(data);
|
||||
// if (res.type === "application/json") {
|
||||
// const json = await readerBlob(res);
|
||||
// if (json !== undefined && json.code !== 200) {
|
||||
// ElMessage.error(json.Message);
|
||||
// }
|
||||
// } else if (res !== undefined && res.size !== 0) {
|
||||
// ElMessage.success("导出成功,下载中🕖请稍等");
|
||||
// const url = window.URL.createObjectURL(res);
|
||||
// const link = document.createElement("a");
|
||||
// link.href = url;
|
||||
// link.setAttribute("download", "导出用户信息.xlsx");
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
// document.body.removeChild(link);
|
||||
// } else {
|
||||
// ElMessage.warning("导出失败,无有效数据");
|
||||
// }
|
||||
};
|
||||
|
||||
const fetchInitData = async () => {
|
||||
schoolList.value = (await getSchoolData()).data;
|
||||
subjectList.value = (await getenum("SubjectEnum")).data;
|
||||
userLevelList.value = (await getenum("StudentLevelEnum")).data;
|
||||
userTypeList.value = (await getenum("UserTypeEnum")).data;
|
||||
};
|
||||
|
||||
const userTypeChange = () => {
|
||||
search.level = "";
|
||||
};
|
||||
|
||||
const schoolChange = () => {
|
||||
search.graduationYear = "";
|
||||
search.grade = "";
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const gradeChange = () => {
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const getClass = () => {
|
||||
const data = {
|
||||
schoolId: search.schoolId || 0,
|
||||
graduationYear: search.graduationYear || 0,
|
||||
grade: search.grade
|
||||
};
|
||||
getClassCombo(data).then(res => {
|
||||
if (res.code === 200) {
|
||||
classList.value = res.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchPagedData = (searchUnUse = false) => {
|
||||
const data = {
|
||||
SearchStr: search.searchStr,
|
||||
UserType: 2,
|
||||
Level: search.level || 0,
|
||||
SchoolId: search.schoolId || 0,
|
||||
GraduationYear: search.graduationYear || 0,
|
||||
Grade: search.grade,
|
||||
ClassId: search.classId || 0,
|
||||
SubjectId: search.subjectId || 0,
|
||||
PositionId: search.positionId || 0,
|
||||
PageIndex: pagination.index,
|
||||
PageSize: pagination.size,
|
||||
UnUsed: searchUnUse
|
||||
};
|
||||
getPageUserList(data).then(res => {
|
||||
if (res.code === 200) {
|
||||
pagination.total = res.data.total;
|
||||
res.data.data.forEach(item => {
|
||||
if (item.positions) {
|
||||
item.positions = PositionsSort(item.positions);
|
||||
}
|
||||
});
|
||||
table.data = res.data.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection: UserDetail[]) => {
|
||||
table.selectRows = selection;
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
// if (table.selectRows.length === 0) {
|
||||
// ElMessage.warning("未勾选记录");
|
||||
// return;
|
||||
// }
|
||||
// const ids: number[] = [];
|
||||
// table.selectRows.forEach(it => {
|
||||
// ids.push(it.Id);
|
||||
// });
|
||||
// ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?", "提示", {
|
||||
// confirmButtonText: "确定",
|
||||
// cancelButtonText: "取消",
|
||||
// type: "warning"
|
||||
// }).then(() => {
|
||||
// delUser(ids).then(res => {
|
||||
// if (res.code === 200) {
|
||||
// handleReloadPaged();
|
||||
// ElMessage.success("删除成功");
|
||||
// } else {
|
||||
// ElMessage.error(res.Message);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
};
|
||||
|
||||
const handleRestPass = async () => {
|
||||
// if (table.selectRows.length === 0) {
|
||||
// ElMessage.warning("未勾选记录");
|
||||
// } else {
|
||||
// const ids: number[] = [];
|
||||
// table.selectRows.forEach(it => {
|
||||
// ids.push(it.Id);
|
||||
// });
|
||||
// try {
|
||||
// await ElMessageBox.confirm("是否需要重置选中用户的密码?", "提示", {
|
||||
// confirmButtonText: "确定",
|
||||
// cancelButtonText: "取消",
|
||||
// type: "warning"
|
||||
// });
|
||||
// const res = await restUserPass(ids);
|
||||
// if (res.code === 200) {
|
||||
// ElMessage.success("重置成功");
|
||||
// } else {
|
||||
// ElMessage.error("重置失败");
|
||||
// }
|
||||
// } catch (error) {
|
||||
// // User cancelled
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
const getUserTypeTag = (type: number) => {
|
||||
return type === 1 ? "info" : "warning";
|
||||
};
|
||||
|
||||
const getUserLevelTag = (level: number) => {
|
||||
return level === 0
|
||||
? "info"
|
||||
: level === 1
|
||||
? "success"
|
||||
: level === 2
|
||||
? "warning"
|
||||
: "error";
|
||||
};
|
||||
|
||||
const getUserLevelText = (level: number) => {
|
||||
const r = userLevelList.value.filter(w => w.value === level);
|
||||
if (r.length > 0) {
|
||||
return r[0].text;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const PositionsSort = (arr: Position[]) => {
|
||||
arr.sort((a, b) => {
|
||||
if (a.enable === b.enable) {
|
||||
return 0;
|
||||
} else if (a.enable) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
|
||||
const handleReloadPaged = (event?: any, searchUnUse?: boolean) => {
|
||||
pagination.index = 1;
|
||||
table.selectRows = [];
|
||||
fetchPagedData(searchUnUse);
|
||||
};
|
||||
|
||||
function pageSizeChange(o) {
|
||||
pagination.size = o;
|
||||
fetchPagedData();
|
||||
}
|
||||
function pageIndexChange(o) {
|
||||
pagination.index = o - 1;
|
||||
fetchPagedData();
|
||||
}
|
||||
|
||||
const AddDialog = () => {
|
||||
editId.value = 0;
|
||||
dialog.update.title = "添加用户";
|
||||
dialog.update.visible = true;
|
||||
};
|
||||
|
||||
const EditDialog = (row?) => {
|
||||
if (row == null && table.selectRows.length !== 1) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.update.title = "修改用户";
|
||||
editId.value = row != null ? row.id : table.selectRows[0].id;
|
||||
dialog.update.visible = true;
|
||||
};
|
||||
|
||||
const handleAddCallback = () => {
|
||||
dialog.update.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const handleEditLevel = () => {
|
||||
if (table.selectRows.length === 0) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.editLevel.title = "修改学生层次";
|
||||
dialog.editLevel.userIds = table.selectRows.map(w => w.id);
|
||||
dialog.editLevel.visible = true;
|
||||
};
|
||||
|
||||
const handleEditLevelCallback = () => {
|
||||
dialog.editLevel.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const handleEditSubjectLevel = () => {
|
||||
if (table.selectRows.length === 0) {
|
||||
ElMessage.warning("请选择要修改用户");
|
||||
return;
|
||||
}
|
||||
dialog.editSubjectLevel.title = "修改学生科目层次";
|
||||
dialog.editSubjectLevel.userIds = table.selectRows.map(w => w.id);
|
||||
dialog.editSubjectLevel.visible = true;
|
||||
};
|
||||
|
||||
const handleEditSubjectLevelCallback = () => {
|
||||
dialog.editSubjectLevel.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const importData = () => {
|
||||
// const fileE = document.createElement("input");
|
||||
// fileE.type = "file";
|
||||
// const formData = new FormData();
|
||||
// fileE.onchange = async function () {
|
||||
// formData.append("File", fileE.files![0]);
|
||||
// const res = await ImporExportTemplate(formData);
|
||||
// if (res.type === "application/json") {
|
||||
// const json = await readerBlob(res);
|
||||
// if (json !== undefined && json.code !== 200) {
|
||||
// return ElMessage.error(json.Message);
|
||||
// } else {
|
||||
// return ElMessage.success("操作成功,没有重复数据");
|
||||
// }
|
||||
// } else if (res === undefined || res.size === 0) {
|
||||
// ElMessage.success("操作成功,没有重复数据");
|
||||
// return;
|
||||
// }
|
||||
// const url = res && window.URL.createObjectURL(res);
|
||||
// const link = document.createElement("a");
|
||||
// link.href = url;
|
||||
// link.setAttribute("download", "未成功导入的用户.xlsx");
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
// document.body.removeChild(link);
|
||||
// ElMessage.success("操作成功,已导出重复数据");
|
||||
// };
|
||||
// try {
|
||||
// fileE.click();
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
};
|
||||
|
||||
const readerBlob = (data: Blob): Promise<any> => {
|
||||
return new Promise(resolve => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(data, "utf-8");
|
||||
reader.onload = function () {
|
||||
const dd = JSON.parse(reader.result as string);
|
||||
resolve(dd);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const downLoadImportUsersTemplate = () => {
|
||||
window.open(excelImportUsersUrl, "_blank");
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await initSearchData();
|
||||
await fetchInitData();
|
||||
fetchPagedData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.userTagRowItop {
|
||||
transform: rotate(180deg) !important;
|
||||
}
|
||||
|
||||
.userTagRow i {
|
||||
padding-top: 3px;
|
||||
transform: rotate(0deg);
|
||||
font-size: 1.3rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.userTagRow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.subjectTagEnableDiv {
|
||||
display: flex;
|
||||
padding: 3px;
|
||||
gap: 5px;
|
||||
}
|
||||
.classTag {
|
||||
color: #a3bf08 !important;
|
||||
background-color: #f4fbd1 !important;
|
||||
border-color: #f4fbd1 !important;
|
||||
}
|
||||
|
||||
.subjectTag {
|
||||
color: #eb0de4 !important;
|
||||
background-color: #fbd9ff !important;
|
||||
border-color: #fbd9ff !important;
|
||||
}
|
||||
|
||||
.subjectlevel_ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.toolbar-container {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,522 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div
|
||||
style="color: #606266; font-size: 1.5em; font-weight: bold"
|
||||
v-if="selectionCount == 1"
|
||||
>
|
||||
双击选中职位
|
||||
</div>
|
||||
<h2></h2>
|
||||
<div class="search-container1">
|
||||
<!-- 搜索项目 -->
|
||||
<el-form :inline="true" :model="search">
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.schoolId"
|
||||
placeholder="学校"
|
||||
clearable
|
||||
filterable
|
||||
@change="schoolChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in schoolList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.positionType"
|
||||
placeholder="职位类型"
|
||||
clearable
|
||||
filterable
|
||||
:disabled="userType > 0"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in positionList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.grade"
|
||||
placeholder="年级"
|
||||
clearable
|
||||
filterable
|
||||
@change="gradeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gradeList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.classId"
|
||||
placeholder="班级"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in classList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.subjectId"
|
||||
placeholder="科目"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in subjectList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="search.status"
|
||||
placeholder="状态"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in statusList"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleReloadPaged"
|
||||
icon="el-icon-search"
|
||||
>查询</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="asyncPosition"
|
||||
>选择勾选职位</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- <div class="toolbar-container">
|
||||
<el-button type="success" plain @click="handleAdd"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button type="primary" plain @click="handleEdit"
|
||||
>修改</el-button
|
||||
>
|
||||
</div> -->
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:data="table.data"
|
||||
ref="positionTb"
|
||||
row-key="id"
|
||||
:border="table.border"
|
||||
@row-dblclick="rowDblclick"
|
||||
height="600px"
|
||||
style="width: 768px; max-width: 768px"
|
||||
:expand-row-keys="tableExpandRowKeys"
|
||||
:tree-props="{ children: 'children' }"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="40" />
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="职位名称[双击行快速选择]"
|
||||
width="220"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span
|
||||
>{{ scope.row.name }}
|
||||
<el-tag v-show="selectPositions.find(s => scope.row.Id == s.id)"
|
||||
>已选</el-tag
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="positionLevel" label="职级" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.positionLevel === 1" type="danger"
|
||||
>教委</el-tag
|
||||
>
|
||||
<el-tag v-else-if="scope.row.positionLevel === 2" type="warning"
|
||||
>校级</el-tag
|
||||
>
|
||||
<el-tag v-else-if="scope.row.positionLevel === 3">年级</el-tag>
|
||||
<el-tag v-else-if="scope.row.positionLevel === 4" type="success"
|
||||
>班级</el-tag
|
||||
>
|
||||
<el-tag v-else-if="scope.row.positionLevel === 5" type="info"
|
||||
>教师</el-tag
|
||||
>
|
||||
<el-tag v-else-if="scope.row.positionType === 1" type="info"
|
||||
>学生</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学校 - 年级 - 班级 - 学科">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="!scope.row.status" type="danger">锁定</el-tag>
|
||||
{{ scope.row.schoolName }} {{ scope.row.grade }}
|
||||
{{ scope.row.className }} {{ scope.row.subjectName }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-card class="box-card">
|
||||
<div class="clearfix clearfixCss">
|
||||
<span style="line-height: 32px; font-weight: 600"
|
||||
>已选职位[{{ selectPositions.length }}]</span
|
||||
>
|
||||
<el-button
|
||||
style="float: right"
|
||||
type="success"
|
||||
@click="handleConfirm"
|
||||
icon="el-icon-check"
|
||||
>提交分配职位</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="positionGap">
|
||||
<el-tag
|
||||
v-for="(p, o) in selectPositions"
|
||||
:key="o"
|
||||
closable
|
||||
@close="tagClose(p)"
|
||||
>
|
||||
{{ p.name }} {{ p.schoolName }} {{ p.grade }} {{ p.className }}
|
||||
{{ p.subjectName }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type { FormInstance } from "element-plus";
|
||||
import {
|
||||
getSchoolData,
|
||||
getClassCombo,
|
||||
getSubjectData,
|
||||
getPositionList,
|
||||
getPositions,
|
||||
Position
|
||||
} from "@/api/userCenter";
|
||||
import { ComboModel } from "@/components/hTable/hTable";
|
||||
|
||||
interface SearchParams {
|
||||
schoolId: string | number;
|
||||
positionType: string | number;
|
||||
grade: string;
|
||||
classId: string | number;
|
||||
subjectId: string | number;
|
||||
status: string | number;
|
||||
}
|
||||
|
||||
interface TableData {
|
||||
data: Position[];
|
||||
selectRows: Position[];
|
||||
border: boolean;
|
||||
}
|
||||
|
||||
interface Dialog {
|
||||
id: number;
|
||||
parentPosition: Position | null;
|
||||
close: boolean;
|
||||
title: string;
|
||||
visible: boolean;
|
||||
width: string;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
userType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
positions: {
|
||||
type: Array as () => number[],
|
||||
default: () => []
|
||||
},
|
||||
selectionCount: {
|
||||
type: Number,
|
||||
default: 999
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(["handleCheckCallback", "handleCheckCallback"]);
|
||||
|
||||
const search = reactive<SearchParams>({
|
||||
schoolId: "",
|
||||
positionType: "",
|
||||
grade: "",
|
||||
classId: "",
|
||||
subjectId: "",
|
||||
status: ""
|
||||
});
|
||||
|
||||
const selectPositions = ref<Position[]>([]);
|
||||
const schoolList = ref<ComboModel[]>([]);
|
||||
const gradeList = ref<ComboModel[]>([
|
||||
{ value: "初一", text: "初一" },
|
||||
{ value: "初二", text: "初二" },
|
||||
{ value: "初三", text: "初三" },
|
||||
{ value: "高一", text: "高一" },
|
||||
{ value: "高二", text: "高二" },
|
||||
{ value: "高三", text: "高三" }
|
||||
]);
|
||||
const classList = ref<ComboModel[]>([]);
|
||||
const subjectList = ref<ComboModel[]>([]);
|
||||
const tableExpandRowKeys = ref<string[]>([]);
|
||||
const positionList = ref<ComboModel[]>([
|
||||
{ text: "学生", value: 1 },
|
||||
{ text: "教师", value: 2 },
|
||||
{ text: "管理员", value: 3 }
|
||||
]);
|
||||
const statusList = ref<ComboModel[]>([
|
||||
{ text: "正常", value: 1 },
|
||||
{ text: "锁定", value: 2 }
|
||||
]);
|
||||
|
||||
const table = reactive<TableData>({
|
||||
data: [],
|
||||
selectRows: [],
|
||||
border: true
|
||||
});
|
||||
|
||||
const dialog = reactive<Dialog>({
|
||||
id: 0,
|
||||
parentPosition: null,
|
||||
close: false,
|
||||
title: "编辑职位",
|
||||
visible: false,
|
||||
width: "800px"
|
||||
});
|
||||
|
||||
const authDialog = reactive<Dialog>({
|
||||
id: 0,
|
||||
parentPosition: null,
|
||||
close: false,
|
||||
title: "职位授权",
|
||||
visible: false,
|
||||
width: "400px"
|
||||
});
|
||||
|
||||
const positionTb = ref<FormInstance>();
|
||||
|
||||
const userTypeToPosition = () => {
|
||||
switch (props.userType) {
|
||||
case 1:
|
||||
search.positionType = 1;
|
||||
break;
|
||||
case 2:
|
||||
search.positionType = 2;
|
||||
break;
|
||||
case 15:
|
||||
search.positionType = 3;
|
||||
break;
|
||||
default:
|
||||
search.positionType = -1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const rowDblclick = (row: Position) => {
|
||||
if (props.selectionCount === 1) {
|
||||
emit("handleCheckCallback", [row]);
|
||||
} else {
|
||||
asyncPosition(null, [row]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReloadPaged = () => {
|
||||
fetchPagedData();
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
if (table.selectRows.length > 0) {
|
||||
dialog.parentPosition = table.selectRows[0];
|
||||
dialog.title = `${table.selectRows[0].name}-添加附属职位`;
|
||||
} else {
|
||||
dialog.title = "添加职位";
|
||||
dialog.parentPosition = null;
|
||||
}
|
||||
dialog.id = 0;
|
||||
dialog.visible = true;
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
if (table.selectRows.length === 0) {
|
||||
ElMessage.warning("未勾选记录");
|
||||
return;
|
||||
}
|
||||
if (table.selectRows.length > 1) {
|
||||
ElMessage.warning("当前操作只支持勾选一条记录");
|
||||
return;
|
||||
}
|
||||
dialog.id = table.selectRows[0].id;
|
||||
dialog.parentPosition = null;
|
||||
dialog.title = "编辑职位";
|
||||
dialog.visible = true;
|
||||
};
|
||||
|
||||
const handleRefreshCallback = () => {
|
||||
dialog.visible = false;
|
||||
authDialog.visible = false;
|
||||
handleReloadPaged();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection: Position[]) => {
|
||||
table.selectRows = selection;
|
||||
};
|
||||
|
||||
const fetchInitData = async () => {
|
||||
const schoolRes = await getSchoolData();
|
||||
if (schoolRes.code === 200) {
|
||||
schoolList.value = schoolRes.data;
|
||||
if (schoolList.value.length > 0) {
|
||||
search.schoolId = schoolList.value[0].value;
|
||||
schoolChange();
|
||||
fetchPagedData();
|
||||
}
|
||||
}
|
||||
|
||||
const subjectRes = await getSubjectData();
|
||||
if (subjectRes.code === 200) {
|
||||
subjectList.value = subjectRes.data;
|
||||
}
|
||||
};
|
||||
|
||||
const schoolChange = () => {
|
||||
search.grade = "";
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const gradeChange = () => {
|
||||
search.classId = "";
|
||||
search.subjectId = "";
|
||||
getClass();
|
||||
};
|
||||
|
||||
const getClass = async () => {
|
||||
const data = {
|
||||
schoolId: search.schoolId || 0,
|
||||
grade: search.grade
|
||||
};
|
||||
const res = await getClassCombo(data);
|
||||
if (res.code === 200) {
|
||||
classList.value = res.data;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPagedData = async () => {
|
||||
const data = {
|
||||
SchoolId: search.schoolId || 0,
|
||||
Grade: search.grade,
|
||||
ClassId: search.classId || 0,
|
||||
SubjectId: search.subjectId || 0,
|
||||
PositionType: search.positionType || 0,
|
||||
Status: search.status || 0
|
||||
};
|
||||
const res = await getPositionList(data);
|
||||
if (res.code === 200) {
|
||||
table.data = res.data;
|
||||
tableExpandRowKeys.value = table.data.map(s => s.id.toString());
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (selectPositions.value.length === 0) {
|
||||
ElMessage.warning("请选择要分配的职位");
|
||||
return;
|
||||
}
|
||||
emit("handleCheckCallback", selectPositions.value);
|
||||
};
|
||||
|
||||
const tagClose = (p: Position) => {
|
||||
selectPositions.value = selectPositions.value.filter(s => s !== p);
|
||||
};
|
||||
|
||||
const asyncPosition = (event: Event | null, rows?: Position[]) => {
|
||||
const datas = rows || table.selectRows;
|
||||
if (datas.length === 0) {
|
||||
ElMessage.warning("请选择要分配的职位");
|
||||
return;
|
||||
}
|
||||
const pIds = selectPositions.value.map(s => s.id);
|
||||
selectPositions.value = selectPositions.value.concat(
|
||||
datas.filter(s => !pIds.includes(s.id))
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
userTypeToPosition();
|
||||
if (props.positions && props.positions.length > 0) {
|
||||
const res = await getPositions(props.positions);
|
||||
selectPositions.value = res.data.map(s => ({ ...s }));
|
||||
}
|
||||
fetchInitData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tableBox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-content: center;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
.clearfixCss {
|
||||
width: 350px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.positionGap {
|
||||
height: calc(600px - 90px);
|
||||
overflow-x: auto;
|
||||
width: 350px;
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue