lxf 3 months ago
parent da13b2aa32
commit 1cfec47aa6

@ -1,57 +1,35 @@
// 从 "@/utils" 模块中导入 http 对象,用于发起 HTTP 请求
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块中导入 IPageSearchElderByKey 接口
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 定义一个名为 IPageAccidentByKey 的接口,用于分页查询事故登记时的数据结构
interface IPageAccidentByKey {
// 老人姓名
elderName: string;
// 护工姓名
staffName: string;
}
// 定义一个名为 IAddAccident 的接口,用于新增事故登记时的数据结构
interface IAddAccident {
// 事故登记的 ID
id: number;
// 老人的 ID
elderId: number;
// 护工的 ID
staffId: number;
// 事故发生日期
occurDate: string;
// 事故描述
description: string;
// 事故相关图片
picture: string;
}
// 定义一个名为 IGetAccidentById 的接口,用于根据编号获取事故登记时的数据结构
interface IGetAccidentById {
// 事故登记的 ID
accidentId: string;
}
// 定义一个名为 IEditAccident 的接口,用于编辑事故登记时的数据结构
interface IEditAccident {
// 事故登记的 ID
id: number;
// 姓名
name: string;
// 电话号码
phone: string;
// 关系
relation: string;
// 事故日期字符串
accidentDateStr: string;
// 事故编号
accidentNum: number;
}
// 定义一个异步函数 pageAccidentByKey用于分页查询事故登记
// 分页查询事故登记
export async function pageAccidentByKey(data: IPageAccidentByKey) {
// 使用 http 对象发起 GET 请求,请求路径为 "/api/accident/pageAccidentByKey",并将 data 对象展开作为请求参数
return http.get("/api/accident/pageAccidentByKey", {
params: {
...data
@ -59,9 +37,8 @@ export async function pageAccidentByKey(data: IPageAccidentByKey) {
});
}
// 定义一个异步函数 pageSearchElderByKey用于分页搜索老人
// 分页搜索老人
export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用 http 对象发起 GET 请求,请求路径为 "/api/accident/pageSearchElderByKey",并将 data 对象展开作为请求参数
return http.get("/api/accident/pageSearchElderByKey", {
params: {
...data
@ -69,21 +46,18 @@ export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
});
}
// 定义一个异步函数 listAccidentStaff用于获取护工列表
// 获取护工列表
export async function listAccidentStaff() {
// 使用 http 对象发起 GET 请求,请求路径为 "/api/accident/listAccidentStaff"
return http.get("/api/accident/listAccidentStaff");
}
// 定义一个函数 addAccident用于新增事故登记
// 新增事故登记
export function addAccident(data: IAddAccident) {
// 使用 http 对象发起 POST 请求,请求路径为 "/api/accident/addAccident",并将 data 对象作为请求体
return http.post("/api/accident/addAccident", data);
}
// 定义一个异步函数 getAccidentById用于根据编号获取事故登记
// 根据编号获取事故登记
export async function getAccidentById(data: IGetAccidentById) {
// 使用 http 对象发起 GET 请求,请求路径为 "/api/accident/getAccidentById",并将 data 对象展开作为请求参数
return http.get("/api/accident/getAccidentById", {
params: {
...data
@ -91,15 +65,13 @@ export async function getAccidentById(data: IGetAccidentById) {
});
}
// 定义一个函数 editAccident用于编辑事故登记
// 编辑事故登记
export function editAccident(data: IEditAccident) {
// 使用 http 对象发起 PUT 请求,请求路径为 "/api/accident/editAccident",并将 data 对象作为请求体
return http.put("/api/accident/editAccident", data);
}
// 定义一个异步函数 deleteAccident用于删除事故登记
// 删除事故登记
export async function deleteAccident(data: IGetAccidentById) {
// 使用 http 对象发起 DELETE 请求,请求路径为 "/api/accident/deleteAccident",并将 data 对象展开作为请求参数
return http.delete("/api/accident/deleteAccident", {
params: {
...data

@ -1,32 +1,18 @@
// 从 "@/utils" 模块导入 http 对象,该对象可能封装了 HTTP 请求方法
import { http } from "@/utils";
// 定义一个名为 IListRoomByKey 的接口,用于描述获取房间列表时请求参数的数据结构
interface IListRoomByKey {
// 楼栋 ID类型为字符串
buildingId: string;
// 楼层 ID类型为字符串
floorId: string;
// 老人姓名,类型为字符串
elderName: string;
}
/**
*
* @returns Promise
*/
// 获取楼栋列表
export async function listBuilding() {
// 发起一个 GET 请求到指定的 API 端点,用于获取楼栋列表
return http.get("/api/bedPanorama/listBuilding");
}
/**
* ID
* @param buildingId - ID
* @returns Promise
*/
// 获取楼层列表
export function listFloorByBuildingId(buildingId: string) {
// 发起一个 GET 请求到指定的 API 端点,携带楼栋 ID 作为参数,用于获取对应楼栋的楼层列表
return http.get("/api/bedPanorama/listFloorByBuildingId", {
params: {
buildingId
@ -34,13 +20,8 @@ export function listFloorByBuildingId(buildingId: string) {
});
}
/**
*
* @param data - IListRoomByKey
* @returns Promise
*/
// 获取房间列表
export function listRoomByKey(data: IListRoomByKey) {
// 发起一个 GET 请求到指定的 API 端点,将 data 对象中的属性展开作为请求参数,用于获取符合条件的房间列表
return http.get("/api/bedPanorama/listRoomByKey", {
params: {
...data

@ -1,79 +1,45 @@
// 从 '@/utils' 模块导入 http 对象,该对象可能封装了 HTTP 请求的方法,用于后续发起网络请求
import { http } from '@/utils'
// 定义一个接口 ISearchFormReserveByKey用于描述分页查询预定时请求参数的数据结构
interface ISearchFormReserveByKey {
// 当前页码,类型为数字
pageNum: number
// 每页显示的数量,类型为数字
pageSize: number
// 老人姓名,可选参数,类型为字符串
elderName?: string
// 付款人电话,可选参数,类型为字符串
payerPhone?: string
}
// 定义一个导出的接口 IPageSearchElderByKey用于描述分页搜索老人时请求参数的数据结构
export interface IPageSearchElderByKey {
// 当前页码,类型为数字
pageNum: number
// 每页显示的数量,类型为数字
pageSize: number
// 老人姓名,可选参数,类型为字符串
elderName?: string
// 老人电话,可选参数,类型为字符串
elderPhone?: string
}
// 定义一个接口 IAddReserve用于描述新增预定时请求体的数据结构
interface IAddReserve {
// 床位 ID类型为字符串
bedId: string
// 定金,类型为字符串
deposit: string
// 截止日期,类型为字符串
dueDate: string
// 老人地址,类型为字符串
elderAddress: string
// 老人年龄,类型为字符串
elderAge: string
// 老人姓名,类型为字符串
elderName: string
// 老人电话,类型为字符串
elderPhone: string
// 老人性别,类型为字符串
elderSex: string
// 身份证号码,类型为字符串
idNum: string
// 付款人姓名,类型为字符串
payerName: string
// 付款人电话,类型为字符串
payerPhone: string
// 工作人员 ID类型为字符串
staffId: string
}
// 定义一个接口 IGetReserveById用于描述根据预定编号和老人编号获取预定信息时请求参数的数据结构
interface IGetReserveById {
// 老人 ID类型为字符串
elderId: string
// 预定 ID类型为字符串
reserveId: string
}
// 定义一个接口 IRefund用于描述退款时请求体的数据结构
interface IRefund {
// 预定 ID类型为字符串
reserveId: string
}
/**
*
* @param data - ISearchFormReserveByKey
* @returns Promise
*/
// 分页查询预定
export async function pageReserveByKey(data: ISearchFormReserveByKey) {
// 发起一个 GET 请求到指定的 API 端点,将 data 对象中的属性展开作为请求参数
return http.get('/api/reserve/pageReserveByKey', {
params: {
...data
@ -81,13 +47,8 @@ export async function pageReserveByKey(data: ISearchFormReserveByKey) {
})
}
/**
*
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 发起一个 GET 请求到指定的 API 端点,将 data 对象中的属性展开作为请求参数
return http.get('/api/reserve/pageSearchElderByKey', {
params: {
...data
@ -95,41 +56,23 @@ export function pageSearchElderByKey(data: IPageSearchElderByKey) {
})
}
/**
*
* @returns Promise
*/
// 获取营销人员
export function listReserveStaff() {
// 发起一个 GET 请求到指定的 API 端点,用于获取营销人员列表
return http.get('/api/reserve/listReserveStaff')
}
/**
*
* @returns Promise
*/
// 获取楼栋树
export function getBuildTree() {
// 发起一个 GET 请求到指定的 API 端点,用于获取楼栋树信息
return http.get('/api/reserve/getBuildTree')
}
/**
*
* @param data - IAddReserve
* @returns Promise
*/
// 新增预定
export function addReserve(data: IAddReserve) {
// 发起一个 POST 请求到指定的 API 端点,将 data 对象作为请求体
return http.post('/api/reserve/addReserve', data)
}
/**
*
* @param data - IGetReserveById
* @returns Promise
*/
// 根据预定编号和老人编号获取预定信息
export function getReserveById(data: IGetReserveById) {
// 发起一个 GET 请求到指定的 API 端点,将 data 对象中的属性展开作为请求参数
return http.get('/api/reserve/getReserveByReserveIdAndElderId', {
params: {
...data
@ -137,12 +80,7 @@ export function getReserveById(data: IGetReserveById) {
})
}
/**
* 退
* @param data - 退 ID IRefund
* @returns Promise退
*/
// 退款
export function refund(data: IRefund) {
// 发起一个 PUT 请求到指定的 API 端点,将 data 对象作为请求体
return http.put('/api/reserve/refund', data)
return http.put('/api/reserve/refund',data)
}

@ -1,103 +1,64 @@
// 从 "@/utils" 模块导入 http 对象,用于发起 HTTP 请求
import { http } from "@/utils";
// 定义 IPageBedByKey 接口,用于分页查询床位时的参数结构
interface IPageBedByKey {
// 楼栋 ID
buildId: string;
// 楼层 ID
floorId: string;
// 房间 ID
roomId: string;
// 床位状态标识
bedFlag: string;
}
// 定义 IAddBuilding 接口,用于新增楼栋时的请求数据结构
interface IAddBuilding {
// 楼栋 ID
id: string;
// 楼栋名称
name: string;
// 楼层数量
floorNum: string;
}
// 定义 IGetBuildingById 接口,用于根据编号获取楼栋时的参数结构
interface IGetBuildingById {
// 楼栋 ID
buildingId: string;
}
// 定义 IAddFloor 接口,用于新增楼层时的请求数据结构
interface IAddFloor {
// 楼层 ID
id: string;
// 楼层名称
name: string;
// 房间数量
roomNum: string;
// 所属楼栋 ID
buildingId: string;
// 楼层限制相关信息
floorLimit: string;
}
// 定义 IGetFloorById 接口,用于根据编号获取楼层时的参数结构
interface IGetFloorById {
// 楼层 ID
floorId: string;
}
// 定义 IAddRoom 接口,用于新增房间时的请求数据结构
interface IAddRoom {
// 房间 ID
id: string;
// 房间名称
name: string;
// 房间类型 ID
typeId: string;
// 床位数量
bedNum: string;
// 所属楼层 ID
floorId: string;
// 房间限制相关信息
roomLimit: string;
}
// 定义 IGetRoomById 接口,用于根据编号获取房间时的参数结构
interface IGetRoomById {
// 房间 ID
roomId: string;
}
// 定义 IDeleteNode 接口,用于删除节点时的参数结构
interface IDeleteNode {
// 节点 ID
id: string;
// 节点标识
mark: string;
}
// 定义 IAddBed 接口,用于新增床位时的请求数据结构
interface IAddBed {
// 床位 ID
id: string;
// 床位名称
name: string;
// 所属房间 ID
roomId: string;
// 床位限制相关信息
bedLimit: string;
}
// 定义 IGetBedById 接口,用于根据编号获取床位时的参数结构
interface IGetBedById {
// 床位 ID
bedId: string;
}
// 定义床位状态列表,包含每个状态的标签和对应的值
// 床位状态
export const IBedFlagList = [
{ label: "空闲", value: "空闲" },
{ label: "预定", value: "预定" },
@ -105,22 +66,13 @@ export const IBedFlagList = [
{ label: "退住审核", value: "退住审核" }
];
/**
* - -
* @returns Promise - -
*/
// 获取楼栋-楼层-房间树
export async function getNoBedTree() {
// 发起 GET 请求到 /api/build/getNoBedTree 接口获取数据
return http.get("/api/build/getNoBedTree");
}
/**
*
* @param data - IPageBedByKey
* @returns Promise
*/
// 分页查询床位
export async function pageBedByKey(data: IPageBedByKey) {
// 发起 GET 请求到 /api/build/pageBedByKey 接口,将 data 对象展开作为请求参数
return http.get("/api/build/pageBedByKey", {
params: {
...data
@ -128,23 +80,13 @@ export async function pageBedByKey(data: IPageBedByKey) {
});
}
/**
*
* @param data - IAddBuilding
* @returns Promise
*/
// 新增楼栋
export function addBuilding(data: IAddBuilding) {
// 发起 POST 请求到 /api/build/addBuilding 接口,将 data 作为请求体
return http.post("/api/build/addBuilding", data);
}
/**
*
* @param data - IGetBuildingById
* @returns Promise
*/
// 根据编号获取楼栋
export async function getBuildingById(data: IGetBuildingById) {
// 发起 GET 请求到 /api/build/getBuildingById 接口,将 data 对象展开作为请求参数
return http.get("/api/build/getBuildingById", {
params: {
...data
@ -152,33 +94,18 @@ export async function getBuildingById(data: IGetBuildingById) {
});
}
/**
*
* @param data - IAddBuilding
* @returns Promise
*/
// 编辑楼栋
export function editBuilding(data: IAddBuilding) {
// 发起 PUT 请求到 /api/build/editBuilding 接口,将 data 作为请求体
return http.put("/api/build/editBuilding", data);
}
/**
*
* @param data - IAddFloor
* @returns Promise
*/
// 新增楼层
export function addFloor(data: IAddFloor) {
// 发起 POST 请求到 /api/build/addFloor 接口,将 data 作为请求体
return http.post("/api/build/addFloor", data);
}
/**
*
* @param data - IGetFloorById
* @returns Promise
*/
// 根据编号获取楼层
export async function getFloorById(data: IGetFloorById) {
// 发起 GET 请求到 /api/build/getFloorById 接口,将 data 对象展开作为请求参数
return http.get("/api/build/getFloorById", {
params: {
...data
@ -186,42 +113,23 @@ export async function getFloorById(data: IGetFloorById) {
});
}
/**
*
* @param data - IAddFloor
* @returns Promise
*/
// 编辑楼层
export function editFloor(data: IAddFloor) {
// 发起 PUT 请求到 /api/build/editFloor 接口,将 data 作为请求体
return http.put("/api/build/editFloor", data);
}
/**
*
* @returns Promise
*/
// 获取房间类型列表
export async function listRoomType() {
// 发起 GET 请求到 /api/build/listRoomType 接口获取数据
return http.get("/api/build/listRoomType");
}
/**
*
* @param data - IAddRoom
* @returns Promise
*/
// 新增房间
export function addRoom(data: IAddRoom) {
// 发起 POST 请求到 /api/build/addRoom 接口,将 data 作为请求体
return http.post("/api/build/addRoom", data);
}
/**
*
* @param data - IGetRoomById
* @returns Promise
*/
// 根据编号获取房间
export async function getRoomById(data: IGetRoomById) {
// 发起 GET 请求到 /api/build/getRoomById 接口,将 data 对象展开作为请求参数
return http.get("/api/build/getRoomById", {
params: {
...data
@ -229,23 +137,13 @@ export async function getRoomById(data: IGetRoomById) {
});
}
/**
*
* @param data - IAddRoom
* @returns Promise
*/
// 编辑房间
export function editRoom(data: IAddRoom) {
// 发起 PUT 请求到 /api/build/editRoom 接口,将 data 作为请求体
return http.put("/api/build/editRoom", data);
}
/**
*
* @param data - IDeleteNode
* @returns Promise
*/
// 删除节点
export async function deleteNode(data: IDeleteNode) {
// 发起 DELETE 请求到 /api/build/deleteNode 接口,将 data 对象展开作为请求参数
return http.delete("/api/build/deleteNode", {
params: {
...data
@ -253,23 +151,13 @@ export async function deleteNode(data: IDeleteNode) {
});
}
/**
*
* @param data - IAddBed
* @returns Promise
*/
// 新增床位
export function addBed(data: IAddBed) {
// 发起 POST 请求到 /api/build/addBed 接口,将 data 作为请求体
return http.post("/api/build/addBed", data);
}
/**
*
* @param data - IGetBedById
* @returns Promise
*/
// 根据编号获取床位
export async function getBedById(data: IGetBedById) {
// 发起 GET 请求到 /api/build/getBedById 接口,将 data 对象展开作为请求参数
return http.get("/api/build/getBedById", {
params: {
...data
@ -277,23 +165,13 @@ export async function getBedById(data: IGetBedById) {
});
}
/**
*
* @param data - IAddBed
* @returns Promise
*/
// 编辑床位
export function editBed(data: IAddBed) {
// 发起 PUT 请求到 /api/build/editBed 接口,将 data 作为请求体
return http.put("/api/build/editBed", data);
}
/**
*
* @param data - IGetBedById
* @returns Promise
*/
// 删除床位
export async function deleteBed(data: IGetBedById) {
// 发起 DELETE 请求到 /api/build/deleteBed 接口,将 data 对象展开作为请求参数
return http.delete("/api/build/deleteBed", {
params: {
...data

@ -1,50 +1,26 @@
// 从 "@/utils" 模块导入 http 对象,用于发起 HTTP 请求
import { http } from "@/utils";
// 从 "@/apis/dishes" 模块导入 IPageDishesByKey 接口,用于分页查询菜品时的参数类型定义
import { IPageDishesByKey } from "@/apis/dishes";
/**
* IPageCateringSetByKey
*/
interface IPageCateringSetByKey {
// 名称,用于筛选餐饮套餐
name: string;
// 套餐名称,由于后台与前端组件封装要求,该字段与 name 可能存在关联
name:string;
setName: string;
}
/**
* IAddCateringSet
*/
interface IAddCateringSet {
// 餐饮套餐的 ID
id: number;
// 餐饮套餐的名称
name: string;
// 餐饮套餐的月价格
monthPrice: number;
// 菜品 ID 列表,类型为 any需根据实际情况调整
dishesIdList: any;
dishesIdList: any ;
}
/**
* IGetCateringSetById
*/
interface IGetCateringSetById {
// 餐饮套餐的 ID
setId: string;
setId: string
}
/**
*
* @param data - IPageCateringSetByKey
* @returns Promise
*/
// 分页查询餐饮套餐
export async function pageCateringSetByKey(data: IPageCateringSetByKey) {
// 由于后台返回的字段与前端表单数据的 prop 不一样,而组件封装要求字段一致
// 所以如果 data 对象中有 'name' 字段,则将其值赋给 'setName' 字段
Reflect.has(data, 'name') ? (data.setName = data.name) : '';
// 发起 GET 请求到 /api/cateringSet/pageCateringSetByKey 接口,将 data 对象展开作为请求参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, 'name') ? (data.setName = data.name) : ''
return http.get("/api/cateringSet/pageCateringSetByKey", {
params: {
...data
@ -52,22 +28,13 @@ export async function pageCateringSetByKey(data: IPageCateringSetByKey) {
});
}
/**
*
* @returns Promise
*/
// 获取菜品分类
export function listDishesType() {
// 发起 POST 请求到 /api/cateringSet/listDishesType 接口获取菜品分类数据
return http.post("/api/cateringSet/listDishesType");
}
/**
*
* @param data - IPageDishesByKey
* @returns Promise
*/
// 分页查询菜品
export async function pageDishesByKey(data: IPageDishesByKey) {
// 发起 GET 请求到 /api/cateringSet/pageDishesByKey 接口,将 data 对象展开作为请求参数
return http.get("/api/cateringSet/pageDishesByKey", {
params: {
...data
@ -75,23 +42,13 @@ export async function pageDishesByKey(data: IPageDishesByKey) {
});
}
/**
*
* @param data - IAddCateringSet
* @returns Promise
*/
// 新增餐饮套餐
export function addCateringSet(data: IAddCateringSet) {
// 发起 POST 请求到 /api/cateringSet/addCateringSet 接口,将 data 作为请求体
return http.post("/api/cateringSet/addCateringSet", data);
}
/**
*
* @param data - IGetCateringSetById
* @returns Promise
*/
// 根据编号查询餐饮套餐
export async function getCateringSetById(data: IGetCateringSetById) {
// 发起 GET 请求到 /api/cateringSet/getCateringSetById 接口,将 data 对象展开作为请求参数
return http.get("/api/cateringSet/getCateringSetById", {
params: {
...data
@ -99,23 +56,13 @@ export async function getCateringSetById(data: IGetCateringSetById) {
});
}
/**
*
* @param data - IAddCateringSet
* @returns Promise
*/
// 编辑餐饮套餐
export function editCateringSet(data: IAddCateringSet) {
// 发起 PUT 请求到 /api/cateringSet/editCateringSet 接口,将 data 作为请求体
return http.put("/api/cateringSet/editCateringSet", data);
}
/**
*
* @param data - IGetCateringSetById
* @returns Promise
*/
// 删除餐饮套餐
export async function deleteCateringSet(data: IGetCateringSetById) {
// 发起 DELETE 请求到 /api/cateringSet/deleteCateringSet 接口,将 data 对象展开作为请求参数
return http.delete("/api/cateringSet/deleteCateringSet", {
params: {
...data

@ -1,87 +1,44 @@
// 从 "@/utils" 模块导入 http 对象,用于发起 HTTP 请求
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,用于分页搜索老人时的参数类型定义
import { IPageSearchElderByKey } from "@/apis/bookManage";
/**
* IPageCheckContractByKey
*/
interface IPageCheckContractByKey {
// 姓名,用于筛选入住签约记录
name: string;
// 性别,用于筛选入住签约记录
sex: string;
// 身份证号码,用于筛选入住签约记录
idNum: string;
}
/**
* IAddCheckContract
*/
interface IAddCheckContract {
// 入住签约的 ID
id: string;
// 护理等级 ID
nursingGradeId: string;
// 餐饮套餐 ID
cateringSetId: string;
// 床位 ID
bedId: string;
// 姓名
name: string;
// 身份证号码
idNum: string;
// 年龄
age: string;
// 性别
sex: string;
// 电话
phone: string;
// 地址
address: string;
// 工作人员 ID
staffId: string;
// 签约日期
signDate: string;
// 开始日期
startDate: string;
// 结束日期
endDate: string;
// 紧急联系人查询列表,包含多个紧急联系人信息
operateEmergencyContactQueryList: IEmergencyContact[];
}
/**
* IEmergencyContact
*/
interface IEmergencyContact {
// 姓名
name: string;
// 电话
phone: string;
// 邮箱
email: string;
// 关系
relation: string;
// 接收标志
receiveFlag: string;
}
/**
* IGetCheckContractById
*/
interface IGetCheckContractById {
// 老人 ID
elderId: string;
elderId: string
}
/**
*
* @param data - IPageCheckContractByKey
* @returns Promise
*/
// 分页查询入住签约
export async function pageCheckContractByKey(data: IPageCheckContractByKey) {
// 发起 GET 请求到 /api/checkContract/pageCheckContractByKey 接口,将 data 对象展开作为请求参数
return http.get("/api/checkContract/pageCheckContractByKey", {
params: {
...data
@ -89,13 +46,8 @@ export async function pageCheckContractByKey(data: IPageCheckContractByKey) {
});
}
/**
*
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 发起 GET 请求到 /api/checkContract/pageSearchElderByKey 接口,将 data 对象展开作为请求参数
return http.get("/api/checkContract/pageSearchElderByKey", {
params: {
...data
@ -103,22 +55,13 @@ export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
});
}
/**
*
* @returns Promise
*/
// 获取护理等级列表
export async function listNurseGrade() {
// 发起 GET 请求到 /api/checkContract/listNurseGrade 接口获取护理等级数据
return http.get("/api/checkContract/listNurseGrade");
}
/**
*
* @param nurseGradeId - ID
* @returns Promise
*/
// 根据编号查询护理等级
export async function getNurseGradeById(nurseGradeId: string) {
// 发起 GET 请求到 /api/checkContract/getNurseGradeById 接口,将 nurseGradeId 作为请求参数
return http.get("/api/checkContract/getNurseGradeById", {
params: {
nurseGradeId
@ -126,22 +69,13 @@ export async function getNurseGradeById(nurseGradeId: string) {
});
}
/**
*
* @returns Promise
*/
// 获取餐饮套餐列表
export async function listCateringSet() {
// 发起 GET 请求到 /api/checkContract/listCateringSet 接口获取餐饮套餐数据
return http.get("/api/checkContract/listCateringSet");
}
/**
*
* @param cateringSetId - ID
* @returns Promise
*/
// 根据编号查询餐饮套餐
export async function getCateringSetById(cateringSetId: string) {
// 发起 GET 请求到 /api/checkContract/getCateringSetById 接口,将 cateringSetId 作为请求参数
return http.get("/api/checkContract/getCateringSetById", {
params: {
cateringSetId
@ -149,22 +83,13 @@ export async function getCateringSetById(cateringSetId: string) {
});
}
/**
*
* @returns Promise
*/
// 获取楼栋树
export async function getBuildTree() {
// 发起 GET 请求到 /api/checkContract/getBuildTree 接口获取楼栋树数据
return http.get("/api/checkContract/getBuildTree");
}
/**
*
* @param bedId - ID
* @returns Promise
*/
// 根据编号查询床位
export async function getBedById(bedId: string) {
// 发起 GET 请求到 /api/checkContract/getBedById 接口,将 bedId 作为请求参数
return http.get("/api/checkContract/getBedById", {
params: {
bedId
@ -172,32 +97,18 @@ export async function getBedById(bedId: string) {
});
}
/**
*
* @returns Promise
*/
// 获取营销人员
export async function listReserveStaff() {
// 发起 GET 请求到 /api/checkContract/listReserveStaff 接口获取营销人员数据
return http.get("/api/checkContract/listReserveStaff");
}
/**
*
* @param data - IAddCheckContract
* @returns Promise
*/
// 新增入住签约
export function addCheckContract(data: IAddCheckContract) {
// 发起 POST 请求到 /api/checkContract/addCheckContract 接口,将 data 作为请求体
return http.post("/api/checkContract/addCheckContract", data);
}
/**
*
* @param data - IGetCheckContractById
* @returns Promise
*/
// 根据老人编号查询入住签约
export async function getCheckContractById(data: IGetCheckContractById) {
// 发起 GET 请求到 /api/checkContract/getCheckContractById 接口,将 data 对象展开作为请求参数
return http.get("/api/checkContract/getCheckContractById", {
params: {
...data
@ -205,23 +116,13 @@ export async function getCheckContractById(data: IGetCheckContractById) {
});
}
/**
*
* @param data - IAddCheckContract
* @returns Promise
*/
// 编辑入住签约
export function editCheckContract(data: IAddCheckContract) {
// 发起 PUT 请求到 /api/checkContract/editCheckContract 接口,将 data 作为请求体
return http.put("/api/checkContract/editCheckContract", data);
}
/**
*
* @param data - IGetCheckContractById
* @returns Promise
*/
// 删除入住签约
export async function deleteCheckContract(data: IGetCheckContractById) {
// 发起 DELETE 请求到 /api/checkContract/deleteCheckContract 接口,将 data 对象展开作为请求参数
return http.delete("/api/checkContract/deleteCheckContract", {
params: {
...data

@ -1,25 +1,13 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IPageConsumeByKey用于描述分页查询消费记录时的请求参数结构
interface IPageConsumeByKey {
// 老人姓名,用于筛选消费记录,类型为字符串
elderName: string;
// 开始时间,用于筛选消费记录的时间范围,类型为字符串
startTime: string;
// 结束时间,用于筛选消费记录的时间范围,类型为字符串
endTime: string;
}
/**
* pageConsumeByKey
* @param data - IPageConsumeByKey
* @returns Promise
*/
// 分页查询消费记录
export async function pageConsumeByKey(data: IPageConsumeByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/consume/pageConsumeByKey"
// 将传入的 data 对象展开作为请求的参数
return http.get("/api/consume/pageConsumeByKey", {
params: {
...data

@ -1,47 +1,24 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,
// 用于描述分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 定义一个接口 IPageDepositRechargeByKey用于描述分页查询预存充值时的请求参数结构
interface IPageDepositRechargeByKey {
// 身份证号码,用于筛选预存充值记录,类型为字符串
idNum: string;
// 姓名,用于筛选预存充值记录,类型为字符串
name: string;
// 老人姓名,用于筛选预存充值记录,类型为字符串
elderName: string;
// 电话,用于筛选预存充值记录,类型为字符串
idNum:string;
name:string;
elderName:string;
phone: string;
// 老人电话,用于筛选预存充值记录,类型为字符串
elderPhone: string;
}
// 定义一个接口 IRecharge用于描述入住老人账户充值时的请求参数结构
interface IRecharge {
// 老人 ID用于指定要充值的老人账户类型为字符串
elderId: string;
// 充值金额,用于指定充值的金额,类型为字符串
amount: string;
}
/**
* pageDepositRechargeByKey
* @param data - IPageDepositRechargeByKey
* @returns Promise
*/
// 分页查询预存充值
export async function pageDepositRechargeByKey(data: IPageDepositRechargeByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以请求前增加一些这两个字段
// 如果 data 对象中有 'elderName' 字段,则将其值赋给 'name' 字段
Reflect.has(data, 'elderName')? (data.name = data.elderName) : '';
// 如果 data 对象中有 'elderPhone' 字段,则将其值赋给 'phone' 字段
Reflect.has(data, 'elderPhone')? (data.phone = data.elderPhone) : '';
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/depositRecharge/pageDepositRechargeByKey"
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, 'elderName') ? (data.name = data.elderName) : ''
Reflect.has(data, 'elderPhone') ? (data.phone = data.elderPhone) : ''
return http.get("/api/depositRecharge/pageDepositRechargeByKey", {
params: {
...data
@ -49,28 +26,16 @@ export async function pageDepositRechargeByKey(data: IPageDepositRechargeByKey)
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/depositRecharge/pageSearchElderByKey"
// 将 data 对象展开作为请求的参数
return http.get('/api/depositRecharge/pageSearchElderByKey', {
params: {
...data
}
});
})
}
/**
* recharge
* @param data - IRecharge
* @returns Promise
*/
// 入住老人账户充值
export function recharge(data: IRecharge) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/depositRecharge/recharge"
// 将 data 对象作为请求的主体
return http.put("/api/depositRecharge/recharge", data);
}

@ -1,60 +1,36 @@
// 从 "@/utils" 模块导入名为 http 的对象,该对象可能是用于发起 HTTP 请求的工具,比如对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IListDishesType用于描述获取菜品分类列表时的请求参数结构
interface IListDishesType {
// 菜品分类名称,用于筛选菜品分类列表,类型为字符串
dishesTypeName: string;
}
// 导出一个接口 IPageDishesByKey用于描述分页查询菜品时的请求参数结构
export interface IPageDishesByKey {
// 菜品名称,用于筛选菜品,类型为字符串
dishesName: string;
// 菜品类型 ID用于筛选属于特定类型的菜品类型为数字
typeId: number;
}
// 定义一个接口 IAddDishesType用于描述新增菜品分类时的数据结构
interface IAddDishesType {
// 菜品分类的 ID类型为数字
id: number;
// 菜品分类的名称,类型为字符串
name: string;
}
// 定义一个接口 IGetDishesTypeById用于描述根据编号获取菜品分类时的请求参数结构
interface IGetDishesTypeById {
// 菜品分类 ID类型为字符串
dishesTypeId: string;
}
// 定义一个接口 IAddDishes用于描述新增菜品时的数据结构
interface IAddDishes {
// 菜品的 ID类型为数字
id: number;
// 菜品的名称,类型为字符串
name: string;
// 菜品的价格,类型为字符串
price: string;
// 菜品所属类型的 ID类型为数字
typeId: number;
}
// 导出一个接口 IGetDishesById用于描述根据编号获取菜品时的请求参数结构
export interface IGetDishesById {
// 菜品 ID类型为字符串
dishesId: string;
}
/**
* listDishesType
* @param data - IListDishesType
* @returns Promise
*/
// 获取菜品分类列表
export async function listDishesType(data: IListDishesType) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/dishes/listDishesType"
// 将 data 对象展开作为请求的参数
return http.get("/api/dishes/listDishesType", {
params: {
...data
@ -62,14 +38,8 @@ export async function listDishesType(data: IListDishesType) {
});
}
/**
* pageDishesByKey
* @param data - IPageDishesByKey
* @returns Promise
*/
// 分页查询菜品
export async function pageDishesByKey(data: IPageDishesByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/dishes/pageDishesByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/dishes/pageDishesByKey", {
params: {
...data
@ -77,25 +47,13 @@ export async function pageDishesByKey(data: IPageDishesByKey) {
});
}
/**
* addDishesType
* @param data - IAddDishesType
* @returns Promise
*/
// 新增菜品分类
export function addDishesType(data: IAddDishesType) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/dishes/addDishesType"
// 将 data 对象作为请求的主体
return http.post("/api/dishes/addDishesType", data);
}
/**
* getDishesTypeById
* @param data - IGetDishesTypeById
* @returns Promise
*/
// 根据编号获取菜品分类
export async function getDishesTypeById(data: IGetDishesTypeById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/dishes/getDishesTypeById"
// 将 data 对象展开作为请求的参数
return http.get("/api/dishes/getDishesTypeById", {
params: {
...data
@ -103,25 +61,13 @@ export async function getDishesTypeById(data: IGetDishesTypeById) {
});
}
/**
* editDishesType
* @param data - IAddDishesType
* @returns Promise
*/
// 编辑菜品分类
export function editDishesType(data: IAddDishesType) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/dishes/editDishesType"
// 将 data 对象作为请求的主体
return http.put("/api/dishes/editDishesType", data);
}
/**
* deleteDishesType
* @param data - IGetDishesTypeById
* @returns Promise
*/
// 删除菜品分类
export async function deleteDishesType(data: IGetDishesTypeById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/dishes/deleteDishesType"
// 将 data 对象展开作为请求的参数
return http.delete("/api/dishes/deleteDishesType", {
params: {
...data
@ -129,25 +75,13 @@ export async function deleteDishesType(data: IGetDishesTypeById) {
});
}
/**
* addDishes
* @param data - IAddDishes
* @returns Promise
*/
// 新增菜品
export function addDishes(data: IAddDishes) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/dishes/addDishes"
// 将 data 对象作为请求的主体
return http.post("/api/dishes/addDishes", data);
}
/**
* getDishesById
* @param data - IGetDishesById
* @returns Promise
*/
// 根据编号获取菜品
export async function getDishesById(data: IGetDishesById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/dishes/getDishesById"
// 将 data 对象展开作为请求的参数
return http.get("/api/dishes/getDishesById", {
params: {
...data
@ -155,25 +89,13 @@ export async function getDishesById(data: IGetDishesById) {
});
}
/**
* editDishes
* @param data - IAddDishes
* @returns Promise
*/
// 编辑菜品
export function editDishes(data: IAddDishes) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/dishes/editDishes"
// 将 data 对象作为请求的主体
return http.put("/api/dishes/editDishes", data);
}
/**
* deleteDishes
* @param data - IGetDishesById
* @returns Promise
*/
// 删除菜品
export async function deleteDishes(data: IGetDishesById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/dishes/deleteDishes"
// 将 data 对象展开作为请求的参数
return http.delete("/api/dishes/deleteDishes", {
params: {
...data

@ -1,72 +1,43 @@
// 从 "@/utils" 模块导入名为 http 的对象,该对象可能是对 HTTP 请求库(如 axios的封装用于发起各种 HTTP 请求
import { http } from "@/utils";
// 定义一个接口 IPageElderByKey用于描述分页查询员工这里可能是长者相关名称可能有误时的请求参数结构
interface IPageElderByKey {
// 姓名,用于筛选,类型为字符串
name: string;
// 长者姓名,用于筛选,类型为字符串
elderName: string;
// 身份证号码,用于筛选,类型为字符串
idNum: string;
// 性别,用于筛选,类型为字符串
sex: string;
// 长者性别,用于筛选,类型为字符串
elderSex: string;
}
// 定义一个接口 IGetElderById用于描述根据编号获取长者信息时的请求参数结构
interface IGetElderById {
// 长者 ID类型为字符串
elderId: string;
}
// 定义一个接口 IEditElder用于描述编辑长者信息时的数据结构
interface IEditElder {
// 长者 ID类型为数字
id: number;
// 姓名,类型为字符串
name: string;
// 身份证号码,类型为字符串
idNum: string;
// 年龄,类型为数字
age: number;
// 性别,类型为字符串
sex: string;
// 电话号码,类型为字符串
phone: string;
// 地址,类型为字符串
address: string;
}
// 定义一个名为 sexList 的常量,是一个包含性别选项的数组,每个选项有标签和对应的值
// 性别
export const sexList = [
{ label: "男", value: "男" },
{ label: "女", value: "女" }
];
/**
* exportExcel Excel
* @returns Promise Excel
*/
// 导出excel
export function exportExcel() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/elderRecord/exportExcel"
return http.get("/api/elderRecord/exportExcel");
}
/**
* pageElderByKey
* @param data - IPageElderByKey
* @returns Promise
*/
// 分页查询员工
export async function pageElderByKey(data: IPageElderByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,但是组件封装是需要一样的,所以请求前增加一些这两个字段
// 如果 data 对象中有 "sex" 字段,则将其值赋给 "elderSex" 字段
Reflect.has(data, "sex")? (data.elderSex = data.sex) : "";
// 如果 data 对象中有 "name" 字段,则将其值赋给 "elderName" 字段
Reflect.has(data, "name")? (data.elderName = data.name) : "";
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/elderRecord/pageElderByKey"
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, "sex") ? (data.elderSex = data.sex) : "";
Reflect.has(data, "name") ? (data.elderName = data.name) : "";
return http.get("/api/elderRecord/pageElderByKey", {
params: {
...data
@ -74,14 +45,8 @@ export async function pageElderByKey(data: IPageElderByKey) {
});
}
/**
* getElderById
* @param data - IGetElderById
* @returns Promise
*/
// 根据编号获取长者信息
export async function getElderById(data: IGetElderById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/elderRecord/getElderById"
// 将 data 对象展开作为请求的参数
return http.get("/api/elderRecord/getElderById", {
params: {
...data
@ -89,14 +54,8 @@ export async function getElderById(data: IGetElderById) {
});
}
/**
* getElderRecordById
* @param data - IGetElderById
* @returns Promise
*/
// 根据编号获取长者档案
export async function getElderRecordById(data: IGetElderById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/elderRecord/getElderRecordById"
// 将 data 对象展开作为请求的参数
return http.get("/api/elderRecord/getElderRecordById", {
params: {
...data
@ -104,25 +63,13 @@ export async function getElderRecordById(data: IGetElderById) {
});
}
/**
* editElder
* @param data - IEditElder
* @returns Promise
*/
// 编辑长者
export function editElder(data: IEditElder) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/elderRecord/editElder"
// 将 data 对象作为请求的主体
return http.put("/api/elderRecord/editElder", data);
}
/**
* deleteElder
* @param data - IGetElderById
* @returns Promise
*/
// 删除长者
export async function deleteElder(data: IGetElderById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/elderRecord/deleteElder"
// 将 data 对象展开作为请求的参数
return http.delete("/api/elderRecord/deleteElder", {
params: {
...data

@ -1,56 +1,25 @@
// 从 '@/utils' 模块导入名为 http 的对象,该对象可能是用于发起 HTTP 请求的工具,比如对 axios 等请求库的封装
import { http } from '@/utils'
/**
* getAvailableBed
* @returns Promise
*/
// 可售床位
export async function getAvailableBed() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/availableBed'
return http.get('/api/home/availableBed')
}
/**
* getBusinessTrend
* @returns Promise
*/
// 业务趋势
export async function getBusinessTrend() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/businessTrend'
return http.get('/api/home/businessTrend')
}
/**
* getClientSource
* @returns Promise
*/
// 客户来源渠道
export async function getClientSource() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/clientSource'
return http.get('/api/home/clientSource')
}
/**
* getMonthPerformanceRank
* @returns Promise
*/
// 本月业绩排行
export async function getMonthPerformanceRank() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/monthPerformanceRank'
return http.get('/api/home/monthPerformanceRank')
}
/**
* getTodayOverview
* @returns Promise
*/
// 今日概览
export async function getTodayOverview() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/todayOverview'
return http.get('/api/home/todayOverview')
}
/**
* getTodaySaleFollow
* @returns Promise
*/
// 今日销售跟进
export async function getTodaySaleFollow() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/home/todaySaleFollow'
return http.get('/api/home/todaySaleFollow')
}

@ -1,29 +1,16 @@
// 注释说明这是动态路由的假数据,并且提示该部分代码可以删除
// 动态路由的假数据 可删除
// 从 '@/utils' 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from '@/utils'
// 注释说明发起请求的时机在动态设置路由的时候data => 树形结构 => 路由列表)
// 问题:何时发起请求? 在动态设置路由的时候data => 树形结构 => 路由列表)
/**
* getUserRouteList
* @param uid - ID
* @returns Promise
*/
function getUserRouteList(uid: number) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/user_router_list',请求体包含用户 ID
return http
.post('/api/user_router_list', { uid })
// 处理请求成功的情况,直接返回请求得到的数据
.then((data) => data)
// 处理请求失败的情况,捕获错误并重新抛出,以便上层调用者处理
.catch((err) => {
throw err
})
}
// 导出 getUserRouteList 函数,以便在其他模块中可以导入和使用该函数
export { getUserRouteList }

@ -1,64 +1,37 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/service" 模块导入 IPageServiceByKey 接口,
// 用于描述分页查询服务时的请求参数结构
import { IPageServiceByKey } from "@/apis/service";
// 定义一个接口 IPageNurseGradeByKey用于描述分页查询护理等级时的请求参数结构
interface IPageNurseGradeByKey {
// 名称,用于筛选护理等级,类型为字符串
name: string;
// 护理等级名称,用于筛选护理等级,类型为字符串
name:string;
gradeName: string;
// 类型,用于筛选护理等级,类型为字符串
type: string;
// 护理类型,用于筛选护理等级,类型为字符串
type:string;
nurseType: string;
}
// 定义一个接口 IAddNurseGrade用于描述新增护理等级时的数据结构
interface IAddNurseGrade {
// 护理等级的 ID类型为数字
id: number;
// 护理等级的名称,类型为字符串
name: string;
// 护理等级的类型,类型为字符串
type: string;
// 护理等级的月价格,类型为数字
monthPrice: number;
// 服务 ID 列表,类型为 any需根据实际情况调整
serviceIdList: any;
serviceIdList: any ;
}
// 定义一个接口 IGetNurseGradeById用于描述根据编号查询护理等级时的请求参数结构
interface IGetNurseGradeById {
// 护理等级 ID类型为字符串
nurseGradeId: string;
nurseGradeId: string
}
// 定义一个名为 INurseTypeList 的常量,是一个包含护理类型选项的数组,每个选项有标签和对应的值
// 护理类型
export const INurseTypeList = [
{ label: "自理", value: "自理" },
{ label: "介护", value: "介护" },
{ label: "全护", value: "全护" }
];
/**
* pageNurseGradeByKey
* @param data - IPageNurseGradeByKey
* @returns Promise
*/
// 分页查询护理等级
export async function pageNurseGradeByKey(data: IPageNurseGradeByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以请求前增加一些这两个字段
// 如果 data 对象中有 'name' 字段,则将其值赋给 'gradeName' 字段
Reflect.has(data, 'name')? (data.gradeName = data.name) : '';
// 如果 data 对象中有 'type' 字段,则将其值赋给 'nurseType' 字段
Reflect.has(data, 'type')? (data.nurseType = data.type) : '';
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseGrade/pageNurseGradeByKey"
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, 'name') ? (data.gradeName = data.name) : ''
Reflect.has(data, 'type') ? (data.nurseType = data.type) : ''
return http.get("/api/nurseGrade/pageNurseGradeByKey", {
params: {
...data
@ -66,23 +39,13 @@ export async function pageNurseGradeByKey(data: IPageNurseGradeByKey) {
});
}
/**
* listServiceType
* @returns Promise
*/
// 获取服务类型
export function listServiceType() {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/nurseGrade/listServiceType"
return http.post("/api/nurseGrade/listServiceType");
}
/**
* pageServiceByKey
* @param data - IPageServiceByKey
* @returns Promise
*/
// 分页查询服务
export async function pageServiceByKey(data: IPageServiceByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseGrade/pageServiceByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/nurseGrade/pageServiceByKey", {
params: {
...data
@ -90,25 +53,13 @@ export async function pageServiceByKey(data: IPageServiceByKey) {
});
}
/**
* addNurseGrade
* @param data - IAddNurseGrade
* @returns Promise
*/
// 新增护理等级
export function addNurseGrade(data: IAddNurseGrade) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/nurseGrade/addNurseGrade"
// 将 data 对象作为请求的主体
return http.post("/api/nurseGrade/addNurseGrade", data);
}
/**
* getNurseGradeById
* @param data - IGetNurseGradeById
* @returns Promise
*/
// 根据编号查询护理等级
export async function getNurseGradeById(data: IGetNurseGradeById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseGrade/getNurseGradeById"
// 将 data 对象展开作为请求的参数
return http.get("/api/nurseGrade/getNurseGradeById", {
params: {
...data
@ -116,25 +67,13 @@ export async function getNurseGradeById(data: IGetNurseGradeById) {
});
}
/**
* editNurseGrade
* @param data - IAddNurseGrade
* @returns Promise
*/
// 编辑护理等级
export function editNurseGrade(data: IAddNurseGrade) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/nurseGrade/editNurseGrade"
// 将 data 对象作为请求的主体
return http.put("/api/nurseGrade/editNurseGrade", data);
}
/**
* deleteNurseGrade
* @param data - IGetNurseGradeById
* @returns Promise
*/
// 删除护理等级
export async function deleteNurseGrade(data: IGetNurseGradeById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/nurseGrade/deleteNurseGrade"
// 将 data 对象展开作为请求的参数
return http.delete("/api/nurseGrade/deleteNurseGrade", {
params: {
...data

@ -1,64 +1,34 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,
// 用于描述分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 从 "@/apis/service" 模块导入 IGetServiceById 接口,
// 用于描述根据编号查询服务时的请求参数结构
import { IGetServiceById } from "@/apis/service";
// 定义一个接口 IPageNurseReserveByKey用于描述分页查询护理预定时的请求参数结构
interface IPageNurseReserveByKey {
// 床位名称,用于筛选护理预定记录,类型为字符串
bedName: string;
// 老人姓名,用于筛选护理预定记录,类型为字符串
elderName: string;
// 服务名称,用于筛选护理预定记录,类型为字符串
elderName:string;
serviceName: string;
}
// 定义一个接口 IAddNurseReserve用于描述新增护理预定时的数据结构
interface IAddNurseReserve {
// 老人 ID类型为数字
elderId: number;
// 服务名称,类型为字符串
serviceName: string;
// 需要服务的日期(这里推测为时间戳等能表示日期的值,类型为数字)
needDate: number;
// 服务价格,类型为数字
servicePrice: number;
// 收费方式,类型为字符串
chargeMethod: string;
// 频率,类型为数字
frequency: number;
// 支付金额,类型为数字
payAmount: number;
}
// 定义一个接口 IExecuteNurseReserve用于描述执行护理预定时的数据结构
interface IExecuteNurseReserve {
// 护理预定的 ID类型为数字
id: number;
// 护理日期,类型为字符串
nurseDate: string;
// 护理人员 ID类型为字符串
staffId: string;
}
/**
* pageNurseReserveByKey
* @param data - IPageNurseReserveByKey
* @returns Promise
*/
// 分页查询护理预定
export async function pageNurseReserveByKey(data: IPageNurseReserveByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以原本计划请求前处理某些字段,
// 但这里代码被注释掉了,可能是暂不处理或有其他调整
// Reflect.has(data, 'name')? (data.gradeName = data.name) : ''
// Reflect.has(data, 'type')? (data.nurseType = data.type) : ''
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseReserve/pageNurseReserveByKey"
// 将 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
// Reflect.has(data, 'name') ? (data.gradeName = data.name) : ''
// Reflect.has(data, 'type') ? (data.nurseType = data.type) : ''
return http.get("/api/nurseReserve/pageNurseReserveByKey", {
params: {
...data
@ -66,49 +36,27 @@ export async function pageNurseReserveByKey(data: IPageNurseReserveByKey) {
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseReserve/pageSearchElderByKey"
// 将 data 对象展开作为请求的参数
return http.get('/api/nurseReserve/pageSearchElderByKey', {
params: {
...data
}
});
})
}
/**
* listService
* @returns Promise
*/
// 获取服务项目
export async function listService() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseReserve/listService"
return http.get("/api/nurseReserve/listService");
}
/**
* addNurseReserve
* @param data - IAddNurseReserve
* @returns Promise
*/
// 新增护理预定
export function addNurseReserve(data: IAddNurseReserve) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/nurseReserve/addNurseReserve"
// 将 data 对象作为请求的主体
return http.post("/api/nurseReserve/addNurseReserve", data);
}
/**
* getServiceById
* @param data - IGetServiceById
* @returns Promise
*/
// 根据编号查询护理预定
export async function getServiceById(data: IGetServiceById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseReserve/getServiceById"
// 将 data 对象展开作为请求的参数
return http.get("/api/nurseReserve/getServiceById", {
params: {
...data
@ -116,22 +64,12 @@ export async function getServiceById(data: IGetServiceById) {
});
}
/**
* listNurseStaff
* @returns Promise
*/
// 护理人员
export async function listNurseStaff() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/nurseReserve/listNurseStaff"
return http.get("/api/nurseReserve/listNurseStaff");
}
/**
* executeNurseReserve
* @param data - IExecuteNurseReserve
* @returns Promise
*/
// 执行护理预定
export function executeNurseReserve(data: IExecuteNurseReserve) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/nurseReserve/executeNurseReserve"
// 将 data 对象作为请求的主体
return http.put("/api/nurseReserve/executeNurseReserve", data);
}

@ -1,70 +1,40 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,
// 用于描述分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 从 "@/apis/dishes" 模块导入 IPageDishesByKey 接口,
// 用于描述分页查询菜品时的请求参数结构
import { IPageDishesByKey } from "@/apis/dishes";
// 定义一个接口 IPageOrderByKey用于描述分页查询点餐时的请求参数结构
interface IPageOrderByKey {
// 老人姓名,用于筛选点餐记录,类型为字符串
elderName: string;
// 老人电话,用于筛选点餐记录,类型为字符串
elderName:string;
elderPhone: string;
}
// 定义一个接口 IAddOrder用于描述新增点餐时的数据结构
interface IAddOrder {
// 老人 ID类型为字符串
elderId: string;
// 就餐方式,类型为字符串
dineType: string;
// 就餐日期,类型为字符串
dineDate: string;
// 点的菜品列表,类型为 any需根据实际情况调整
orderDishesList: any;
}
// 定义一个接口 IGetOrderById用于描述根据编号查询点餐时的请求参数结构
interface IGetOrderById {
// 菜品 ID这里可能是点餐记录中的菜品 ID用于查询特定点餐记录类型为字符串
dishesId: string;
}
// 定义一个接口 ISendOrder用于描述送餐时的数据结构
interface ISendOrder {
// 订单 ID类型为字符串
id: string;
// 送餐日期,类型为字符串
deliverDishesDate: string;
// 送餐人员 ID类型为字符串
staffId: string;
}
// 定义一个名为 IDineTypeList 的常量,是一个包含就餐方式选项的数组,每个选项有标签和对应的值
// 就餐方式
export const IDineTypeList = [
{ label: "送餐", value: "送餐" },
{ label: "堂食", value: "堂食" }
];
/**
* pageOrderByKey
* @param data - IPageOrderByKey
* @returns Promise
*/
// 分页查询点餐
export async function pageOrderByKey(data: IPageOrderByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以原本计划请求前处理某些字段,
// 但这里代码被注释掉了,可能是暂不处理或有其他调整
// Reflect.has(data, 'name')? (data.gradeName = data.name) : ''
// Reflect.has(data, 'type')? (data.nurseType = data.type) : ''
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/order/pageOrderByKey"
// 将 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
// Reflect.has(data, 'name') ? (data.gradeName = data.name) : ''
// Reflect.has(data, 'type') ? (data.nurseType = data.type) : ''
return http.get("/api/order/pageOrderByKey", {
params: {
...data
@ -72,55 +42,31 @@ export async function pageOrderByKey(data: IPageOrderByKey) {
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/order/pageSearchElderByKey"
// 将 data 对象展开作为请求的参数
return http.get('/api/order/pageSearchElderByKey', {
params: {
...data
}
});
})
}
/**
* pageDishesByKey
* @param data - IPageDishesByKey
* @returns Promise
*/
// 分页查询菜品
export async function pageDishesByKey(data: IPageDishesByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/order/pageDishesByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/order/pageDishesByKey", {
params: {
return http.get("/api/order/pageDishesByKey",{
params:{
...data
}
});
}
/**
* addOrder
* @param data - IAddOrder
* @returns Promise
*/
// 新增点餐
export function addOrder(data: IAddOrder) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/order/addOrder"
// 将 data 对象作为请求的主体
return http.post("/api/order/addOrder", data);
}
/**
* getOrderById
* @param data - IGetOrderById
* @returns Promise
*/
// 根据编号查询点餐
export async function getOrderById(data: IGetOrderById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/order/getOrderById"
// 将 data 对象展开作为请求的参数
return http.get("/api/order/getOrderById", {
params: {
...data
@ -128,22 +74,12 @@ export async function getOrderById(data: IGetOrderById) {
});
}
/**
* listNurseStaff
* @returns Promise
*/
// 护理人员
export async function listNurseStaff() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/order/listNurseStaff"
return http.get("/api/order/listNurseStaff");
}
/**
* sendOrder
* @param data - ISendOrder
* @returns Promise
*/
// 送餐
export function sendOrder(data: ISendOrder) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/order/sendOrder"
// 将 data 对象作为请求的主体
return http.put("/api/order/sendOrder", data);
}

@ -1,77 +1,48 @@
// 从 "@/utils" 模块导入名为 http 的对象,该对象可用于发起 HTTP 请求,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,此接口用于定义分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 定义 IPageOutwardByKey 接口,用于描述分页查询外出登记时的请求参数结构
interface IPageOutwardByKey {
// 老人姓名,用于筛选外出登记记录,类型为字符串
elderName: string;
// 陪同人类型,用于筛选外出登记记录,类型为字符串
chaperoneType: string;
// 外出开始时间,用于筛选外出登记记录,类型为字符串
startTime: string;
// 外出结束时间,用于筛选外出登记记录,类型为字符串
endTime: string;
}
// 定义 IListContactByElderId 接口,用于描述根据老人 ID 获取紧急联系人列表时的请求参数结构
interface IListContactByElderId {
// 老人 ID类型为字符串
elderId: string;
}
// 定义 IAddOutward 接口,用于描述新增外出登记时的数据结构
interface IAddOutward {
// 老人 ID类型为数字
elderId: number;
// 陪同人姓名,类型为字符串
chaperoneName: string;
// 陪同人电话,类型为字符串
chaperonePhone: string;
// 陪同人类型,类型为字符串
chaperoneType: string;
// 外出日期,类型为字符串
outwardDate: string;
// 计划返回日期,类型为字符串
planReturnDate: string;
}
// 定义 IGetOutwardById 接口,用于描述根据编号获取外出登记时的请求参数结构
interface IGetOutwardById {
// 外出登记 ID类型为字符串
outwardId: string;
}
// 定义 IDelayReturn 接口,用于描述延期返回操作时的数据结构
interface IDelayReturn {
// 外出登记 ID类型为字符串
id: string;
// 新的计划返回日期,类型为字符串
planReturnDate: string;
}
// 定义 IRecordReturn 接口,用于描述登记返回操作时的数据结构
interface IRecordReturn {
// 外出登记 ID类型为字符串
id: string;
// 实际返回日期,类型为 any具体类型需根据实际情况确定
realReturnDate: any;
}
// 定义一个常量 typeList包含陪同人类型的选项,每个选项有标签和对应的值
// 陪同人类型
export const typeList = [
{ label: "护工", value: "护工" },
{ label: "家属", value: "家属" }
];
/**
* pageOutwardByKey
* @param data - IPageOutwardByKey
* @returns Promise
*/
// 分页查询外出登记
export async function pageOutwardByKey(data: IPageOutwardByKey) {
// 使用 http 对象发起 GET 请求,请求地址为 "/api/outward/pageOutwardByKey",并将 data 对象展开作为请求参数
return http.get("/api/outward/pageOutwardByKey", {
params: {
...data
@ -79,13 +50,8 @@ export async function pageOutwardByKey(data: IPageOutwardByKey) {
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用 http 对象发起 GET 请求,请求地址为 "/api/outward/pageSearchElderByKey",并将 data 对象展开作为请求参数
return http.get("/api/outward/pageSearchElderByKey", {
params: {
...data
@ -93,22 +59,13 @@ export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
});
}
/**
* listOutwardStaff
* @returns Promise
*/
// 获取护工列表
export async function listOutwardStaff() {
// 使用 http 对象发起 GET 请求,请求地址为 "/api/outward/listOutwardStaff"
return http.get("/api/outward/listOutwardStaff");
}
/**
* listContactByElderId ID
* @param data - IListContactByElderId ID
* @returns Promise
*/
// 获取紧急联系人列表
export async function listContactByElderId(data: IListContactByElderId) {
// 使用 http 对象发起 GET 请求,请求地址为 "/api/outward/listContactByElderId",并将 data 对象展开作为请求参数
return http.get("/api/outward/listContactByElderId", {
params: {
...data
@ -116,23 +73,13 @@ export async function listContactByElderId(data: IListContactByElderId) {
});
}
/**
* addOutward
* @param data - IAddOutward
* @returns Promise
*/
// 新增外出登记
export function addOutward(data: IAddOutward) {
// 使用 http 对象发起 POST 请求,请求地址为 "/api/outward/addOutward",并将 data 对象作为请求体
return http.post("/api/outward/addOutward", data);
}
/**
* getOutwardById
* @param data - IGetOutwardById ID
* @returns Promise
*/
// 根据编号获取外出登记
export async function getOutwardById(data: IGetOutwardById) {
// 使用 http 对象发起 GET 请求,请求地址为 "/api/outward/getOutwardById",并将 data 对象展开作为请求参数
return http.get("/api/outward/getOutwardById", {
params: {
...data
@ -140,33 +87,18 @@ export async function getOutwardById(data: IGetOutwardById) {
});
}
/**
* delayReturn
* @param data - IDelayReturn
* @returns Promise
*/
// 延期返回
export function delayReturn(data: IDelayReturn) {
// 使用 http 对象发起 PUT 请求,请求地址为 "/api/outward/delayReturn",并将 data 对象作为请求体
return http.put("/api/outward/delayReturn", data);
}
/**
* recordReturn
* @param data - IRecordReturn
* @returns Promise
*/
// 登记返回
export function recordReturn(data: IRecordReturn) {
// 使用 http 对象发起 PUT 请求,请求地址为 "/api/outward/recordReturn",并将 data 对象作为请求体
return http.put("/api/outward/recordReturn", data);
}
/**
* deleteOutward
* @param data - IGetOutwardById ID
* @returns Promise
*/
// 删除外出登记
export async function deleteOutward(data: IGetOutwardById) {
// 使用 http 对象发起 DELETE 请求,请求地址为 "/api/outward/deleteOutward",并将 data 对象展开作为请求参数
return http.delete("/api/outward/deleteOutward", {
params: {
...data

@ -1,37 +1,19 @@
// 从 "@/utils" 模块导入名为 http 的对象,
// 推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,
// 用于描述分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 定义一个接口 IPageRetreatApplyByKey用于描述分页查询退住申请时的请求参数结构
interface IPageRetreatApplyByKey {
// 床位名称,用于筛选退住申请记录,类型为字符串
bedName: string;
// 老人姓名,用于筛选退住申请记录,类型为字符串
elderName: string;
// 老人性别,用于筛选退住申请记录,类型为字符串
elderSex: string;
// 身份证号码,用于筛选退住申请记录,类型为字符串
idNum: string;
}
// 定义一个接口 IAddRetreatApply用于描述新增退住申请时的数据结构
interface IAddRetreatApply {
// 老人 ID类型为数字用于标识发起退住申请的老人
elderId: number;
}
/**
* pageRetreatApplyByKey退
* @param data - IPageRetreatApplyByKey
* @returns Promise 退
*/
// 分页查询退住申请
export async function pageRetreatApplyByKey(data: IPageRetreatApplyByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/retreatApply/pageRetreatApplyByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/retreatApply/pageRetreatApplyByKey", {
params: {
...data
@ -39,14 +21,8 @@ export async function pageRetreatApplyByKey(data: IPageRetreatApplyByKey) {
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/retreatApply/pageSearchElderByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/retreatApply/pageSearchElderByKey", {
params: {
...data
@ -54,13 +30,7 @@ export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
});
}
/**
* addRetreatApply退
* @param data - IAddRetreatApply 退
* @returns Promise 退
*/
// 新增退住申请
export function addRetreatApply(data: IAddRetreatApply) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/retreatApply/addRetreatApply"
// 将 data 对象作为请求的主体
return http.post("/api/retreatApply/addRetreatApply", data);
}

@ -1,46 +1,29 @@
// 从 "@/utils" 模块导入名为 http 的对象,该对象可能用于发起 HTTP 请求,例如对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IPageRetreatAuditByKey用于描述分页查询退住审核时的请求参数结构
interface IPageRetreatAuditByKey {
// 老人姓名,用于筛选退住审核记录,类型为字符串
elderName: string;
// 老人性别,用于筛选退住审核记录,类型为字符串
elderSex: string;
// 身份证号码,用于筛选退住审核记录,类型为字符串
idNum: string;
}
// 定义一个接口 IGetElderFeeById用于描述根据编号获取老人费用详情时的请求参数结构
interface IGetElderFeeById {
// 老人 ID类型为数字用于指定获取费用详情的老人
elderId: number;
}
// 定义一个接口 IAuditElderFee用于描述审核老人费用详情时的数据结构
interface IAuditElderFee {
// 申请 ID类型为数字用于标识退住申请
applyId: number;
// 老人 ID类型为数字用于关联老人
elderId: number;
// 审核结果,类型为数字,可能是枚举值(如 0 表示不通过1 表示通过等)
auditResult: number;
}
// 定义一个常量 IAuditResultList包含审核结果的选项,每个选项有标签和对应的值
// 审核结果
export const IAuditResultList = [
{ label: "通过", value: "通过" },
{ label: "不通过", value: "不通过" }
];
/**
* pageRetreatAuditByKey退
* @param data - IPageRetreatAuditByKey
* @returns Promise 退
*/
// 分页查询退住审核
export async function pageRetreatAuditByKey(data: IPageRetreatAuditByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/retreatAudit/pageRetreatAuditByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/retreatAudit/pageRetreatAuditByKey", {
params: {
...data
@ -48,14 +31,8 @@ export async function pageRetreatAuditByKey(data: IPageRetreatAuditByKey) {
});
}
/**
* getElderFeeById
* @param data - IGetElderFeeById
* @returns Promise
*/
// 根据编号获取老人费用详情
export async function getElderFeeById(data: IGetElderFeeById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/retreatAudit/getElderFeeById"
// 将 data 对象展开作为请求的参数
return http.get("/api/retreatAudit/getElderFeeById", {
params: {
...data
@ -63,13 +40,7 @@ export async function getElderFeeById(data: IGetElderFeeById) {
});
}
/**
* auditElderFee
* @param data - IAuditElderFee
* @returns Promise
*/
// 审核老人费用详情
export function auditElderFee(data: IAuditElderFee) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/retreatAudit/auditElderFee"
// 将 data 对象作为请求的主体
return http.put("/api/retreatAudit/auditElderFee", data);
}

@ -1,42 +1,24 @@
// 从 "@/utils" 模块导入名为 http 的对象,该对象可能是用于发起 HTTP 请求的工具,比如对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IPageRoomTypeByKey用于描述分页查询房间类型时的请求参数结构
interface IPageRoomTypeByKey {
// 名称,用于筛选房间类型,类型为字符串
name: string;
// 房间类型名称,用于筛选房间类型,类型为字符串
roomTypeName: string;
}
// 定义一个接口 IAddRoomType用于描述新增房间类型时的数据结构
interface IAddRoomType {
// 房间类型的 ID类型为字符串
id: string;
// 房间类型的名称,类型为字符串
name: string;
// 房间类型的月价格,类型为字符串
monthPrice: string;
}
// 定义一个接口 IGetRoomTypeById用于描述根据编号查询房间类型时的请求参数结构
interface IGetRoomTypeById {
// 房间类型 ID类型为字符串
roomTypeId: string;
}
/**
* pageRoomTypeByKey
* @param data - IPageRoomTypeByKey
* @returns Promise
*/
// 分页查询房间类型
export async function pageRoomTypeByKey(data: IPageRoomTypeByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以请求前增加一些这两个字段
// 如果 data 对象中有 "name" 字段,则将其值赋给 "roomTypeName" 字段
Reflect.has(data, "name")? (data.roomTypeName = data.name) : "";
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/roomType/pageRoomTypeByKey"
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, "name") ? (data.roomTypeName = data.name) : "";
return http.get("/api/roomType/pageRoomTypeByKey", {
params: {
...data
@ -44,25 +26,13 @@ export async function pageRoomTypeByKey(data: IPageRoomTypeByKey) {
});
}
/**
* addRoomType
* @param data - IAddRoomType
* @returns Promise
*/
// 新增房间类型
export function addRoomType(data: IAddRoomType) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/roomType/addRoomType"
// 将 data 对象作为请求的主体
return http.post("/api/roomType/addRoomType", data);
}
/**
* getRoomTypeById
* @param data - IGetRoomTypeById
* @returns Promise
*/
// 根据编号查询房间类型
export async function getRoomTypeById(data: IGetRoomTypeById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/roomType/getRoomTypeById"
// 将 data 对象展开作为请求的参数
return http.get("/api/roomType/getRoomTypeById", {
params: {
...data
@ -70,25 +40,13 @@ export async function getRoomTypeById(data: IGetRoomTypeById) {
});
}
/**
* editRoomType
* @param data - IAddRoomType
* @returns Promise
*/
// 编辑房间类型
export function editRoomType(data: IAddRoomType) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/roomType/editRoomType"
// 将 data 对象作为请求的主体
return http.put("/api/roomType/editRoomType", data);
}
/**
* deleteRoomType
* @param data - IGetRoomTypeById
* @returns Promise
*/
// 删除房间类型
export async function deleteRoomType(data: IGetRoomTypeById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/roomType/deleteRoomType"
// 将 data 对象展开作为请求的参数
return http.delete("/api/roomType/deleteRoomType", {
params: {
...data

@ -1,70 +1,44 @@
// 从 "@/utils" 模块导入名为 http 的对象,推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IGetServiceType用于描述获取服务类型时的请求参数结构
interface IGetServiceType {
// 服务类型名称,用于筛选服务类型,类型为字符串
serviceTypeName: string;
}
// 导出一个接口 IPageServiceByKey用于描述分页查询服务时的请求参数结构
export interface IPageServiceByKey {
// 名称,用于筛选服务,类型为字符串
name: string;
// 服务类型 ID用于筛选属于特定类型的服务类型为数字
typeId: number;
}
// 定义一个接口 IAddServiceType用于描述新增服务类型时的数据结构
interface IAddServiceType {
// 服务类型的 ID类型为数字
id: number;
// 服务类型的名称,类型为字符串
name: string;
}
// 定义一个接口 IGetServiceTypeById用于描述根据编号获取服务类型时的请求参数结构
interface IGetServiceTypeById {
// 服务类型 ID类型为字符串
serviceTypeId: string;
}
// 定义一个接口 IAddService用于描述新增服务时的数据结构
interface IAddService {
// 服务的 ID类型为数字
id: number;
// 服务的名称,类型为字符串
name: string;
// 服务所需日期,类型为字符串
needDate: string;
// 服务价格,类型为字符串
price: string;
// 服务所属类型的 ID类型为数字
typeId: number;
// 收费方式,类型为字符串
chargeMethod: string;
}
// 导出一个接口 IGetServiceById用于描述根据编号获取服务时的请求参数结构
export interface IGetServiceById {
// 服务 ID类型为字符串
serviceId: string;
}
// 定义一个名为 IChargeMethodList 的常量,是一个包含收费方式选项的数组,每个选项有标签和对应的值
// 收费方式
export const IChargeMethodList = [
{ label: "按次", value: "按次" },
{ label: "按月", value: "按月" }
];
/**
* getServiceType
* @param data - IGetServiceType
* @returns Promise
*/
// 获取服务类型列表
export async function getServiceType(data: IGetServiceType) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/service/getServiceType"
// 将 data 对象展开作为请求的参数
return http.get("/api/service/getServiceType", {
params: {
...data
@ -72,17 +46,10 @@ export async function getServiceType(data: IGetServiceType) {
});
}
/**
* pageServiceByKey
* @param data - IPageServiceByKey
* @returns Promise
*/
// 分页查询服务
export async function pageServiceByKey(data: IPageServiceByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,但是组件封装是需要一样的,所以请求前增加一些这两个字段
// 这里注释掉的代码可能是原本用于处理字段的逻辑,但当前未启用
// Reflect.has(data, 'roleName')? (data.roleId = data.roleName) : ''
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/service/pageServiceByKey"
// 将 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
// Reflect.has(data, 'roleName') ? (data.roleId = data.roleName) : ''
return http.get("/api/service/pageServiceByKey", {
params: {
...data
@ -90,25 +57,13 @@ export async function pageServiceByKey(data: IPageServiceByKey) {
});
}
/**
* addServiceType
* @param data - IAddServiceType
* @returns Promise
*/
// 新增服务类型
export function addServiceType(data: IAddServiceType) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/service/addServiceType"
// 将 data 对象作为请求的主体
return http.post("/api/service/addServiceType", data);
}
/**
* getServiceTypeById
* @param data - IGetServiceTypeById
* @returns Promise
*/
// 根据编号获取服务类型
export async function getServiceTypeById(data: IGetServiceTypeById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/service/getServiceTypeById"
// 将 data 对象展开作为请求的参数
return http.get("/api/service/getServiceTypeById", {
params: {
...data
@ -116,25 +71,13 @@ export async function getServiceTypeById(data: IGetServiceTypeById) {
});
}
/**
* editServiceType
* @param data - IAddServiceType
* @returns Promise
*/
// 编辑服务类型
export function editServiceType(data: IAddServiceType) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/service/editServiceType"
// 将 data 对象作为请求的主体
return http.put("/api/service/editServiceType", data);
}
/**
* deleteServiceType
* @param data - IGetServiceTypeById
* @returns Promise
*/
// 删除服务类型
export async function deleteServiceType(data: IGetServiceTypeById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/service/deleteServiceType"
// 将 data 对象展开作为请求的参数
return http.delete("/api/service/deleteServiceType", {
params: {
...data
@ -142,25 +85,13 @@ export async function deleteServiceType(data: IGetServiceTypeById) {
});
}
/**
* addService
* @param data - IAddService
* @returns Promise
*/
// 新增服务
export function addService(data: IAddService) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/service/addService"
// 将 data 对象作为请求的主体
return http.post("/api/service/addService", data);
}
/**
* getServiceById
* @param data - IGetServiceById
* @returns Promise
*/
// 根据编号获取服务
export async function getServiceById(data: IGetServiceById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/service/getServiceById"
// 将 data 对象展开作为请求的参数
return http.get("/api/service/getServiceById", {
params: {
...data
@ -168,25 +99,13 @@ export async function getServiceById(data: IGetServiceById) {
});
}
/**
* editService
* @param data - IAddService
* @returns Promise
*/
// 编辑服务
export function editService(data: IAddService) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/service/editService"
// 将 data 对象作为请求的主体
return http.put("/api/service/editService", data);
}
/**
* deleteService
* @param data - IGetServiceById
* @returns Promise
*/
// 删除服务
export async function deleteService(data: IGetServiceById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/service/deleteService"
// 将 data 对象展开作为请求的参数
return http.delete("/api/service/deleteService", {
params: {
...data

@ -1,110 +1,58 @@
// 从 '@/utils' 模块导入名为 http 的对象,该对象可能是用于发起 HTTP 请求的工具,比如对 axios 等请求库的封装
import { http } from '@/utils'
// 定义一个接口 IAddConsult用于描述新增咨询时的数据结构
interface IAddConsult {
// 地址,类型为字符串
address: string;
// 年龄,类型为字符串
age: string;
// 咨询内容,类型为字符串
consultContent: string;
// 咨询日期,类型为字符串
consultDate: string;
// 咨询人姓名,类型为字符串
consultName: string;
// 咨询人电话,类型为字符串
consultPhone: string;
// 老人姓名,类型为字符串
elderName: string;
// 老人电话,类型为字符串
elderPhone: string;
// 身份证号码,类型为字符串
idNum: string;
// 关系,类型为字符串
relation: string;
// 性别,类型为字符串
sex: string;
// 来源 ID可以是字符串或数字
sourceId: string | number;
// 接待人 ID可以是字符串或数字
staffId: string | number;
// 咨询 ID可选类型可以是字符串或数字
consultId?: string | number;
// 老人 ID可选类型可以是字符串或数字
elderId?: string | number;
address: string
age: string
consultContent: string
consultDate: string
consultName: string
consultPhone: string
elderName: string
elderPhone: string
idNum: string
relation: string
sex: string
sourceId: string | number
staffId: string | number
consultId?: string | number
elderId?: string | number
}
// 定义一个接口 ISearhFormConsultByKey用于描述分页查询咨询时的请求参数结构
interface ISearhFormConsultByKey {
// 页码,类型为数字
pageNum: number;
// 每页数量,类型为数字
pageSize: number;
// 咨询人姓名,可选,类型为字符串
consultName?: string;
// 咨询人电话,可选,类型为字符串
consultPhone?: string;
// 老人姓名,可选,类型为字符串
elderName?: string;
// 老人电话,可选,类型为字符串
elderPhone?: string;
// 结束时间,可选,类型为字符串
endTime?: string;
// 来源 ID可选类型为字符串
sourceId?: string;
// 接待人 ID可选类型为字符串
staffId?: string;
// 开始时间,可选,类型为字符串
startTime?: string;
// 来源名称,可选,类型为字符串
sourceName?: string;
// 接待人名称,可选,类型为字符串
staffName?: string;
pageNum: number
pageSize: number
consultName?: string
consultPhone?: string
elderName?: string
elderPhone?: string
endTime?: string
sourceId?: string
staffId?: string
startTime?: string
sourceName?: string
staffName?: string
}
// 定义一个接口 IConsultByForm用于描述根据咨询人编号和老人编号获取咨询信息时的请求参数结构
interface IConsultByForm {
// 咨询 ID可以是字符串或数字
consultId: string | number;
// 老人 ID可以是字符串或数字
elderId: string | number;
consultId: string | number
elderId: string | number
}
/**
* getConsultByForm
* @param data - IConsultByForm
* @returns Promise
*/
// 获取咨询管理表格数据 根据咨询人编号和老人编号获取咨询信息
export async function getConsultByForm(data: IConsultByForm) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/consult/getConsultByConsultIdAndElderId'
// 将 data 对象展开作为请求的参数
return http.get('/api/consult/getConsultByConsultIdAndElderId', {
params: {
...data
}
})
}
/**
* addConsult
* @param data - IAddConsult
* @returns Promise
*/
//新增资询
export function addConsult(data: IAddConsult) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/consult/addConsult'
// 将 data 对象作为请求的主体
return http.post('/api/consult/addConsult', data)
}
/**
* delConsult
* @param elderId - ID
* @returns Promise
*/
// 删除咨询
export function delConsult(elderId: string | number) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 '/api/consult/deleteConsult'
// 将 elderId 作为请求的参数
return http.delete('/api/consult/deleteConsult', {
params: {
elderId
@ -112,25 +60,13 @@ export function delConsult(elderId: string | number) {
})
}
/**
* editConsult
* @param data - IAddConsult
* @returns Promise
*/
//编辑咨询
export function editConsult(data: IAddConsult) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/consult/editConsult'
// 将 data 对象作为请求的主体
return http.put('/api/consult/editConsult', data)
}
/**
* intentionConsult
* @param elderId - ID
* @returns Promise
*/
// 转为意向客户
export function intentionConsult(elderId: string | number) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/consult/intentionConsult'
// 将包含 elderId 的对象作为请求的主体
return http.put('/api/consult/intentionConsult', {
data: {
elderId
@ -138,37 +74,21 @@ export function intentionConsult(elderId: string | number) {
})
}
/**
* listConsultSource
* @returns Promise
*/
// 来源渠道
export function listConsultSource() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/consult/listConsultSource'
return http.get('/api/consult/listConsultSource')
}
/**
* listConsultStaff
* @returns Promise
*/
// 接待人
export function listConsultStaff() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/consult/listConsultStaff'
return http.get('/api/consult/listConsultStaff')
}
/**
* pageConsultByKey
* @param data - ISearhFormConsultByKey
* @returns Promise
*/
// 分页查询咨询
export async function pageConsultByKey(data: ISearhFormConsultByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,但是组件封装是需要一样的,所以请求前增加一些这两个字段
// 如果 data 对象中有'sourceName' 字段,则将其值赋给'sourceId' 字段
Reflect.has(data,'sourceName')? (data.sourceId = data.sourceName) : '';
// 如果 data 对象中有'staffName' 字段,则将其值赋给'staffId' 字段
Reflect.has(data,'staffName')? (data.staffId = data.staffName) : '';
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/consult/pageConsultByKey'
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, 'sourceName') ? (data.sourceId = data.sourceName) : ''
Reflect.has(data, 'staffName') ? (data.staffId = data.staffName) : ''
const res = await http.get('/api/consult/pageConsultByKey', {
params: {
...data
@ -177,28 +97,17 @@ export async function pageConsultByKey(data: ISearhFormConsultByKey) {
return res
}
// 定义一个接口 ISearhFormIntentionByKey用于描述分页查询意向客户时的请求参数结构
//意向用户接口
interface ISearhFormIntentionByKey {
// 页码,类型为数字
pageNum: number;
// 每页数量,类型为数字
pageSize: number;
// 老人姓名,可选,类型为字符串
elderName?: string;
// 老人电话,可选,可以是字符串或数字
elderPhone?: string | number;
// 标签 ID可选类型为数字
labelId?: number;
pageNum: number
pageSize: number
elderName?: string
elderPhone?: string | number
labelId?: number
}
/**
* pageIntentionByKey
* @param data - ISearhFormIntentionByKey
* @returns Promise
*/
//分页查询意向客户
export async function pageIntentionByKey(data: ISearhFormIntentionByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/intention/pageIntentionByKey'
// 将 data 对象展开作为请求的参数
const res = await http.get('/api/intention/pageIntentionByKey', {
params: {
...data
@ -207,47 +116,23 @@ export async function pageIntentionByKey(data: ISearhFormIntentionByKey) {
return res
}
/**
* addCommunicationRecord
* @param data - any
* @returns Promise
*/
// 新增沟通记录
export function addCommunicationRecord(data: any) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/intention/addCommunicationRecord'
// 将 data 对象作为请求的主体
return http.post('/api/intention/addCommunicationRecord', data)
}
/**
* addIntention
* @param data - any
* @returns Promise
*/
// 新增意向客户
export function addIntention(data: any) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/intention/addIntention'
// 将 data 对象作为请求的主体
return http.post('/api/intention/addIntention', data)
}
/**
* addVisitPlan访
* @param data - 访 any
* @returns Promise 访
*/
// 新增回访计划
export function addVisitPlan(data: any) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/intention/addVisitPlan'
// 将 data 对象作为请求的主体
return http.post('/api/intention/addVisitPlan', data)
}
/**
* deleteCommunicationRecord
* @param communicationRecordId - ID any
* @returns Promise
*/
// 新增沟通记录
export function deleteCommunicationRecord(communicationRecordId: any) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 '/api/intention/deleteCommunicationRecord'
// 将 communicationRecordId 作为请求的参数
return http.delete('/api/intention/deleteCommunicationRecord', {
params: {
communicationRecordId
@ -255,14 +140,8 @@ export function deleteCommunicationRecord(communicationRecordId: any) {
})
}
/**
* deleteVisitPlan访
* @param visitPlanId - 访 ID any访
* @returns Promise 访
*/
// 删除回访计划
export function deleteVisitPlan(visitPlanId: any) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 '/api/intention/deleteVisitPlan'
// 将 visitPlanId 作为请求的参数
return http.delete('/api/intention/deleteVisitPlan', {
params: {
visitPlanId
@ -270,58 +149,28 @@ export function deleteVisitPlan(visitPlanId: any) {
})
}
/**
* editCommunicationRecord
* @param data - any
* @returns Promise
*/
// 编辑沟通记录
export function editCommunicationRecord(data: any) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/intention/editCommunicationRecord'
//将 data 对象作为请求的主体
return http.put('/api/intention/editCommunicationRecord', data)
}
/**
* editIntention
* @param data - any
* @returns Promise
*/
// 编辑意向客户
export function editIntention(data: any) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/intention/editIntention'
// 将 data 对象作为请求的主体
return http.put('/api/intention/editIntention', data)
}
/**
* editElderLabel
* @param data - any
* @returns Promise
*/
// 编辑老人标签
export function editElderLabel(data: any) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/intention/editElderLabel'
// 将 data 对象作为请求的主体
return http.put('/api/intention/editElderLabel', data)
}
/**
* executeVisitPlan访
* @param data - 访 any
* @returns Promise 访
*/
// 执行回访计划
export function executeVisitPlan(data: any) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/intention/executeVisitPlan'
// 将 data 对象作为请求的主体
return http.put('/api/intention/executeVisitPlan', data)
}
/**
* getEditElderLabelById
* @param data - any
* @returns Promise
*/
// 根据编号获取编辑意向客户标签
export function getEditElderLabelById(data: any) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/intention/getEditElderLabelById'
// 将 data 对象展开作为请求的参数
return http.get('/api/intention/getEditElderLabelById', {
params: {
...data
@ -329,14 +178,8 @@ export function getEditElderLabelById(data: any) {
})
}
/**
* getElderLabelById
* @param data - any
* @returns Promise
*/
// 根据编号获取意向客户标签
export function getElderLabelById(data: any) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/intention/getElderLabelById'
// 将 data 对象展开作为请求的参数
return http.get('/api/intention/getElderLabelById', {
params: {
...data
@ -344,14 +187,8 @@ export function getElderLabelById(data: any) {
})
}
/**
* getIntentById
* @param data - any
* @returns Promise
*/
// 根据编号获取意向客户
export function getIntentById(data: any) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/intention/getIntentById'
// 将 data 对象展开作为请求的参数
return http.get('/api/intention/getIntentById', {
params: {
...data
@ -359,14 +196,8 @@ export function getIntentById(data: any) {
})
}
/**
* listLabel
* @param data - any
* @returns Promise
*/
//客户标签
export function listLabel(data: any) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/intention/listLabel'
// 将 data 对象展开作为请求的参数
return http.get('/intention/listLabel', {
params: {
...data
@ -374,12 +205,29 @@ export function listLabel(data: any) {
})
}
/**
* pageCommunicationRecord
* @param data - any
* @returns Promise
*/
// 分页查询沟通记录
export function pageCommunicationRecord(data: any) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/intention/pageCommunicationRecord'
// 将 data 对象展开作为请求的参数
return http.get
return http.get('/intention/pageCommunicationRecord', {
params: {
...data
}
})
}
// 分页搜索老人
export function pageSearchElderByKey(data: any) {
return http.get('/intention/pageSearchElderByKey', {
params: {
...data
}
})
}
// 分页查询回访计划
export function pageVisitPlan(data: any) {
return http.get('/intention/pageVisitPlan', {
params: {
...data
}
})
}

@ -1,40 +1,23 @@
// 从 "@/utils" 模块导入名为 http 的对象,推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IPageSourceByKey用于描述分页查询来源渠道时的请求参数结构
interface IPageSourceByKey {
// 名称,用于筛选来源渠道,类型为字符串
name: string;
// 来源渠道名称,用于筛选来源渠道,类型为字符串
sourceName: string;
}
// 定义一个接口 IAddSource用于描述新增来源渠道时的数据结构
interface IAddSource {
// 来源渠道的 ID类型为字符串
id: string;
// 来源渠道的名称,类型为字符串
name: string;
}
// 定义一个接口 IGetSourceById用于描述根据编号查询来源渠道时的请求参数结构
interface IGetSourceById {
// 来源渠道 ID类型为字符串
sourceId: string;
}
/**
* pageSourceByKey
* @param data - IPageSourceByKey
* @returns Promise
*/
// 分页查询来源渠道
export async function pageSourceByKey(data: IPageSourceByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以请求前增加一些这两个字段
// 如果 data 对象中有 "name" 字段,则将其值赋给 "sourceName" 字段
Reflect.has(data, "name")? (data.sourceName = data.name) : "";
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/source/pageSourceByKey"
// 将处理后的 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, "name") ? (data.sourceName = data.name) : "";
return http.get("/api/source/pageSourceByKey", {
params: {
...data
@ -42,25 +25,13 @@ export async function pageSourceByKey(data: IPageSourceByKey) {
});
}
/**
* addSource
* @param data - IAddSource
* @returns Promise
*/
// 新增来源渠道
export function addSource(data: IAddSource) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/source/addSource"
// 将 data 对象作为请求的主体
return http.post("/api/source/addSource", data);
}
/**
* getSourceById
* @param data - IGetSourceById
* @returns Promise
*/
// 根据编号查询来源渠道
export async function getSourceById(data: IGetSourceById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/source/getSourceById"
// 将 data 对象展开作为请求的参数
return http.get("/api/source/getSourceById", {
params: {
...data
@ -68,25 +39,13 @@ export async function getSourceById(data: IGetSourceById) {
});
}
/**
* editSource
* @param data - IAddSource
* @returns Promise
*/
// 编辑来源渠道
export function editSource(data: IAddSource) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/source/editSource"
// 将 data 对象作为请求的主体
return http.put("/api/source/editSource", data);
}
/**
* deleteSource
* @param data - IGetSourceById
* @returns Promise
*/
// 删除来源渠道
export async function deleteSource(data: IGetSourceById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/source/deleteSource"
// 将 data 对象展开作为请求的参数
return http.delete("/api/source/deleteSource", {
params: {
...data

@ -1,69 +1,38 @@
// 从 "@/utils" 模块导入名为 http 的对象,推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 定义一个接口 IPageStaffByKey用于描述分页查询员工时的请求参数结构
interface IPageStaffByKey {
// 角色 ID用于筛选员工类型为数字
roleId: number;
// 这里 roleName 的类型标注为 number 可能有误,通常角色名称应该是字符串类型,用于筛选员工
roleName: number;
// 员工姓名,用于筛选员工,类型为字符串
roleName:number;
name: string;
// 员工电话,用于筛选员工,类型为字符串
phone: string;
}
// 定义一个接口 IAddStaff用于描述新增员工时的数据结构
interface IAddStaff {
// 员工 ID类型为数字
id: number;
// 员工角色 ID类型为数字
roleId: number;
// 员工姓名,类型为字符串
name: string;
// 员工身份证号码,类型为字符串
idNum: string;
// 员工年龄,类型为数字
age: number;
// 员工性别,类型为字符串
sex: string;
// 员工电话,类型为字符串
phone: string;
// 员工邮箱,类型为字符串
email: string;
// 员工地址,类型为字符串
address: string;
// 员工头像地址,类型为字符串
avator: string;
}
// 定义一个接口 IGetStaffById用于描述根据员工编号查询员工时的请求参数结构
interface IGetStaffById {
// 员工 ID类型为字符串
staffId: string;
staffId: string
}
/**
* getRole
* @returns Promise
*/
// 获取角色列表
export async function getRole() {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/staff/getRole"
return http.get("/api/staff/getRole");
}
/**
* pageStaffByKey
* @param data - IPageStaffByKey
* @returns Promise
*/
// 分页查询员工
export async function pageStaffByKey(data: IPageStaffByKey) {
// 因为后台返回的字段与前端表单数据的 prop 不一样,
// 但是组件封装需要一样,所以请求前增加一些这两个字段
// 如果 data 对象中有 'roleName' 字段,则将其值赋给 'roleId' 字段,这里逻辑可能需要进一步确认合理性
Reflect.has(data, 'roleName')? (data.roleId = data.roleName) : '';
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/staff/pageStaffByKey"
// 将 data 对象展开作为请求的参数
// 因为后台返回的字段与前端表单数据的prop不一样但是组件封装是需要一样的所以请求前增加一些这两个字段
Reflect.has(data, 'roleName') ? (data.roleId = data.roleName) : ''
return http.get("/api/staff/pageStaffByKey", {
params: {
...data
@ -71,25 +40,13 @@ export async function pageStaffByKey(data: IPageStaffByKey) {
});
}
/**
* addStaff
* @param data - IAddStaff
* @returns Promise
*/
// 新增员工
export function addStaff(data: IAddStaff) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/staff/addStaff"
// 将 data 对象作为请求的主体
return http.post("/api/staff/addStaff", data);
}
/**
* getStaffById
* @param data - IGetStaffById
* @returns Promise
*/
// 根据老人编号查询员工
export async function getStaffById(data: IGetStaffById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/staff/getStaffById"
// 将 data 对象展开作为请求的参数
return http.get("/api/staff/getStaffById", {
params: {
...data
@ -97,25 +54,13 @@ export async function getStaffById(data: IGetStaffById) {
});
}
/**
* editStaff
* @param data - IAddStaff
* @returns Promise
*/
// 编辑员工
export function editStaff(data: IAddStaff) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/staff/editStaff"
// 将 data 对象作为请求的主体
return http.put("/api/staff/editStaff", data);
}
/**
* leaveStaff
* @param data - IGetStaffById
* @returns Promise
*/
// 删除员工
export async function leaveStaff(data: IGetStaffById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/staff/leaveStaff"
// 将 data 对象展开作为请求的参数
return http.delete("/api/staff/leaveStaff", {
params: {
...data

@ -1,106 +1,60 @@
// 从 '@/utils' 模块导入名为 http 的对象,推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from '@/utils';
import { http } from '@/utils'
// 定义一个接口 ILoginForm用于描述登录表单的数据结构
interface ILoginForm {
// 密码,类型为字符串
pass: string;
// 电话号码,类型为字符串
phone: string;
pass: string
phone: string
}
// 定义一个接口 ISendCodeForm用于描述发送验证码表单的数据结构
interface ISendCodeForm {
// 密码,类型为字符串
pass: string;
// 账号,类型为字符串
account: string;
pass: string
account: string
}
// 定义一个接口 IForgetPass用于描述忘记密码时的数据结构
interface IForgetPass {
// 验证码,类型为字符串
code: string;
// 新密码,类型为字符串
pass: string;
// 账号,类型为字符串
account: string;
code: string
pass: string
account: string
}
// 定义一个接口 IEditPass用于描述修改密码时的数据结构
interface IEditPass {
// 新密码,类型为字符串
newPass: string;
// 旧密码,类型为字符串
oldPass: string;
newPass: string
oldPass: string
}
// 定义一个类 IEditPassImpl实现了 IEditPass 接口,用于表示修改密码的数据实体
export class IEditPassImpl implements IEditPass {
// 新密码属性
newPass: string;
// 旧密码属性
oldPass: string;
// 构造函数,接收新密码和旧密码作为参数,并赋值给对应的属性
newPass: string
oldPass: string
constructor(newPass: string, oldPass: string) {
this.newPass = newPass;
this.oldPass = oldPass;
this.newPass = newPass
this.oldPass = oldPass
}
}
/**
* getLogin
* @param data - ILoginForm
* @returns Promise
*/
// 登录
export function getLogin(data: ILoginForm) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 '/api/account/login'
// 将 data 对象作为请求的主体
return http.post('/api/account/login', data);
return http.post('/api/account/login', data)
}
/**
* sendCode
* @param data - ISendCodeForm
* @returns Promise
*/
// 发送验证码
export async function sendCode(data: ISendCodeForm) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 '/api/account/sendCode'
// 将 data 对象展开作为请求的参数
return http.get('/api/account/sendCode', {
params: {
...data
}
});
})
}
/**
* forgetPass
* @param data - IForgetPass
* @returns Promise
*/
// 忘记密码
export async function forgetPass(data: IForgetPass) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/account/forget'
// 将 data 对象作为请求的主体
return http.put('/api/account/forget', data);
return http.put('/api/account/forget', data)
}
/**
* editPass
* @param data - IEditPass
* @returns Promise
*/
// 修改密码
export async function editPass(data: IEditPass) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 '/api/account/edit'
// 将 data 对象作为请求的主体
return http.put('/api/account/edit', data);
return http.put('/api/account/edit', data)
}
/**
* getLogout退
* @returns Promise 退
*/
// 退出登录
export async function getLogout() {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 '/api/account/logout'
return http.delete('/api/account/logout');
return http.delete('/api/account/logout')
}

@ -1,83 +1,49 @@
// 从 "@/utils" 模块导入名为 http 的对象,推测该对象是用于发起 HTTP 请求的工具,可能是对 axios 等请求库的封装
import { http } from "@/utils";
// 从 "@/apis/bookManage" 模块导入 IPageSearchElderByKey 接口,
// 用于描述分页搜索老人时的请求参数结构
import { IPageSearchElderByKey } from "@/apis/bookManage";
// 定义一个接口 IPageVisitByKey用于描述分页查询来访登记时的请求参数结构
interface IPageVisitByKey {
// 老人姓名,用于筛选来访登记记录,类型为字符串
elderName: string;
// 来访人姓名,用于筛选来访登记记录,类型为字符串
visitName: string;
// 来访人电话,用于筛选来访登记记录,类型为字符串
visitPhone: string;
// 来访状态标识,用于筛选来访登记记录,类型为字符串
visitFlag: string;
}
// 定义一个接口 IAddVisit用于描述新增来访登记时的数据结构
interface IAddVisit {
// 来访登记的 ID类型为数字
id: number;
// 老人 ID类型为数字
elderId: number;
// 来访人姓名,类型为字符串
name: string;
// 来访人电话,类型为字符串
phone: string;
// 与老人的关系,类型为字符串
relation: string;
// 来访日期,类型为字符串
visitDate: string;
// 来访次数,类型为数字
visitNum: number;
}
// 定义一个接口 IGetVisitById用于描述根据编号获取来访登记时的请求参数结构
interface IGetVisitById {
// 来访登记 ID类型为字符串
visitId: string;
}
// 定义一个接口 IEditVisit用于描述编辑来访登记时的数据结构
interface IEditVisit {
// 来访登记的 ID类型为数字
id: number;
// 来访人姓名,类型为字符串
name: string;
// 来访人电话,类型为字符串
phone: string;
// 与老人的关系,类型为字符串
relation: string;
// 来访日期字符串,类型为字符串
visitDateStr: string;
// 来访次数,类型为数字
visitNum: number;
}
// 定义一个接口 IRecordLeave用于描述登记离开时的数据结构
interface IRecordLeave {
// 来访登记 ID类型为字符串
id: string;
// 离开日期,类型为 any具体类型需根据实际情况确定
leaveDate: any;
}
// 定义一个名为 typeList 的常量,是一个包含来访状态选项的数组,每个选项有标签和对应的值
// 来访状态
export const typeList = [
{ label: "待离开", value: "待离开" },
{ label: "已离开", value: "已离开" }
];
/**
* pageVisitByKey访
* @param data - IPageVisitByKey
* @returns Promise 访
*/
// 分页查询来访登记
export async function pageVisitByKey(data: IPageVisitByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/visit/pageVisitByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/visit/pageVisitByKey", {
params: {
...data
@ -85,14 +51,8 @@ export async function pageVisitByKey(data: IPageVisitByKey) {
});
}
/**
* pageSearchElderByKey
* @param data - IPageSearchElderByKey
* @returns Promise
*/
// 分页搜索老人
export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/visit/pageSearchElderByKey"
// 将 data 对象展开作为请求的参数
return http.get("/api/visit/pageSearchElderByKey", {
params: {
...data
@ -100,25 +60,13 @@ export async function pageSearchElderByKey(data: IPageSearchElderByKey) {
});
}
/**
* addVisit访
* @param data - IAddVisit 访
* @returns Promise 访
*/
// 新增来访登记
export function addVisit(data: IAddVisit) {
// 使用导入的 http 对象发起 POST 请求,请求地址为 "/api/visit/addVisit"
// 将 data 对象作为请求的主体
return http.post("/api/visit/addVisit", data);
}
/**
* getVisitById访
* @param data - IGetVisitById 访
* @returns Promise 访
*/
// 根据编号获取来访登记
export async function getVisitById(data: IGetVisitById) {
// 使用导入的 http 对象发起 GET 请求,请求地址为 "/api/visit/getVisitById"
// 将 data 对象展开作为请求的参数
return http.get("/api/visit/getVisitById", {
params: {
...data
@ -126,36 +74,18 @@ export async function getVisitById(data: IGetVisitById) {
});
}
/**
* editVisit访
* @param data - IEditVisit 访
* @returns Promise 访
*/
// 编辑来访登记
export function editVisit(data: IEditVisit) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/visit/editVisit"
// 将 data 对象作为请求的主体
return http.put("/api/visit/editVisit", data);
}
/**
* recordLeave
* @param data - IRecordLeave
* @returns Promise
*/
// 登记离开
export function recordLeave(data: IRecordLeave) {
// 使用导入的 http 对象发起 PUT 请求,请求地址为 "/api/visit/recordLeave"
// 将 data 对象作为请求的主体
return http.put("/api/visit/recordLeave", data);
}
/**
* deleteVisit访
* @param data - IGetVisitById 访
* @returns Promise 访
*/
// 删除来访登记
export async function deleteVisit(data: IGetVisitById) {
// 使用导入的 http 对象发起 DELETE 请求,请求地址为 "/api/visit/deleteVisit"
// 将 data 对象展开作为请求的参数
return http.delete("/api/visit/deleteVisit", {
params: {
...data

@ -1,38 +1,23 @@
<template>
<!-- 根元素 div通过 style 绑定动态样式v-show 根据 isShow 的值控制元素的显示与隐藏 -->
<div :style="style" v-show="isShow">
<!-- 插槽用于在父组件中插入内容 -->
<slot></slot>
</div>
</template>
<script setup lang="ts" name="GridItem">
// vue
import { computed, inject, Ref, ref, useAttrs, watch } from 'vue'
// '../interface/index' BreakPoint Responsive
import { BreakPoint, Responsive } from '../interface/index'
// Props
type Props = {
// 0
offset?: number
// 1
span?: number
// false
suffix?: boolean
// xs undefined
xs?: Responsive
// sm undefined
sm?: Responsive
// md undefined
md?: Responsive
// lg undefined
lg?: Responsive
// xl undefined
xl?: Responsive
}
// 使 withDefaults defineProps
const props = withDefaults(defineProps<Props>(), {
offset: 0,
span: 1,
@ -44,63 +29,43 @@ const props = withDefaults(defineProps<Props>(), {
xl: undefined
})
// props
const attrs = useAttrs() as any
// isShow true
const isShow = ref(true)
// breakPoint Ref<BreakPoint> ref('xl')
//
const breakPoint = inject<Ref<BreakPoint>>('breakPoint', ref('xl'))
// shouldHiddenIndex Ref<number> ref(-1)
const shouldHiddenIndex = inject<Ref<number>>('shouldHiddenIndex', ref(-1))
// shouldHiddenIndex breakPoint
watch(
// shouldHiddenIndex.value breakPoint.value
() => [shouldHiddenIndex.value, breakPoint.value],
// n shouldHiddenIndex.value breakPoint.value
n => {
// attrs index
if (attrs.index) {
//
isShow.value =!(n[0]!== -1 && parseInt(attrs.index) >= n[0])
isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= n[0])
}
},
// immediate: true
{ immediate: true }
)
// gap 0
const gap = inject('gap', 0)
// cols Ref<number> ref(4)
const cols = inject<Ref<number>>('cols', ref(4))
// style props
const style = computed(() => {
// span 使 props.span
let span = props[breakPoint.value]?.span?? props.span
// offset 使 props.offset
let offset = props[breakPoint.value]?.offset?? props.offset
//
let span = props[breakPoint.value]?.span ?? props.span
let offset = props[breakPoint.value]?.offset ?? props.offset
if (props.suffix) {
return {
// gridColumnStart
gridColumnStart: cols.value - span - offset + 1,
// gridColumnEnd
gridColumnEnd: `span ${span + offset}`,
// marginLeft
marginLeft:
offset!== 0
offset !== 0
? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})`
: 'unset'
}
} else {
return {
// gridColumn
gridColumn: `span ${
span + offset > cols.value? cols.value : span + offset
}/span ${span + offset > cols.value? cols.value : span + offset}`,
// marginLeft
span + offset > cols.value ? cols.value : span + offset
}/span ${span + offset > cols.value ? cols.value : span + offset}`,
marginLeft:
offset!== 0
offset !== 0
? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})`
: 'unset'
}

@ -1,13 +1,10 @@
<template>
<!-- 根元素 div通过 style 绑定动态样式用于包裹插槽内容 -->
<div :style="style">
<!-- 插槽用于父组件插入内容 -->
<slot></slot>
</div>
</template>
<script setup lang="ts" name="Grid">
// 'vue' Vue
import {
ref,
watch,
@ -22,68 +19,50 @@ import {
VNodeArrayChildren,
VNode
} from 'vue'
// BreakPoint
import type { BreakPoint } from './interface/index'
// Props
type Props = {
//
cols?: number | Record<BreakPoint, number>
// false
collapsed?: boolean
// 1
collapsedRows?: number
// [, ]
gap?: [number, number] | number
}
// 使 withDefaults
const props = withDefaults(defineProps<Props>(), {
//
cols: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }),
//
collapsed: false,
// 1
collapsedRows: 1,
// 0
gap: 0
})
// collapsed true findIndex
onBeforeMount(() => props.collapsed && findIndex())
// resize window resize
onMounted(() => {
resize({ target: { innerWidth: window.innerWidth } } as any)
window.addEventListener('resize', resize)
})
// resize window resize
onActivated(() => {
resize({ target: { innerWidth: window.innerWidth } } as any)
window.addEventListener('resize', resize)
})
// window resize
onUnmounted(() => {
window.removeEventListener('resize', resize)
})
// window resize
onDeactivated(() => {
window.removeEventListener('resize', resize)
})
// resize breakPoint
//
const resize = (e: UIEvent) => {
//
let width = (e.target as Window).innerWidth
// breakPoint
switch (!!width) {
case width < 768:
breakPoint.value = 'xs'
break
case width >= 768 && width < 992:
breakPoint.value ='sm'
breakPoint.value = 'sm'
break
case width >= 992 && width < 1200:
breakPoint.value ='md'
breakPoint.value = 'md'
break
case width >= 1200 && width < 1920:
breakPoint.value = 'lg'
@ -94,66 +73,58 @@ const resize = (e: UIEvent) => {
}
}
// gap gap 使 gap
provide('gap', Array.isArray(props.gap)? props.gap[0] : props.gap)
// gap
provide('gap', Array.isArray(props.gap) ? props.gap[0] : props.gap)
// breakPoint
//
let breakPoint = ref<BreakPoint>('xl')
provide('breakPoint', breakPoint)
// index
// index
const hiddenIndex = ref(-1)
provide('shouldHiddenIndex', hiddenIndex)
// cols cols breakPoint 使 cols
// cols
const cols = computed(() => {
if (typeof props.cols === 'object')
return props.cols[breakPoint.value]?? props.cols
return props.cols[breakPoint.value] ?? props.cols
return props.cols
})
provide('cols', cols)
//
const slots = useSlots().default!()
// findIndex index
// index
const findIndex = () => {
//
let fields: VNodeArrayChildren = []
//
let suffix: any = null
//
slots.forEach((slot: any) => {
// 'GridItem' suffix
if (
typeof slot.type === 'object' &&
slot.type.name === 'GridItem' &&
slot.props?.suffix!== undefined
slot.props?.suffix !== undefined
)
suffix = slot
// symbol
if (typeof slot.type ==='symbol' && Array.isArray(slot.children))
if (typeof slot.type === 'symbol' && Array.isArray(slot.children))
slot.children.forEach((child: any) => fields.push(child))
})
// suffix
// suffix
let suffixCols = 0
if (suffix) {
suffixCols =
(suffix.props![breakPoint.value]?.span?? suffix.props?.span?? 1) +
(suffix.props![breakPoint.value]?.offset?? suffix.props?.offset?? 0)
(suffix.props![breakPoint.value]?.span ?? suffix.props?.span ?? 1) +
(suffix.props![breakPoint.value]?.offset ?? suffix.props?.offset ?? 0)
}
try {
//
let find = false
//
fields.reduce((prev = 0, current, index) => {
prev +=
((current as VNode)!.props![breakPoint.value]?.span??
(current as VNode)!.props?.span??
((current as VNode)!.props![breakPoint.value]?.span ??
(current as VNode)!.props?.span ??
1) +
((current as VNode)!.props![breakPoint.value]?.offset??
(current as VNode)!.props?.offset??
((current as VNode)!.props![breakPoint.value]?.offset ??
(current as VNode)!.props?.offset ??
0)
if ((prev as number) > props.collapsedRows * cols.value - suffixCols) {
hiddenIndex.value = index
@ -162,14 +133,13 @@ const findIndex = () => {
}
return prev
}, 0)
// hiddenIndex -1
if (!find) hiddenIndex.value = -1
} catch (e) {
// console.warn(e);
}
}
// breakPoint collapsed true findIndex
// findIndex
watch(
() => breakPoint.value,
() => {
@ -177,7 +147,7 @@ watch(
}
)
// collapsed true findIndex hiddenIndex -1
// collapsed
watch(
() => props.collapsed,
value => {
@ -186,14 +156,14 @@ watch(
}
)
//
//
const gap = computed(() => {
if (typeof props.gap === 'number') return `${props.gap}px`
if (Array.isArray(props.gap)) return `${props.gap[1]}px ${props.gap[0]}px`
return 'unset'
})
//
// style
const style = computed(() => {
return {
display: 'grid',
@ -202,6 +172,5 @@ const style = computed(() => {
}
})
// breakPoint便访
defineExpose({ breakPoint })
</script>

@ -1,12 +1,6 @@
// 定义一个类型别名 BreakPoint它的值只能是 'xs'、'sm'、'md'、'lg' 或 'xl' 中的一个,
// 通常用于表示响应式布局中的不同屏幕断点
export type BreakPoint = 'xs' |'sm' |'md' | 'lg' | 'xl';
export type BreakPoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
// 定义一个类型别名 Responsive它是一个对象类型包含两个可选属性 span 和 offset。
// span 用于表示在响应式布局中元素所占的列数,类型为 number 类型的可选值。
// offset 用于表示在响应式布局中元素的偏移量,类型为 number 类型的可选值。
// 这个类型通常用于描述在不同屏幕断点下元素的布局属性
export type Responsive = {
span?: number;
offset?: number;
};
span?: number
offset?: number
}

@ -1,12 +1,4 @@
<template>
<!-- Component Vue 中的动态组件:is="icon" 表示根据 icon 的值来动态渲染对应的图标组件 -->
<!-- :theme="theme" 绑定图标主题如轮廓outline填充filled -->
<!-- :size="size" 绑定图标大小可以是数字或字符串类型 -->
<!-- :spin="spin" 绑定图标是否旋转的状态布尔类型 -->
<!-- :fill="fill" 绑定图标的填充颜色可以是字符串或字符串数组 -->
<!-- :strokeLinecap="strokeLinecap" 绑定图标描边端点的样式 -->
<!-- :strokeLinejoin="strokeLinejoin" 绑定图标描边连接处的样式 -->
<!-- :strokeWidth="strokeWidth" 绑定图标描边的宽度 -->
<Component
:is="icon"
:theme="theme"
@ -20,26 +12,16 @@
</template>
<script setup lang="ts">
// '@icon-park/vue-next/lib/runtime' Icon
import type { Icon } from '@icon-park/vue-next/lib/runtime'
// 使 defineProps
defineProps<{
// icon Icon
icon: Icon
// theme 'outline' | 'filled' | 'two-tone' |'multi-color'
theme?: 'outline' | 'filled' | 'two-tone' |'multi-color'
// size number | string
theme?: 'outline' | 'filled' | 'two-tone' | 'multi-color'
size?: number | string
// spin boolean
spin?: boolean
// fill string | string[]
fill?: string | string[]
// strokeLinecap 'butt' | 'round' |'square'
strokeLinecap?: 'butt' | 'round' |'square'
// strokeLinejoin 'miter' | 'round' | 'bevel'
strokeLinecap?: 'butt' | 'round' | 'square'
strokeLinejoin?: 'miter' | 'round' | 'bevel'
// strokeWidth number
strokeWidth?: number
}>()
</script>

@ -1,18 +1,7 @@
<template>
<!-- 注释说明该部分是列设置 -->
<!-- el-drawer Element Plus 中的抽屉组件用于展示列设置的内容 -->
<!-- title="列设置" 设置抽屉的标题 -->
<!-- v-model="drawerVisible" 双向绑定抽屉的显示隐藏状态drawerVisible 是一个响应式变量 -->
<!-- size="450px" 设置抽屉的宽度为 450px -->
<!-- 列设置 -->
<el-drawer title="列设置" v-model="drawerVisible" size="450px">
<!-- 定义一个包含表格的 div 容器 -->
<div class="table-main">
<!-- el-table Element Plus 中的表格组件用于展示列设置的数据 -->
<!-- :data="colSetting" 绑定表格的数据colSetting 是一个数组包含列的设置信息 -->
<!-- :border="true" 设置表格有边框 -->
<!-- row-key="prop" 为表格的每一行设置唯一的标识这里使用 prop 作为标识 -->
<!-- default-expand-all 表示默认展开所有行对于树形表格 -->
<!-- :tree-props="{ children: '_children' }" 配置表格为树形表格指定子节点的字段为 _children -->
<el-table
:data="colSetting"
:border="true"
@ -20,34 +9,23 @@
default-expand-all
:tree-props="{ children: '_children' }"
>
<!-- el-table-column 是表格列组件用于定义表格的列 -->
<!-- prop="label" 绑定列的数据字段为 label -->
<!-- align="center" 设置列内容居中对齐 -->
<!-- label="列名" 设置列的标题为列名 -->
<el-table-column prop="label" align="center" label="列名" />
<!-- 定义显示列prop="isShow" 绑定数据字段为 isShow -->
<!-- v-slot="scope" 定义作用域插槽scope 包含当前行的数据 -->
<el-table-column
prop="isShow"
align="center"
label="显示"
v-slot="scope"
>
<!-- el-switch Element Plus 中的开关组件v-model="scope.row.isShow" 双向绑定当前行的 isShow 字段 -->
<el-switch v-model="scope.row.isShow"></el-switch>
</el-table-column>
<!-- 定义排序列prop="sortable" 绑定数据字段为 sortable -->
<!-- v-slot="scope" 定义作用域插槽scope 包含当前行的数据 -->
<el-table-column
prop="sortable"
align="center"
label="排序"
v-slot="scope"
>
<!-- el-switch Element Plus 中的开关组件v-model="scope.row.sortable" 双向绑定当前行的 sortable 字段 -->
<el-switch v-model="scope.row.sortable"></el-switch>
</el-table-column>
<!-- 定义表格为空时显示的内容#empty 是表格的 empty 插槽 -->
<template #empty>
<div class="table-empty">
<div>暂无可配置列</div>
@ -59,29 +37,23 @@
</template>
<script setup lang="ts" name="ColSetting">
// Vue ref
import { ref } from 'vue'
// ProTable ColumnProps
import { ColumnProps } from '@/components/ProTable/interface'
// 使 defineProps colSetting ColumnProps
defineProps<{ colSetting: ColumnProps[] }>()
// drawerVisible false
const drawerVisible = ref<boolean>(false)
// openColSetting drawerVisible true
//
const openColSetting = () => {
drawerVisible.value = true
}
// openColSetting 便
defineExpose({
openColSetting
})
</script>
<style scoped lang="scss">
// cursor-move move
.cursor-move {
cursor: move;
}

@ -1,14 +1,5 @@
<template>
<!-- 注释说明该部分是分页组件 -->
<!-- el-pagination Element Plus 中的分页组件 -->
<!-- :current-page="pageable.pageNum" 双向绑定当前页码pageable.pageNum 是一个响应式变量表示当前页码 -->
<!-- :page-size="pageable.pageSize" 双向绑定每页显示的数量pageable.pageSize 是一个响应式变量表示每页显示的数量 -->
<!-- :page-sizes="[10, 25, 50, 100]" 设置每页显示数量的可选值 -->
<!-- :background="true" 设置分页组件的背景颜色 -->
<!-- layout="total, sizes, prev, pager, next, jumper" 设置分页组件的布局包括总数量每页显示数量选择器上一页页码下一页跳转到指定页 -->
<!-- :total="pageable.total" 绑定总数量pageable.total 是一个响应式变量表示数据的总数量 -->
<!-- @size-change="handleSizeChange" 监听每页显示数量改变的事件当用户选择不同的每页显示数量时会调用 handleSizeChange 函数 -->
<!-- @current-change="handleCurrentChange" 监听当前页码改变的事件当用户点击上一页下一页或跳转到指定页时会调用 handleCurrentChange 函数 -->
<!-- 分页组件 -->
<el-pagination
:current-page="pageable.pageNum"
:page-size="pageable.pageSize"
@ -22,26 +13,17 @@
</template>
<script setup lang="ts" name="Pagination">
// Pageable
// pageNum number
// pageSize number
// total number
interface Pageable {
pageNum: number
pageSize: number
total: number
}
// PaginationProps
// pageable Pageable
// handleSizeChange number size
// handleCurrentChange number currentPage
interface PaginationProps {
pageable: Pageable
handleSizeChange: (size: number) => void
handleCurrentChange: (currentPage: number) => void
}
// 使 defineProps PaginationProps
defineProps<PaginationProps>()
</script>

@ -1,42 +1,31 @@
<template>
<!-- 使用动态组件根据 renderLoop 函数的返回值来渲染不同的表格列 -->
<component :is="renderLoop(column)"></component>
</template>
<script lang="tsx" setup name="TableColumn">
// vue
import { inject, ref, useSlots } from 'vue'
// ProTable ColumnProps
import { ColumnProps } from '@/components/ProTable/interface'
//
import { filterEnum, formatValue, handleRowAccordingToProp } from '@/utils/util'
// 使 defineProps column ColumnProps
defineProps<{ column: ColumnProps }>()
//
const slots = useSlots()
// enumMap Ref<Map<any, any>> Map
const enumMap = inject('enumMap', ref(new Map()))
// renderCellData
//
const renderCellData = (item: ColumnProps, scope: { [key: string]: any }) => {
// prop enumMap
return enumMap.value.get(item.prop) && item.isFilterEnum
// filterEnum
? filterEnum(
handleRowAccordingToProp(scope.row, item.prop!),
enumMap.value.get(item.prop)!,
item.fieldNames
)
//
handleRowAccordingToProp(scope.row, item.prop!),
enumMap.value.get(item.prop)!,
item.fieldNames
)
: formatValue(handleRowAccordingToProp(scope.row, item.prop!))
}
// getTagType
// tag
const getTagType = (item: ColumnProps, scope: { [key: string]: any }) => {
// filterEnum
return filterEnum(
handleRowAccordingToProp(scope.row, item.prop!),
enumMap.value.get(item.prop),
@ -45,53 +34,35 @@ const getTagType = (item: ColumnProps, scope: { [key: string]: any }) => {
) as any
}
// renderLoop
const renderLoop = (item: ColumnProps) => {
return (
<>
//
{item.isShow && (
// el-table-column
<el-table-column
//
{...item}
//
align={item.align?? 'center'}
// prop 'operation'
align={item.align ?? 'center'}
showOverflowTooltip={
item.showOverflowTooltip?? item.prop!== 'operation'
item.showOverflowTooltip ?? item.prop !== 'operation'
}
>
{{
//
default: (scope: any) => {
//
if (item._children)
//
return item._children.map(child => renderLoop(child))
//
if (item.render) return item.render(scope)
// prop
if (slots[item.prop!]) return slots[item.prop!]!(scope)
//
if (item.tag)
return (
// el-tag
<el-tag type={getTagType(item, scope)}>
{renderCellData(item, scope)}
</el-tag>
)
//
return renderCellData(item, scope)
},
//
header: () => {
//
if (item.headerRender) return item.headerRender(item)
// propHeader
if (slots[`${item.prop}Header`])
return slots[`${item.prop}Header`]!({ row: item })
// label
return item.label
}
}}

@ -2,14 +2,6 @@
<template>
<!-- 查询表单 card -->
<!-- SearchForm 是自定义的搜索表单组件 -->
<!-- :search="search" 绑定搜索方法 -->
<!-- :reset="reset" 绑定重置方法 -->
<!-- :searchParam="searchParam" 绑定搜索参数 -->
<!-- :columns="searchColumns" 绑定搜索列配置 -->
<!-- :searchCol="searchCol" 绑定搜索项每列占比配置 -->
<!-- v-show="isShowSearch" 根据 isShowSearch 的值显示或隐藏搜索表单 -->
<!-- ref="searchForm" 为搜索表单组件添加引用 -->
<SearchForm
:search="search"
:reset="reset"
@ -21,12 +13,11 @@
/>
<!-- 表格内容 card -->
<MyCard class="mt-2">
<div class="card table-main">
<MyCard class="mt-2"
><div class="card table-main">
<div class="table-header">
<div class="flex justify-between header-button-lf mb-2">
<div>
<!-- 具名插槽 tableHeader传递了 selectedListIdsselectedList isSelected 数据 -->
<slot
name="tableHeader"
:selectedListIds="selectedListIds"
@ -36,19 +27,15 @@
</div>
<div class="header-button-ri">
<!-- 具名插槽 toolButton包含了一些功能按钮 -->
<slot name="toolButton">
<!-- 刷新按钮点击时调用 getTableList 方法获取表格数据 -->
<el-button :icon="Refresh" circle @click="getTableList" />
<!-- <el-button :icon="Printer" circle v-if="columns.length" @click="handlePrint" /> -->
<!-- 列设置按钮 columns 存在时显示点击时调用 openColSetting 方法打开列设置 -->
<el-button
:icon="Operation"
circle
v-if="columns.length"
@click="openColSetting"
/>
<!-- 搜索按钮 searchColumns 存在时显示点击时切换 isShowSearch 的值显示或隐藏搜索表单 -->
<el-button
:icon="Search"
circle
@ -60,13 +47,6 @@
</div>
</div>
<!-- 表格主体 -->
<!-- el-table Element Plus 的表格组件 -->
<!-- ref="tableRef" 为表格组件添加引用 -->
<!-- v-bind="$attrs" 绑定父组件传递的所有属性 -->
<!-- :data="tableData" 绑定表格数据 -->
<!-- :border="border" 绑定表格是否有纵向边框 -->
<!-- :row-key="rowKey" 绑定行数据的唯一标识 -->
<!-- @selection-change="selectionChange" 监听表格行选择变化事件 -->
<el-table
ref="tableRef"
v-bind="$attrs"
@ -77,35 +57,31 @@
>
<!-- 默认插槽 -->
<slot></slot>
<!-- 循环渲染表格列 -->
<template v-for="item in tableColumns" :key="item">
<!-- selection || index 类型的列 -->
<!-- selection || index -->
<el-table-column
v-bind="item"
:align="item.align?? 'center'"
:reserve-selection="item.type =='selection'"
v-if="item.type =='selection' || item.type == 'index'"
:align="item.align ?? 'center'"
:reserve-selection="item.type == 'selection'"
v-if="item.type == 'selection' || item.type == 'index'"
>
</el-table-column>
<!-- expand 类型的列支持 tsx 语法和作用域插槽 -->
<!-- expand 支持 tsx 语法 && 作用域插槽 (tsx > slot) -->
<el-table-column
v-bind="item"
:align="item.align?? 'center'"
:align="item.align ?? 'center'"
v-if="item.type == 'expand'"
v-slot="scope"
>
<!-- 如果有自定义渲染函数则使用该函数渲染 -->
<component :is="item.render" :row="scope.row" v-if="item.render">
</component>
<!-- 否则使用插槽渲染 -->
<slot :name="item.type" :row="scope.row" v-else></slot>
</el-table-column>
<!-- 其他类型的列通过 TableColumn 组件递归渲染 -->
<!-- other 循环递归 -->
<TableColumn
v-if="!item.type && item.prop && item.isShow"
:column="item"
>
<!-- 循环渲染插槽内容 -->
<template v-for="slot in Object.keys($slots)" #[slot]="scope">
<slot :name="slot" :row="scope.row"></slot>
</template>
@ -124,10 +100,9 @@
</div>
</template>
</el-table>
<!-- 分页组件插槽 -->
<!-- 分页组件 -->
<slot name="pagination">
<div class="mt-2 flex flex-row-reverse">
<!-- Pagination 是自定义的分页组件 pagination true 时显示 -->
<Pagination
v-if="pagination"
:pageable="pageable"
@ -135,78 +110,50 @@
:handleCurrentChange="handleCurrentChange"
/>
</div>
</slot>
</div>
</MyCard>
</slot></div
></MyCard>
<!-- 列设置 -->
<!-- ColSetting 是自定义的列设置组件 toolButton true 时显示 -->
<!-- v-model:colSetting="colSetting" 双向绑定列设置数据 -->
<ColSetting v-if="toolButton" ref="colRef" v-model:colSetting="colSetting" />
</template>
<script setup lang="ts" name="ProTable">
// Vue
import { ref, watch, computed, provide, onMounted } from 'vue'
// Hooks
import { useTable } from '@/hooks/useTable'
//
import { BreakPoint } from '@/components/Grid/interface'
//
import { ColumnProps } from '@/components/ProTable/interface'
// Element Plus
import { ElTable, TableProps } from 'element-plus'
// Element Plus
import { Refresh, Printer, Operation, Search } from '@element-plus/icons-vue'
//
import {
filterEnum,
formatValue,
handleProp,
handleRowAccordingToProp
} from '@/utils/util'
//
import SearchForm from '@/components/SearchForm/index.vue'
//
import Pagination from './components/Pagination.vue'
//
import ColSetting from './components/ColSetting.vue'
//
import TableColumn from './components/TableColumn.vue'
// Hooks
import { useSelection } from '@/hooks/useSelection'
// import printJS from "print-js";
//
const searchForm = ref()
// ProTable TableProps data
interface ProTableProps extends Partial<Omit<TableProps<any>, 'data'>> {
//
columns: ColumnProps[]
// API
requestApi: (params: any) => Promise<any>
//
columns: ColumnProps[] //
requestApi: (params: any) => Promise<any> // api ==>
requestAuto?: boolean
//
dataCallback?: (data: any) => any
//
title?: string
// true
pagination?: boolean
// {}
initParam?: any
// true
border?: boolean
// true
toolButton?: boolean
// Key Table id id
rowKey?: string
// { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }
searchCol?: number | Record<BreakPoint, number>
dataCallback?: (data: any) => any // ==>
title?: string // ==>
pagination?: boolean // ==> true
initParam?: any // ==> {}
border?: boolean // ==> true
toolButton?: boolean // ==> true
rowKey?: string // Key Table id ==> id
searchCol?: number | Record<BreakPoint, number> // ==> { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }
}
//
//
const props = withDefaults(defineProps<ProTableProps>(), {
requestAuto: true,
columns: () => [],
@ -218,17 +165,17 @@ const props = withDefaults(defineProps<ProTableProps>(), {
searchCol: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 })
})
//
//
const isShowSearch = ref(true)
// DOM
// DOM
const tableRef = ref<InstanceType<typeof ElTable>>()
// 使 Hooks
// Hooks
const { selectionChange, selectedList, selectedListIds, isSelected } =
useSelection(props.rowKey)
// 使 Hooks
// Hooks
const {
tableData,
pageable,
@ -246,99 +193,90 @@ const {
props.dataCallback
)
//
//
const clearSelection = () => tableRef.value!.clearSelection()
// requestAuto true getTableList
//
onMounted(() => props.requestAuto && getTableList())
// initParam
// initParam
watch(() => props.initParam, getTableList, { deep: true })
//
// columns
const tableColumns = ref<ColumnProps[]>(props.columns)
// enumMap provide
// enumMap enum ||
const enumMap = ref(new Map<string, { [key: string]: any }[]>())
provide('enumMap', enumMap)
// enumMap
const setEnumMap = async (col: ColumnProps) => {
if (!col.enum) return
// enum enumMap
if (typeof col.enum!== 'function')
// enum enumMap
if (typeof col.enum !== 'function')
return enumMap.value.set(col.prop!, col.enum!)
// enum enumMap
const { data } = await col.enum()
enumMap.value.set(col.prop!, data)
}
// columns
// columns
const flatColumnsFunc = (
columns: ColumnProps[],
flatArr: ColumnProps[] = []
) => {
columns.forEach(async col => {
//
if (col._children?.length) flatArr.push(...flatColumnsFunc(col._children))
flatArr.push(col)
// column isShow isFilterEnum
col.isShow = col.isShow?? true
col.isFilterEnum = col.isFilterEnum?? true
// column isShow && isFilterEnum
col.isShow = col.isShow ?? true
col.isFilterEnum = col.isFilterEnum ?? true
// enumMap
setEnumMap(col)
})
//
return flatArr.filter(item =>!item._children?.length)
return flatArr.filter(item => !item._children?.length)
}
// columns
// flatColumns
const flatColumns = ref<ColumnProps[]>()
flatColumns.value = flatColumnsFunc(tableColumns.value)
//
//
const searchColumns = flatColumns.value.filter(item => item.search?.el)
//
// &&
searchColumns.forEach((column, index) => {
column.search!.order = column.search!.order?? index + 2
column.search!.order = column.search!.order ?? index + 2
if (
column.search?.defaultValue!== undefined &&
column.search?.defaultValue!== null
column.search?.defaultValue !== undefined &&
column.search?.defaultValue !== null
) {
searchInitParam.value[column.search.key?? handleProp(column.prop!)] =
searchInitParam.value[column.search.key ?? handleProp(column.prop!)] =
column.search?.defaultValue
searchParam.value[column.search.key?? handleProp(column.prop!)] =
searchParam.value[column.search.key ?? handleProp(column.prop!)] =
column.search?.defaultValue
}
})
//
//
searchColumns.sort((a, b) => a.search!.order! - b.search!.order!)
//
// ==>
const colRef = ref()
//
const colSetting = tableColumns.value!.filter(
item =>
![
'selection',
'index',
'expand'
].includes(item.type!) && item.prop!== 'operation'
!['selection', 'index', 'expand'].includes(item.type!) &&
item.prop !== 'operation'
)
//
const openColSetting = () => colRef.value.openColSetting()
// 201-238
// enum
// enum
const printData = computed(() => {
const printDataList = JSON.parse(
JSON.stringify(
selectedList.value.length? selectedList.value : tableData.value
selectedList.value.length ? selectedList.value : tableData.value
)
)
//
// enum || prop && enum
const needTransformCol = flatColumns.value!.filter(
item =>
(item.enum || (item.prop && item.prop.split('.').length > 1)) &&
@ -347,13 +285,13 @@ const printData = computed(() => {
needTransformCol.forEach(colItem => {
printDataList.forEach((tableItem: { [key: string]: any }) => {
tableItem[handleProp(colItem.prop!)] =
colItem.prop!.split('.').length > 1 &&!colItem.enum
colItem.prop!.split('.').length > 1 && !colItem.enum
? formatValue(handleRowAccordingToProp(tableItem, colItem.prop!))
: filterEnum(
handleRowAccordingToProp(tableItem, colItem.prop!),
enumMap.value.get(colItem.prop!),
colItem.fieldNames
)
handleRowAccordingToProp(tableItem, colItem.prop!),
enumMap.value.get(colItem.prop!),
colItem.fieldNames
)
for (const key in tableItem) {
if (tableItem[key] === null)
tableItem[key] = formatValue(tableItem[key])
@ -380,7 +318,7 @@ const printData = computed(() => {
// });
// };
//
// ()
defineExpose({
element: tableRef,
tableData,

@ -1,32 +1,17 @@
// 从 "element-plus/es/components/table/src/table-column/defaults" 导入 TableColumnCtx 类型
// TableColumnCtx 可能是 Element Plus 中表格列的上下文类型,包含了表格列的一些默认属性和方法
import { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
// 从 "@/components/Grid/interface" 导入 BreakPoint 和 Responsive 类型
// BreakPoint 可能表示响应式布局中的不同断点(如 xs, sm, md, lg, xl 等)
// Responsive 可能用于描述在不同断点下的响应式配置
import { BreakPoint, Responsive } from "@/components/Grid/interface";
// 定义一个接口 EnumProps用于描述枚举属性
export interface EnumProps {
// 选项框显示的文字,类型为字符串
label: string;
// 选项框值,可以是任意类型
value: any;
// 是否禁用此选项,可选,默认为 undefined类型为布尔值
disabled?: boolean;
// 当 tag 为 true 时,此选择会指定 tag 显示类型,可选,默认为 undefined类型为字符串
tagType?: string;
// 为树形选择时,可以通过 children 属性指定子选项,可选,默认为 undefined类型为 EnumProps 数组
children?: EnumProps[];
// 允许添加任意其他属性,属性名和值的类型都为任意类型
label: string; // 选项框显示的文字
value: any; // 选项框值
disabled?: boolean; // 是否禁用此选项
tagType?: string; // 当 tag 为 true 时,此选择会指定 tag 显示类型
children?: EnumProps[]; // 为树形选择时,可以通过 children 属性指定子选项
[key: string]: any;
}
// 定义一个类型别名 TypeProp其值只能是 "index"、"selection" 或 "expand" 中的一个
export type TypeProp = "index" | "selection" | "expand";
export type TypeProp = "index" | "selection" | "expand"
// 定义一个类型别名 SearchType用于表示搜索框的类型
// 可以是 "input"、"input-number" 等多种 Element Plus 组件类型
export type SearchType =
| "input"
| "input-number"
@ -38,47 +23,27 @@ export type SearchType =
| "time-picker"
| "time-select"
| "switch"
| "slider";
| "slider"
// 定义一个接口 SearchProps用于描述搜索项的属性
export type SearchProps = {
// 当前项搜索框的类型,类型为 SearchType
el: SearchType;
// 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件,可选,默认为 undefined
props?: any;
// 当搜索项 key 不为 prop 属性时,可通过 key 指定,可选,默认为 undefined类型为字符串
key?: string;
// 搜索项排序(从大到小),可选,默认为 undefined类型为数字
order?: number;
// 搜索项所占用的列数,默认为 1 列,可选,默认为 undefined类型为数字
span?: number;
// 搜索字段左侧偏移列数,可选,默认为 undefined类型为数字
offset?: number;
// 搜索项默认值,可以是字符串、数字、布尔值或任意类型的数组,可选,默认为 undefined
defaultValue?: string | number | boolean | any[];
// 扩展为包含 BreakPoint 类型的键和 Responsive 类型的值的部分记录,用于实现响应式配置
} & Partial<Record<BreakPoint, Responsive>>;
el: SearchType // 当前项搜索框的类型
props?: any // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
key?: string // 当搜索项 key 不为 prop 属性时,可通过 key 指定
order?: number // 搜索项排序(从大到小)
span?: number // 搜索项所占用的列数默认为1列
offset?: number // 搜索字段左侧偏移列数
defaultValue?: string | number | boolean | any[] // 搜索项默认值
} & Partial<Record<BreakPoint, Responsive>>
// 定义一个接口 ColumnProps用于描述表格列的属性
// 扩展自 Partial<Omit<TableColumnCtx<T>, "children" | "renderHeader" | "renderCell">>,表示部分继承 TableColumnCtx 类型并去除 "children"、"renderHeader" 和 "renderCell" 属性
export interface ColumnProps<T = any>
extends Partial<Omit<TableColumnCtx<T>, "children" | "renderHeader" | "renderCell">> {
// 是否是标签展示,可选,默认为 undefined类型为布尔值
tag?: boolean;
// 是否显示在表格当中,可选,默认为 undefined类型为布尔值
isShow?: boolean;
// 搜索项配置,可选,默认为 undefined类型为 SearchProps 或 undefined
search?: SearchProps | undefined;
// 枚举类型(渲染值的字典),可以是 EnumProps 数组或一个返回 Promise<any> 的函数,可选,默认为 undefined
enum?: EnumProps[] | ((params?: any) => Promise<any>);
// 当前单元格值是否根据 enum 格式化示例enum 只作为搜索项数据),可选,默认为 undefined类型为布尔值
isFilterEnum?: boolean;
// 指定 label && value 的 key 值,可选,默认为 undefined类型为包含 label 和 value 键的对象
fieldNames?: { label: string; value: string };
// 自定义表头内容渲染tsx语法可选默认为 undefined类型为一个接受 ColumnProps 类型参数并返回任意类型的函数
headerRender?: (row: ColumnProps) => any;
// 自定义单元格内容渲染tsx语法可选默认为 undefined类型为一个接受包含 row 属性且类型为 T 的对象并返回任意类型的函数
render?: (scope: { row: T }) => any;
// 多级表头,可选,默认为 undefined类型为 ColumnProps<T> 数组
_children?: ColumnProps<T>[];
tag?: boolean; // 是否是标签展示
isShow?: boolean; // 是否显示在表格当中
search?: SearchProps | undefined; // 搜索项配置
enum?: EnumProps[] | ((params?: any) => Promise<any>); // 枚举类型(渲染值的字典)
isFilterEnum?: boolean; // 当前单元格值是否根据 enum 格式化示例enum 只作为搜索项数据)
fieldNames?: { label: string; value: string }; // 指定 label && value 的 key 值
headerRender?: (row: ColumnProps) => any; // 自定义表头内容渲染tsx语法
render?: (scope: { row: T }) => any; // 自定义单元格内容渲染tsx语法
_children?: ColumnProps<T>[]; // 多级表头
}

@ -1,12 +1,6 @@
// 从当前目录下的 src 文件夹中的 index.vue 文件导入组件
// 这里将导入的组件命名为 reImageVerify它应该是一个 Vue 组件
import reImageVerify from './src/index.vue'
/** 图形验证码组件 */
// 使用具名导出的方式,将导入的组件以 ReImageVerify 这个名称导出
// 具名导出允许在导入时指定具体要导入的内容,方便在其他文件中使用
export const ReImageVerify = reImageVerify
// 使用默认导出的方式,将导入的组件作为默认导出
// 默认导出允许在导入时可以使用任意名称来接收该组件,通常一个文件只能有一个默认导出
export default ReImageVerify

@ -5,32 +5,23 @@ import { ref, onMounted } from 'vue'
* @param width -
* @param height -
*/
// 定义一个名为 useImageVerify 的函数,用于生成和管理图形验证码,接受图形宽度和高度作为参数,有默认值
export const useImageVerify = (width = 120, height = 40) => {
// 创建一个响应式引用 domRef用于存储 <canvas> 元素的引用
const domRef = ref<HTMLCanvasElement>()
// 创建一个响应式变量 imgCode用于存储生成的图形验证码字符串
const imgCode = ref('')
// 定义一个函数 setImgCode用于设置 imgCode 的值
function setImgCode(code: string) {
imgCode.value = code
}
// 定义一个函数 getImgCode用于在 <canvas> 上绘制验证码并获取生成的验证码字符串
function getImgCode() {
// 如果 domRef 没有值(即 <canvas> 元素未挂载),则直接返回
if (!domRef.value) return
// 调用 draw 函数绘制验证码,并将返回的验证码字符串赋值给 imgCode
imgCode.value = draw(domRef.value, width, height)
}
// 在组件挂载后执行的钩子函数,调用 getImgCode 函数生成验证码
onMounted(() => {
getImgCode()
})
// 返回一个包含 domRef、imgCode、setImgCode 和 getImgCode 的对象,以便在其他地方使用这些变量和函数
return {
domRef,
imgCode,
@ -39,95 +30,56 @@ export const useImageVerify = (width = 120, height = 40) => {
}
}
// 定义一个函数 randomNum用于生成指定范围内的随机整数
function randomNum(min: number, max: number) {
// 使用 Math.random() 生成一个 0 到 1 之间的随机小数,然后通过计算得到指定范围内的整数
const num = Math.floor(Math.random() * (max - min) + min)
return num
}
// 定义一个函数 randomColor用于生成指定范围内的随机颜色RGB 格式)
function randomColor(min: number, max: number) {
// 分别生成随机的红r、绿g、蓝b分量值
const r = randomNum(min, max)
const g = randomNum(min, max)
const b = randomNum(min, max)
// 返回 RGB 格式的颜色字符串
return `rgb(${r},${g},${b})`
}
// 定义一个函数 draw用于在 <canvas> 元素上绘制图形验证码
function draw(dom: HTMLCanvasElement, width: number, height: number) {
// 初始化一个空字符串 imgCode用于存储生成的验证码
let imgCode = ''
// 定义一个字符串 NUMBER_STRING包含数字 0 到 9用于生成验证码字符
const NUMBER_STRING = '0123456789'
// 获取 <canvas> 元素的 2D 绘图上下文 ctx
const ctx = dom.getContext('2d')
// 如果获取上下文失败ctx 为 null则直接返回空的验证码字符串
if (!ctx) return imgCode
// 设置绘图上下文的填充样式为随机颜色(背景色)
ctx.fillStyle = randomColor(180, 230)
// 使用填充样式绘制一个矩形,覆盖整个 <canvas> 区域,作为验证码的背景
ctx.fillRect(0, 0, width, height)
// 循环 4 次,生成 4 个验证码字符
for (let i = 0; i < 4; i += 1) {
// 从 NUMBER_STRING 中随机选取一个字符作为验证码字符
const text = NUMBER_STRING[randomNum(0, NUMBER_STRING.length)]
// 将选取的字符添加到 imgCode 字符串中
imgCode += text
// 随机生成字体大小
const fontSize = randomNum(18, 41)
// 随机生成字符的旋转角度
const deg = randomNum(-30, 30)
// 设置绘图上下文的字体样式
ctx.font = `${fontSize}px Simhei`
// 设置文本基线为顶部
ctx.textBaseline = 'top'
// 设置绘图上下文的填充样式为随机颜色(字符颜色)
ctx.fillStyle = randomColor(80, 150)
// 保存当前绘图上下文的状态
ctx.save()
// 平移绘图上下文的原点到指定位置(每个字符的起始位置)
ctx.translate(30 * i + 15, 15)
// 旋转绘图上下文指定的角度
ctx.rotate((deg * Math.PI) / 180)
// 在指定位置绘制字符
ctx.fillText(text, -15 + 5, -15)
// 恢复之前保存的绘图上下文状态
ctx.restore()
}
// 循环 5 次,绘制 5 条随机直线
for (let i = 0; i < 5; i += 1) {
// 开始绘制路径
ctx.beginPath()
// 设置路径的起始点为随机位置
ctx.moveTo(randomNum(0, width), randomNum(0, height))
// 设置路径的终点为随机位置
ctx.lineTo(randomNum(0, width), randomNum(0, height))
// 设置绘图上下文的描边样式为随机颜色
ctx.strokeStyle = randomColor(180, 230)
// 关闭路径
ctx.closePath()
// 绘制路径(直线)
ctx.stroke()
}
// 循环 41 次,绘制 41 个随机圆形
for (let i = 0; i < 41; i += 1) {
// 开始绘制路径
ctx.beginPath()
// 绘制一个圆形,圆心为随机位置,半径为 1
ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI)
// 关闭路径
ctx.closePath()
// 设置绘图上下文的填充样式为随机颜色
ctx.fillStyle = randomColor(150, 200)
// 填充圆形
ctx.fill()
}
// 返回生成的验证码字符串
return imgCode
}

@ -1,50 +1,37 @@
<script setup lang="ts">
// Vue watch
import { watch } from 'vue'
// useImageVerify
import { useImageVerify } from './hooks'
// Props
interface Props {
code?: string // code
code?: string
}
// Emits
interface Emits {
(e: 'update:code', code: string): void // 'update:code' code
(e: 'update:code', code: string): void
}
// 使 withDefaults props
const props = withDefaults(defineProps<Props>(), {
code: '' // code
code: ''
})
// emit
const emit = defineEmits<Emits>()
// useImageVerify domRefimgCodesetImgCode getImgCode
const { domRef, imgCode, setImgCode, getImgCode } = useImageVerify()
// props.code props.code setImgCode
watch(
() => props.code,
newValue => {
setImgCode(newValue)
}
)
// imgCode imgCode 'update:code'
watch(imgCode, newValue => {
emit('update:code', newValue)
})
// getImgCode 便
defineExpose({ getImgCode })
</script>
<template>
<!-- 定义一个 canvas 元素设置其宽度为 120高度为 40添加类名 cursor-pointer 使其具有指针样式
绑定 ref domRef以便在脚本中访问该元素绑定 click 事件为 getImgCode 函数 -->
<canvas
ref="domRef"
width="120"

@ -1,76 +1,66 @@
<template>
<!-- 根据条件渲染不同的组件 -->
<component
v-if="column.search?.el" <!-- 如果 column.search.el 存在则渲染该组件 -->
:is="`el-${column.search.el}`" <!-- 根据 column.search.el 的值动态渲染对应的 Element Plus 组件例如 'el-input''el-select' -->
v-bind="handleSearchProps" <!-- 绑定处理后的搜索属性 -->
v-model.trim="searchParam[column.search.key?? handleProp(column.prop!)]" <!-- 双向绑定搜索参数使用 trim 修饰符去除首尾空格 -->
:data="column.search?.el === 'tree-select'? columnEnum : []" <!-- 如果是 tree-select 组件绑定 columnEnum 数据否则绑定空数组 -->
:options="
['cascader','select-v2'].includes(column.search?.el)? columnEnum : []
" <!-- 如果是 cascader select-v2 组件绑定 columnEnum 数据作为选项否则绑定空数组 -->
:placeholder="placeholder" <!-- 绑定占位符文本 -->
:clearable="clearable" <!-- 绑定是否可清除的属性 -->
range-separator="至" <!-- 日期范围选择器的分隔符 -->
start-placeholder="开始时间" <!-- 日期范围选择器开始时间的占位符 -->
end-placeholder="结束时间" <!-- 日期范围选择器结束时间的占位符 -->
v-if="column.search?.el"
:is="`el-${column.search.el}`"
v-bind="handleSearchProps"
v-model.trim="searchParam[column.search.key ?? handleProp(column.prop!)]"
:data="column.search?.el === 'tree-select' ? columnEnum : []"
:options="
['cascader', 'select-v2'].includes(column.search?.el) ? columnEnum : []
"
:placeholder="placeholder"
:clearable="clearable"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
>
<!-- column.search.el 'cascader' 渲染默认插槽内容 -->
<template #default="{ data }" v-if="column.search.el === 'cascader'">
<span>{{ data[fieldNames.label] }}</span> <!-- 显示数据的 label 字段 -->
</template>
<!-- column.search.el 'select' 渲染子选项 -->
<template v-if="column.search.el ==='select'">
<component
:is="`el-option`" <!-- 渲染 Element Plus el-option 组件 -->
v-for="(col, index) in columnEnum" <!-- 遍历 columnEnum 数据 -->
:key="index" <!-- 设置唯一的 key -->
:label="col[fieldNames.label]" <!-- 绑定选项的 label -->
:value="col[fieldNames.value]" <!-- 绑定选项的值 -->
></component>
</template>
<!-- 如果以上条件都不满足渲染插槽内容 -->
<slot v-else></slot>
<template #default="{ data }" v-if="column.search.el === 'cascader'">
<span>{{ data[fieldNames.label] }}</span>
</template>
<template v-if="column.search.el === 'select'">
<component
:is="`el-option`"
v-for="(col, index) in columnEnum"
:key="index"
:label="col[fieldNames.label]"
:value="col[fieldNames.value]"
></component>
</template>
<slot v-else></slot>
</component>
</template>
<script setup lang="ts" name="SearchFormItem">
// Vue
import { computed, inject, onMounted, ref } from 'vue'
// handleProp
import { handleProp } from '@/utils/util'
//
import { ColumnProps } from '@/components/ProTable/interface'
// SearchFormItem
interface SearchFormItem {
column: ColumnProps //
searchParam: { [key: string]: any } //
column: ColumnProps
searchParam: { [key: string]: any }
}
// props
const props = defineProps<SearchFormItem>()
// fieldNames label && value key
const fieldNames = computed(() => {
return {
label: props.column.fieldNames?.label?? 'label', // column.fieldNames.label 使使 'label'
value: props.column.fieldNames?.value?? 'value' // column.fieldNames.value 使使 'value'
label: props.column.fieldNames?.label ?? 'label',
value: props.column.fieldNames?.value ?? 'value'
}
})
// enumMap
// enumMap
const enumMap = inject('enumMap', ref(new Map()))
// columnEnum props.column.prop enumMap
const columnEnum = computed(() => {
let enumData = enumMap.value.get(props.column.prop)
if (!enumData) return [] //
if (props.column.search?.el ==='select-v2' && props.column.fieldNames) {
if (!enumData) return []
if (props.column.search?.el === 'select-v2' && props.column.fieldNames) {
enumData = enumData.map((item: { [key: string]: any }) => {
return {
...item,
label: item[fieldNames.value.label], // label
value: item[fieldNames.value.value] // value
label: item[fieldNames.value.label],
value: item[fieldNames.value.value]
}
})
}
@ -82,18 +72,18 @@ const handleSearchProps = computed(() => {
const label = fieldNames.value.label
const value = fieldNames.value.value
const searchEl = props.column.search?.el
const searchProps = props.column.search?.props?? {}
const searchProps = props.column.search?.props ?? {}
let handleProps = searchProps
if (searchEl === 'tree-select')
handleProps = {
...searchProps,
props: { label,...searchProps.props }, // tree-select props
props: { label, ...searchProps.props },
nodeKey: value
}
if (searchEl === 'cascader')
handleProps = {
...searchProps,
props: { label, value,...searchProps.props } // cascader props
props: { label, value, ...searchProps.props }
}
return handleProps
})
@ -102,7 +92,7 @@ const handleSearchProps = computed(() => {
const placeholder = computed(() => {
const search = props.column.search
return (
search?.props?.placeholder?? (search?.el === 'input'? '请输入' : '请选择') //
search?.props?.placeholder ?? (search?.el === 'input' ? '请输入' : '请选择')
)
})
@ -110,8 +100,8 @@ const placeholder = computed(() => {
const clearable = computed(() => {
const search = props.column.search
return (
search?.props?.clearable??
(search?.defaultValue == null || search?.defaultValue == undefined) // props
search?.props?.clearable ??
(search?.defaultValue == null || search?.defaultValue == undefined)
)
})
</script>

@ -1,34 +1,25 @@
<template>
<!-- MyCard 组件可能是一个自定义的卡片组件 -->
<MyCard>
<!-- columns 数组长度大于 0 时显示搜索表单 -->
<div class="card table-search" v-if="columns.length">
<!-- el-form 组件用于创建表单 -->
<MyCard
><div class="card table-search" v-if="columns.length">
<el-form ref="formRef" :model="searchParam">
<!-- Grid 组件可能是一个用于布局的网格组件 -->
<Grid
ref="gridRef"
:collapsed="collapsed"
:gap="[20, 0]"
:cols="searchCol"
>
<!-- 循环渲染 GridItem 组件每个 GridItem 对应一个搜索表单字段 -->
<GridItem
v-for="(item, index) in columns"
:key="item.prop"
v-bind="getResponsive(item)"
:index="index"
>
<!-- el-form-item 组件用于创建表单字段 -->
<el-form-item :label="`${item.label} :`">
<!-- SearchFormItem 组件用于渲染具体的搜索表单字段 -->
<SearchFormItem :column="item" :searchParam="searchParam" />
</el-form-item>
</GridItem>
<!-- 带有 suffix 标志的 GridItem 组件用于放置操作按钮 -->
<GridItem suffix>
<div class="operation">
<!-- 搜索按钮点击时调用 search 方法 -->
<el-button
class="bg-blue clickSearchBtn"
type="primary"
@ -37,74 +28,53 @@
>
搜索
</el-button>
<!-- 重置按钮点击时调用 reset 方法 -->
<el-button :icon="Delete" @click="reset"></el-button>
<!-- 展开/合并按钮根据 collapsed 的值显示不同的文本和图标 -->
<el-button
v-if="showCollapse"
link
class="search-isOpen"
@click="collapsed =!collapsed"
@click="collapsed = !collapsed"
>
{{ collapsed? '展开' : '合并' }}
{{ collapsed ? '展开' : '合并' }}
<el-icon class="el-icon--right">
<component :is="collapsed? ArrowDown : ArrowUp"></component>
<component :is="collapsed ? ArrowDown : ArrowUp"></component>
</el-icon>
</el-button>
</div>
</GridItem>
</Grid>
</el-form>
</div>
</MyCard>
</el-form></div
></MyCard>
</template>
<script setup lang="ts" name="SearchForm">
// Vue
import { computed, onMounted, ref } from 'vue'
// ProTable
import { ColumnProps } from '@/components/ProTable/interface'
// Grid
import { BreakPoint } from '@/components/Grid/interface'
// Element Plus
import { Delete, Search, ArrowDown, ArrowUp } from '@element-plus/icons-vue'
// SearchFormItem
import SearchFormItem from './components/SearchFormItem.vue'
// Grid
import Grid from '@/components/Grid/index.vue'
// GridItem
import GridItem from '@/components/Grid/components/GridItem.vue'
// MyCard
import MyCard from '../my-card/my-card.vue'
// ProTableProps
interface ProTableProps {
//
columns?: ColumnProps[]
//
searchParam?: { [key: string]: any }
//
columns?: ColumnProps[] //
searchParam?: { [key: string]: any } //
searchCol: number | Record<BreakPoint, number>
//
search: (params: any) => void
//
reset: (params: any) => void
search: (params: any) => void //
reset: (params: any) => void //
}
// 使 withDefaults
//
const props = withDefaults(defineProps<ProTableProps>(), {
columns: () => [],
searchParam: () => ({})
})
//
//
const getResponsive = (item: ColumnProps) => {
return {
// item.search.span
span: item.search?.span,
// item.search.offset 0
offset: item.search?.offset?? 0,
// item.search
offset: item.search?.offset ?? 0,
xs: item.search?.xs,
sm: item.search?.sm,
md: item.search?.md,
@ -113,24 +83,21 @@ const getResponsive = (item: ColumnProps) => {
}
}
//
//
const collapsed = ref(true)
// ref Grid
//
const gridRef = ref()
//
const breakPoint = computed<BreakPoint>(() => gridRef.value?.breakPoint)
// /
// /
const showCollapse = computed(() => {
let show = false
// columns
props.columns.reduce((prev, current) => {
prev +=
(current.search![breakPoint.value]?.span?? current.search?.span?? 1) +
(current.search![breakPoint.value]?.offset?? current.search?.offset?? 0)
// searchCol /
if (typeof props.searchCol!== 'number') {
(current.search![breakPoint.value]?.span ?? current.search?.span ?? 1) +
(current.search![breakPoint.value]?.offset ?? current.search?.offset ?? 0)
if (typeof props.searchCol !== 'number') {
if (prev >= props.searchCol[breakPoint.value]) show = true
} else {
if (prev > props.searchCol) show = true

@ -1,49 +1,36 @@
<template>
<!-- SVG 图标容器添加了 svg-icon 类用于样式设置area-hidden="true" 用于隐藏无障碍区域 -->
<svg class="svg-icon" area-hidden="true">
<!-- use 元素用于引用外部 SVG 符号:xlink:href 绑定了动态的图标名称 -->
<use :xlink:href="iconName"></use>
</svg>
</template>
<script setup lang="ts">
// Vue defineProps computed
import { defineProps, computed } from 'vue'
//
const props = defineProps({
// icon
icon: {
type: String,
required: true
},
// size 16
size: {
type: [Number, String],
default: 16
}
})
// icon #icon-
const iconName = computed(() => {
return `#icon-${props.icon}`
})
// size
const iconSize = computed(() => {
return props.size + 'px'
})
</script>
<style lang="scss" scoped>
// .svg-icon SVG
.svg-icon {
// 1em
width: 1em;
// 1em
height: 1em;
//
fill: currentColor;
// iconSize
font-size: v-bind(iconSize);
}
</style>

@ -1,47 +1,26 @@
<template>
<!-- el-dialog Element Plus 中的对话框组件用于展示选择老人的界面 -->
<!-- style="width: 70%" 设置对话框的宽度为父容器的 70% -->
<!-- v-model="dialogVisible" 双向绑定对话框的显示隐藏状态dialogVisible 是一个响应式变量 -->
<!-- title="选择老人" 设置对话框的标题 -->
<!-- destroy-on-close 表示在对话框关闭时销毁其内容 -->
<el-dialog
style="width: 70%"
v-model="dialogVisible"
title="选择老人"
destroy-on-close
>
<!-- 定义一个包含表格的 div 容器 -->
<div class="table-box">
<!-- ProTable 是自定义的表格组件用于展示用户列表 -->
<!-- ref="proTable" 为表格组件添加引用方便在脚本中访问 -->
<!-- title="用户列表" 设置表格的标题 -->
<!-- :columns="columns" 绑定表格的列配置项columns 是一个数组包含每列的信息 -->
<!-- :requestApi="getTableList" 绑定数据请求方法getTableList 用于获取表格数据 -->
<ProTable
ref="proTable"
title="用户列表"
:columns="columns"
:requestApi="getTableList"
>
<!-- 定义表格操作列的插槽内容 -->
<!-- 表格操作 -->
<template #operation="scope">
<!-- el-popconfirm Element Plus 中的弹出确认框组件 -->
<!-- title="Are you sure to choose this?" 设置确认框的提示信息 -->
<!-- @confirm="checkElder(scope.row)" 当用户确认时调用 checkElder 方法并传递当前行的数据 -->
<!-- confirm-button-type="warning" 设置确认按钮的类型为警告样式 -->
<el-popconfirm
title="Are you sure to choose this?"
@confirm="checkElder(scope.row)"
confirm-button-type="warning"
>
<!-- 定义确认框的触发元素 -->
<template #reference>
<!-- el-button Element Plus 中的按钮组件 -->
<!-- size="small" 设置按钮大小为小 -->
<!-- link 设置按钮为链接样式 -->
<!-- :icon="View" 绑定图标View 是从 @element-plus/icons-vue 导入的图标组件 -->
<!-- 选择 是按钮的文本内容 -->
<el-button size="small" link :icon="View">选择</el-button>
<el-button size="small" link :icon="View" > 选择 </el-button>
</template>
</el-popconfirm>
</template>
@ -51,36 +30,27 @@
</template>
<script setup lang="ts" name="useProTable">
// Vue ref
import { ref } from "vue";
// ProTable ColumnProps
import { ColumnProps } from "@/components/ProTable/interface";
// ProTable
import ProTable from "@/components/ProTable/index.vue";
// Element Plus View
import { View } from "@element-plus/icons-vue";
// dialogVisible
const dialogVisible = ref(false);
// proTable ProTable
const proTable = ref();
// drawerProps DialogProps
const drawerProps = ref<DialogProps>();
// DialogProps elderApi
interface DialogProps {
elderApi: (params: any) => Promise<any>;
}
// getTableList params
//
// elderApi
// params
// ProTable :requestApi="getUserList"
let getTableList = async (params: any) => {
let newParams = JSON.parse(JSON.stringify(params));
return drawerProps.value?.elderApi(newParams);
};
// columns ColumnProps
//
const columns: ColumnProps<any>[] = [
{ prop: "rank", label: "序号", width: 55 },
{ prop: "name", label: "姓名", search: { el: "input" } },
@ -92,23 +62,21 @@ const columns: ColumnProps<any>[] = [
{ prop: "operation", label: "操作", width: 70 }
];
// elderAcceptParams DialogProps params
// drawerProps
//
const elderAcceptParams = (params: DialogProps) => {
drawerProps.value = params;
dialogVisible.value = true;
};
// elderAcceptParams 便
//
defineExpose({
elderAcceptParams
});
// emit
// const emit = defineEmits(['getCheckElderInfo'])
const emit = defineEmits<{
(event: "getCheckElderInfo", val: any): void
}>();
// checkElder row
// "getCheckElderInfo"
//
const checkElder = (row: any) => {
emit("getCheckElderInfo", row);
dialogVisible.value = false;

@ -1,27 +1,17 @@
<template>
<!-- 根元素 div应用了多个类名用于设置样式和布局 -->
<!-- class="flex flex-col rounded card-wrap p-3" 表示使用 flex 布局方向为列边框圆角应用 card-wrap 类的样式内边距为 3 -->
<div class="flex flex-col rounded card-wrap p-3">
<!-- 条件渲染的 div如果 title 存在即不是 undefined 或空字符串等假值则显示该 div -->
<!-- class="pb-2" 表示该元素底部外边距为 2 -->
<!-- v-if="title" Vue 的条件渲染指令 -->
<div class="pb-2" v-if="title">{{ title }}</div>
<!-- 插槽用于父组件插入内容会被父组件的内容替换 -->
<slot></slot>
</div>
</template>
<script lang="ts" setup>
// 使 defineProps
// title ?
defineProps<{
title?: string
}>()
</script>
<style lang="scss" scoped>
// .card-wrap
// 1px 线 #eee 18px
.card-wrap {
background-color: #ffffff;
border: 1px solid #eee;

@ -1,20 +1,10 @@
<template>
<!-- Element Plus 的对话框组件 el-dialog -->
<!-- style="width: 70%" 设置对话框的宽度为父容器的 70% -->
<!-- v-model="dialogVisible" 双向绑定对话框的显示隐藏状态dialogVisible 为一个响应式变量 -->
<!-- title="选择床位" 设置对话框的标题为选择床位 -->
<!-- destroy-on-close 表示在对话框关闭时销毁其中的内容 -->
<el-dialog
style="width: 70%"
v-model="dialogVisible"
title="选择床位"
destroy-on-close
>
<!-- Element Plus 的树状组件 el-tree -->
<!-- :data="data" 绑定树状结构的数据data 是一个响应式变量 -->
<!-- :props="defaultProps" 配置树状结构的属性如节点的标识显示文本子节点的字段等 -->
<!-- accordion 使树状结构以手风琴模式显示即同一时间只有一个节点可以展开 -->
<!-- @node-click="checkBed" 监听节点点击事件当点击节点时调用 checkBed 函数 -->
<el-tree
:data="data"
:props="defaultProps"
@ -25,63 +15,43 @@
</template>
<script setup lang="ts" name="useProTable">
// Vue ref
import { ref } from "vue";
// API getBuildTree
import { getBuildTree } from "@/apis/bookManage";
// data undefined
const data: any = ref();
// dialogVisible false
const dialogVisible = ref(false);
// drawerProps DialogProps undefined
const drawerProps = ref<DialogProps>();
// DialogProps
// treeApi PromisePromise
interface DialogProps {
treeApi: (params: any) => Promise<any>;
}
// defaultProps el-tree
// id: "id" "id"
// label: "name" "name"
// children: "childrenList" "childrenList"
const defaultProps = {
id: "id",
label: "name",
children: "childrenList"
};
// treeAcceptParams
//
const treeAcceptParams = async (params: DialogProps) => {
// drawerProps
drawerProps.value = params;
//
dialogVisible.value = true;
// getBuildTree
const res: any = await getBuildTree();
// data
data.value = res.data;
};
// treeAcceptParams 便
//
defineExpose({
treeAcceptParams
});
// "getCheckBedInfo"
//
// const emit = defineEmits(['getCheckElderInfo'])
const emit = defineEmits<{
(event: "getCheckBedInfo", val: any): void
}>();
// checkBed
//
const checkBed = (bed: any) => {
// level 4
if (bed.level === 4) {
// "getCheckBedInfo"
emit("getCheckBedInfo", bed);
//
dialogVisible.value = false;
}
};

@ -1,14 +1,4 @@
<template>
<!-- Element Plus 的上传组件 el-upload -->
<!-- v-model:file-list="imageList" 双向绑定上传文件列表imageList 是一个响应式变量 -->
<!-- :action="requestUrl" 设置上传文件的接口地址requestUrl 是一个变量 -->
<!-- :headers="{ token: token }" 设置上传请求的头部信息包含 token -->
<!-- list-type="picture-card" 设置上传文件列表的展示类型为图片卡片形式 -->
<!-- :before-upload="uploadBefore" 在文件上传前调用 uploadBefore 函数进行处理 -->
<!-- :on-error="handleError" 当文件上传失败时调用 handleError 函数 -->
<!-- :on-success="handleSuccess" 当文件上传成功时调用 handleSuccess 函数 -->
<!-- :on-preview="handlePreview" 当点击预览图片时调用 handlePreview 函数 -->
<!-- :on-remove="handleRemove" 当移除上传文件时调用 handleRemove 函数 -->
<el-upload
v-model:file-list="imageList"
:action="requestUrl"
@ -20,16 +10,12 @@
:on-preview="handlePreview"
:on-remove="handleRemove"
>
<!-- Element Plus 的图标组件 el-icon展示一个加号图标 -->
<el-icon>
<Plus />
</el-icon>
</el-upload>
<!-- Element Plus 的对话框组件 el-dialog用于展示预览图片 -->
<!-- v-model="dialogVisible" 双向绑定对话框的显示隐藏状态dialogVisible 是一个响应式变量 -->
<el-dialog v-model="dialogVisible">
<!-- img 标签用于显示预览图片w-full 可能是一个自定义的类名表示宽度占满:src="dialogImageUrl" 绑定图片的源地址dialogImageUrl 是一个响应式变量 -->
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</template>
@ -64,126 +50,97 @@ uploadParams.value.imageList.push({
-->
<script lang="ts" setup>
// Vuex store
import store from "@/store";
// URL
import { baseUrl } from "@/utils/http";
// Element Plus ElMessage
import { ElMessage } from "element-plus";
// Element Plus Plus
import { Plus } from "@element-plus/icons-vue";
// Vue
import { defineEmits, onMounted, ref, watch } from "vue";
// Element Plus
import type { UploadUserFile, ElUpload } from "element-plus";
// dialogImageUrl URL
// page data
const dialogImageUrl = ref("");
// dialogVisible false
const dialogVisible = ref(false);
// imageList
const imageList = ref<UploadUserFile[]>([]);
// props uploadParams
// father component transfer to this date
const props = defineProps({
uploadParams: Object
});
//
//
onMounted(() => {
// uploadParams imageList imageList
props.uploadParams?.["imageList"].forEach((image: any) => {
imageList.value.push(image);
});
});
// URL
// http request data
const requestUrl = baseUrl + "file/uploadImg";
// Vuex store token
const token = store.state.app.token;
// imageUrlList URL
// return data
const imageUrlList = ref<any[]>([]);
// "setImageData"
//
const emits = defineEmits(["setImageData"]);
// updateData
//
const updateData = () => {
// imageUrlList
//
imageUrlList.value = [];
// imageList URL imageUrlList
imageList.value.forEach(image => imageUrlList.value.push(image.url));
// data
//
const data = ref<any>();
//
if (props.uploadParams?.["uploadType"] === "single") {
// URL data
data.value = imageUrlList.value[0];
} else {
// imageUrlList data
data.value = imageUrlList;
}
// "setImageData"
//
emits("setImageData", data);
};
// imageList
//
watch(imageList, (value, oldValue, onCleanup) => {
// imageList 1
if (props.uploadParams?.["uploadType"] === "single" && imageList.value.length > 1) {
//
imageList.value.splice(0, 1);
//
updateData();
}
});
// uploadBefore
//
const uploadBefore = (file: any) => {
// jpeg png
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
// 2MB
const isLt2M = file.size / 1024 / 1024 < 2;
// jpeg png
if (!isJPG) {
ElMessage.error("只能上传jpg/png文件");
}
// 2MB
if (!isLt2M) {
ElMessage.error("文件大小不能超过2MB");
}
//
return isJPG && isLt2M;
};
// handleError
//
const handleError = (response: any) => {
//
ElMessage.error(response.data.msg);
};
// handleSuccess
//
const handleSuccess = (response: any, uploadFile: any) => {
// URL url
uploadFile.url = response.data.url;
//
updateData();
};
// handleRemove
//
const handleRemove = async (uploadFile: any) => {
// imageList
imageList.value.filter((image) => image.uid!== uploadFile.uid);
//
imageList.value.filter((image) => image.uid !== uploadFile.uid);
updateData();
// TODO imageId : uploadFile.uid
};
// handlePreview
//
const handlePreview = (uploadFile: any) => {
// URL URL
dialogImageUrl.value = uploadFile.url!;
//
dialogVisible.value = true;
};
</script>

@ -1,36 +1,28 @@
<!-- Element Plus 中动态添加组件可以使用 el-component 组件该组件可以将任何一个 Vue 组件动态添加到页面中下面是一个示例代码-->
<!--在上面的示例中我们使用了 el-component 组件来动态添加组件通过 :is 属性指定要添加的组件类型通过 :props 属性传递组件所需的 props 数据-->
<!-- addNew 方法中我们向 componentList 数组中添加一个组件对象其中 type 属性指定要添加的组件类型props 属性指定要传递给组件的数据-->
<!--最后在模板中使用 v-for 指令遍历 componentList 数组并通过 :is :props 属性将组件动态添加到页面中-->
<!--需要注意的是在使用 el-component 组件动态添加组件时需要将要添加的组件在 components 中先进行注册-->
<template>
<div>
<!-- 定义一个 Element Plus 的按钮点击该按钮会触发 addNew 方法 -->
<el-button @click="addNew"></el-button>
<!-- 使用 v-for 指令遍历 componentList 数组将数组中的每个元素渲染为一个组件 -->
<div v-for="(item, index) in componentList" :key="index">
<!-- 使用 el-component 动态添加组件 -->
<!-- :is="item.type" 指定要渲染的组件类型该类型从 componentList 数组元素的 type 属性获取 -->
<!-- :props="item.props" 传递组件所需的 props 数据这些数据从 componentList 数组元素的 props 属性获取 -->
<el-component :is="item.type" :props="item.props"></el-component>
</div>
</div>
</template>
<script>
// HelloWorld
import HelloWorld from './components/HelloWorld.vue'
export default {
// data
data() {
return {
// componentList
componentList: []
}
},
// methods
methods: {
// addNew componentList
addNew() {
// componentList
// type HelloWorld
// props HelloWorld msg 'Hello World!'
this.componentList.push({
type: HelloWorld,
props: {
@ -39,7 +31,6 @@ export default {
})
}
},
// components HelloWorld
components: {
HelloWorld
}

@ -1,42 +1,27 @@
// 定义一个名为 Table 的命名空间
export namespace Table {
// 在 Table 命名空间内,定义一个接口 Pageable用于描述分页相关的属性
export interface Pageable {
// 当前页码,类型为数字
pageNum: number
// 每页显示的数量,类型为数字
pageSize: number
// 数据的总数量,类型为数字
total: number
}
// 在 Table 命名空间内,定义一个接口 TableStateProps用于描述表格相关的状态属性
export interface TableStateProps {
// 表格数据,是一个任意类型的数组
tableData: any[]
// 分页相关的属性,类型为 Pageable 接口
pageable: Pageable
// 搜索参数,是一个键值对对象,键为字符串,值为任意类型
searchParam: {
[key: string]: any
}
// 初始化的搜索参数,是一个键值对对象,键为字符串,值为任意类型
searchInitParam: {
[key: string]: any
}
// 用于获取总数的参数,是一个键值对对象,键为字符串,值为任意类型
totalParam: {
[key: string]: any
}
// 可选的图标相关属性,是一个键值对对象,键为字符串,值为任意类型,默认为 undefined
icon?: {
[key: string]: any
}
}
}
// 定义一个名为 HandleData 的命名空间
export namespace HandleData {
// 在 HandleData 命名空间内,定义一个类型别名 MessageType
// MessageType 的值可以是空字符串,或者是'success'、'warning'、'info'、'error' 中的一个
export type MessageType = '' |'success' | 'warning' | 'info' | 'error'
export type MessageType = '' | 'success' | 'warning' | 'info' | 'error'
}

@ -1,6 +1,4 @@
// 从 element-plus 库中导入 ElMessageBox 和 ElMessage 组件,分别用于显示确认框和提示消息
import { ElMessageBox, ElMessage } from 'element-plus'
// 从 './interface' 文件中导入 HandleData 命名空间,用于获取其中定义的类型
import { HandleData } from './interface'
/**
@ -11,42 +9,26 @@ import { HandleData } from './interface'
* @param {String} confirmType icon(, warning)
* @return Promise
*/
// 定义一个泛型函数 useHandleDataP 表示 api 函数参数的类型R 表示 api 函数返回值的类型
export const useHandleData = <P = any, R = any>(
// api 是一个函数,接收类型为 P 的参数并返回一个 PromisePromise 的解析值类型为 R
api: (params: P) => Promise<R>,
// params 是 api 函数的参数,类型与 api 函数的参数类型一致
params: Parameters<typeof api>[0],
// message 是一个字符串,用于显示确认框中的提示信息
message: string,
// confirmType 是一个字符串,类型为 HandleData.MessageType默认值为 'warning'
confirmType: HandleData.MessageType = 'warning'
) => {
// 返回一个 Promise
return new Promise((resolve, reject) => {
// 显示一个确认框
ElMessageBox.confirm(`是否${message}?`, '温馨提示', {
// 确认按钮的文本
confirmButtonText: '确定',
// 取消按钮的文本
cancelButtonText: '取消',
// 确认框的图标类型
type: confirmType,
// 是否可拖动
draggable: true
})
.then(async () => {
// 调用 api 函数并等待其返回结果
const res = await api(params)
// 如果结果为 falsy 值,则 reject 该 Promise
if (!res) return reject(false)
// 显示一个成功提示消息
ElMessage({
type:'success',
message: `${message}成功!`
})
// resolve 该 Promise表示操作成功
resolve(true)
}).then(async () => {
const res = await api(params)
if (!res) return reject(false)
ElMessage({
type: 'success',
message: `${message}成功!`
})
resolve(true)
})
})
}

@ -1,21 +1,10 @@
// 从 '@/components/SvgIcon/index.vue' 导入 SvgIcon 组件
import SvgIcon from '@/components/SvgIcon/index.vue'
// 从 'vue' 导入 h 函数和 defineComponent 函数
import { h, defineComponent } from 'vue'
// 定义一个名为 useRenderIcon 的函数它接受两个参数iconName字符串类型和 attrs可选的任意类型
export function useRenderIcon(iconName: string, attrs?: any) {
// 使用 defineComponent 函数定义一个新的组件
return defineComponent({
// 新组件的名称为 'SvgIcon'
name: 'SvgIcon',
// 定义组件的渲染函数
render() {
// 使用 h 函数创建一个 SvgIcon 组件的虚拟节点
// 第一个参数是要创建的组件(这里是 SvgIcon
// 第二个参数是一个对象,包含要传递给 SvgIcon 组件的属性
// 'icon' 属性的值是传入的 iconName
// '...attrs' 表示将 attrs 对象中的所有属性也传递给 SvgIcon 组件
return h(SvgIcon, {
icon: iconName,
...attrs

@ -4,24 +4,16 @@ import { ref, computed } from 'vue'
* @description
* @param {String} rowKey id
* */
// 定义一个名为 useSelection 的函数,用于处理表格多选数据的操作
// 接受一个可选参数 rowKey默认值为 'id',表示行数据中用于唯一标识的键名
export const useSelection = (rowKey = 'id') => {
// 创建一个响应式变量 isSelected用于表示是否选中了数据
// 初始值为 false类型为 boolean
// 是否选中数据
const isSelected = ref<boolean>(false)
// 创建一个响应式变量 selectedList用于存储选中的数据列表
// 初始值为空数组,类型为 any[]
// 选中的数据列表
const selectedList = ref([])
// 创建一个计算属性 selectedListIds用于获取当前选中的所有数据的 id 数组
// 计算属性会根据依赖项(这里是 selectedList的变化而自动更新
// 当前选中的所有ids(数组)可根据项目自行配置id字段
const selectedListIds = computed((): string[] => {
// 初始化一个空数组 ids 用于存储 id
const ids: string[] = []
// 遍历 selectedList 中的每一项数据
selectedList.value.forEach(item => ids.push(item[rowKey]))
// 返回包含所有 id 的数组
return ids
})
@ -30,18 +22,11 @@ export const useSelection = (rowKey = 'id') => {
* @param {Array} rowArr
* @return void
*/
// 定义一个函数 selectionChange用于处理表格多选数据的变化事件
// 接受一个参数 rowArr类型为 any[],表示当前选中的所有数据
const selectionChange = (rowArr: any) => {
// 如果选中的数据列表为空,则将 isSelected 设置为 false
// 否则将 isSelected 设置为 true
rowArr.length === 0? (isSelected.value = false) : (isSelected.value = true)
// 更新 selectedList 为当前选中的数据列表
selectedList.value = rowArr
}
rowArr.length === 0 ? (isSelected.value = false) : (isSelected.value = true)
selectedList.value = rowArr
}
// 返回一个包含 isSelected、selectedList、selectedListIds 和 selectionChange 的对象
// 以便在其他地方使用这些变量和函数来处理表格多选数据
return {
isSelected,
selectedList,

@ -8,196 +8,160 @@ import { reactive, computed, toRefs } from 'vue'
* @param {Boolean} isPageable (true)
* @param {Function} dataCallBack ()
* */
// 定义一个名为 useTable 的函数,用于封装表格页面的操作方法
// api 是获取表格数据的 API 方法,是必传参数
// initParam 是获取数据的初始化参数,非必传,默认值为空对象
// isPageable 表示是否有分页功能,非必传,默认值为 true
// dataCallBack 是对后台返回的数据进行处理的方法,非必传
export const useTable = (
api: (params: any) => Promise<any>,
initParam: object = {},
isPageable = true,
dataCallBack?: (data: any) => any
) => {
// 使用 reactive 创建一个响应式的 state 对象,包含表格数据、分页数据、查询参数等
const state = reactive<Table.TableStateProps>({
// 表格数据,初始值为空数组
// 表格数据
tableData: [],
// 分页数据,包含当前页数、每页显示条数和总条数
// 分页数据
pageable: {
// 当前页数,初始值为 1
// 当前页数
pageNum: 1,
// 每页显示条数,初始值为 10
// 每页显示条数
pageSize: 10,
// 总条数,初始值为 0
// 总条数
total: 0
},
// 查询参数,只包括查询条件,初始值为空对象
// 查询参数(只包括查询)
searchParam: {},
// 初始化默认的查询参数,初始值为空对象
// 初始化默认的查询参数
searchInitParam: {},
// 总参数,包含分页和查询参数,初始值为空对象
// 总参数(包含分页和查询参数)
totalParam: {}
})
/**
* @description (,)
* */
// 定义一个计算属性 pageParam用于获取和设置分页查询参数
const pageParam = computed({
// 获取分页查询参数
get: () => {
return {
pageNum: state.pageable.pageNum,
pageSize: state.pageable.pageSize
}
},
// 设置分页查询参数,这里暂时为空,可根据需要实现
set: (newVal: any) => { // 我是分页更新之后的值
get: () => {
return {
pageNum: state.pageable.pageNum,
pageSize: state.pageable.pageSize
}
})
},
set: (newVal: any) => { // 我是分页更新之后的值
}
})
/**
* @description
* @return void
* */
// 定义一个异步函数 getTableList用于获取表格数据
const getTableList = async () => {
try {
// 先把初始化参数和分页参数放到总参数里面
Object.assign(
state.totalParam,
initParam,
isPageable? pageParam.value : {}
)
// 请求前格式化数据,如果总参数中有 consultDate 字段,则进行处理
if (state.totalParam.consultDate) {
state.totalParam.startTime = state.totalParam.consultDate[0]
state.totalParam.endTime = state.totalParam.consultDate[1]
delete state.totalParam.consultDate
}
// 调用 API 方法获取数据
let { data } = await api({
...state.searchInitParam,
...state.totalParam
})
// 如果有数据处理回调函数,则对数据进行处理
dataCallBack && (data = dataCallBack(data))
// 获取当前表格数据,如果有分页,则取 data.list否则取 data
state.tableData = isPageable? data.list : data
// 从返回的数据中获取分页信息
const { pageNum, pageSize, total } = data
// 如果有分页,则更新分页信息
isPageable && updatePageable({ pageNum, pageSize, total })
} catch (error) {
// 如果发生错误,打印错误信息
console.log(error)
try {
// 先把初始化参数和分页参数放到总参数里面
Object.assign(
state.totalParam,
initParam,
isPageable ? pageParam.value : {}
)
//请求前格式化数据
if (state.totalParam.consultDate) {
state.totalParam.startTime = state.totalParam.consultDate[0]
state.totalParam.endTime = state.totalParam.consultDate[1]
delete state.totalParam.consultDate
}
let { data } = await api({
...state.searchInitParam,
...state.totalParam
})
dataCallBack && (data = dataCallBack(data))
// 获取当前表格数据
state.tableData = isPageable ? data.list : data
const { pageNum, pageSize, total } = data
isPageable && updatePageable({ pageNum, pageSize, total })
} catch (error) {
console.log(error)
}
}
/**
* @description
* @return void
* */
// 定义一个函数 updatedTotalParam用于更新总参数
const updatedTotalParam = () => {
state.totalParam = {}
// 处理查询参数,可以给查询参数加自定义前缀操作
const nowSearchParam: { [key: string]: any } = {}
// 防止手动清空输入框携带参数(这里可以自定义查询参数前缀)
for (const key in state.searchParam) {
// * 某些情况下参数为 false/0 也应该携带参数
if (
state.searchParam[key] ||
state.searchParam[key] === false ||
state.searchParam[key] === 0
) {
nowSearchParam[key] = state.searchParam[key]
}
state.totalParam = {}
// 处理查询参数,可以给查询参数加自定义前缀操作
const nowSearchParam: { [key: string]: any } = {}
// 防止手动清空输入框携带参数(这里可以自定义查询参数前缀)
for (const key in state.searchParam) {
// * 某些情况下参数为 false/0 也应该携带参数
if (
state.searchParam[key] ||
state.searchParam[key] === false ||
state.searchParam[key] === 0
) {
nowSearchParam[key] = state.searchParam[key]
}
// 将处理后的查询参数和分页参数合并到总参数中
Object.assign(
state.totalParam,
nowSearchParam,
isPageable? pageParam.value : {}
)
}
Object.assign(
state.totalParam,
nowSearchParam,
isPageable ? pageParam.value : {}
)
}
/**
* @description
* @param {Object} resPageable
* @return void
* */
// 定义一个函数 updatePageable用于更新分页信息
const updatePageable = (resPageable: Table.Pageable) => {
// 使用 Object.assign 方法将后台返回的分页数据合并到 state.pageable 中
Object.assign(state.pageable, resPageable)
}
Object.assign(state.pageable, resPageable)
}
/**
* @description
* @return void
* */
// 定义一个函数 search用于进行表格数据查询
const search = () => {
// 将当前页数设置为 1
state.pageable.pageNum = 1
// 更新总参数
updatedTotalParam()
// 获取表格数据
getTableList()
}
state.pageable.pageNum = 1
updatedTotalParam()
getTableList()
}
/**
* @description
* @return void
* */
// 定义一个函数 reset用于重置表格数据
const reset = () => {
// 将当前页数设置为 1
state.pageable.pageNum = 1
// 清空搜索参数
state.searchParam = {}
// 重置搜索表单时,如果有默认搜索参数,则重置为默认值
Object.keys(state.searchInitParam).forEach(key => {
state.searchParam[key] = state.searchInitParam[key]
})
// 更新总参数
updatedTotalParam()
// 获取表格数据
getTableList()
}
state.pageable.pageNum = 1
state.searchParam = {}
// 重置搜索表单的时,如果有默认搜索参数,则重置默认的搜索参数
Object.keys(state.searchInitParam).forEach(key => {
state.searchParam[key] = state.searchInitParam[key]
})
updatedTotalParam()
getTableList()
}
/**
* @description
* @param {Number} val
* @return void
* */
// 定义一个函数 handleSizeChange用于处理每页条数改变的事件
const handleSizeChange = (val: number) => {
// 将当前页数设置为 1
state.pageable.pageNum = 1
// 更新每页显示条数
state.pageable.pageSize = val
// 获取表格数据
getTableList()
}
state.pageable.pageNum = 1
state.pageable.pageSize = val
getTableList()
}
/**
* @description
* @param {Number} val
* @return void
* */
// 定义一个函数 handleCurrentChange用于处理当前页改变的事件
const handleCurrentChange = (val: number) => {
// 更新当前页数
state.pageable.pageNum = val
// 获取表格数据
getTableList()
}
state.pageable.pageNum = val
getTableList()
}
// 返回一个包含 state 的响应式引用、获取表格数据的函数、查询函数、重置函数、处理每页条数改变和当前页改变的函数以及更新总参数的函数
return {
...toRefs(state),
getTableList,

@ -1,21 +1,15 @@
// 从项目路径 '@/components/SvgIcon/index.vue' 导入 SvgIcon 组件
import SvgIcon from '@/components/SvgIcon/index.vue'
// 从 'vue' 中导入 App 类型,用于表示 Vue 应用实例
import { App } from 'vue'
// 获取上下文 require.context检索的目录是否检索子文件夹正则表达式
// 返回值是一个函数(传入路径可以导入文件)
// 通过静态方法keys可以检索所有文件路径
// 通过.prototype可以查看所有静态方法
// 这里指定检索当前目录下的 './svg' 文件夹,不检索子文件夹,匹配所有以.svg 结尾的文件
const svgRequired = require.context('./svg', false, /\.svg$/)
// 遍历所有匹配的 SVG 文件路径
svgRequired.keys().forEach(item => svgRequired(item))
// 导出一个默认函数,该函数接收一个 Vue 应用实例 app 作为参数
export default (app: App) => {
// 使用 app.component 方法将 SvgIcon 组件注册为全局组件,别名为'svg-icon'
// 这样在整个 Vue 应用中都可以使用 <svg-icon> 标签来使用该组件
app.component('svg-icon', SvgIcon)
}

@ -1,49 +1,34 @@
<template>
<!-- Element Plus 的下拉菜单组件触发方式为点击 -->
<el-dropdown trigger="click">
<!-- 下拉菜单的触发元素 -->
<span class="navbar-bg-hover">
<!-- 显示用户头像图片地址通过 :src 绑定 avator 变量 -->
<img :src="avator" />
<!-- 如果用户名存在显示用户名使用了暗色模式下文字颜色为黑色的样式 -->
<p v-if="username" class="dark:text-black">{{ username }}</p>
</span>
<!-- 下拉菜单内容模板 -->
<template #dropdown>
<!-- Element Plus 的下拉菜单 -->
<el-dropdown-menu class="logout">
<!-- 下拉菜单项点击触发 editPassShow 方法 -->
<el-dropdown-item @click="editPassShow">
<!-- 自定义的 SVG 图标组件显示修改密码图标 -->
<svg-icon
@click="editPassShow"
icon="verify"
size="14"
style="margin-right: 5px"
></svg-icon>
<!-- 菜单项文本 -->
修改密码
</el-dropdown-item>
<!-- 下拉菜单项点击触发 logout 方法 -->
<el-dropdown-item @click="logout">
<!-- 自定义的 SVG 图标组件显示退出登录图标 -->
<svg-icon
@click="logout"
icon="logout"
size="14"
style="margin-right: 5px"
></svg-icon>
<!-- 菜单项文本 -->
退出登录
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- Element Plus 的对话框组件用于修改密码 -->
<el-dialog v-model="editPassVisible" title="修改密码">
<!-- 对话框内容模板 -->
<template #default>
<!-- Element Plus 的表单组件绑定表单数据表单规则和表单引用 -->
<el-form
:model="formData"
class="forget-pass-form"
@ -51,9 +36,7 @@
:rules="editPassRules"
size="large"
>
<!-- 表单项对应旧密码字段 -->
<el-form-item prop="oldPass">
<!-- Element Plus 的输入框组件绑定旧密码数据显示为密码输入框 -->
<el-input
v-model="formData.oldPass"
placeholder="旧密码"
@ -63,9 +46,8 @@
show-password
/>
</el-form-item>
<!-- 表单项对应新密码字段 -->
<el-form-item prop="newPass">
<!-- Element Plus 的输入框组件绑定新密码数据显示为密码输入框 -->
<el-input
v-model="formData.newPass"
placeholder="新密码"
@ -75,9 +57,8 @@
show-password
/>
</el-form-item>
<!-- 表单项对应确认密码字段 -->
<el-form-item prop="confirmPassword">
<!-- Element Plus 的输入框组件绑定确认密码数据显示为密码输入框 -->
<el-input
v-model="formData.confirmPassword"
placeholder="确认密码"
@ -89,12 +70,9 @@
</el-form-item>
</el-form>
</template>
<!-- 对话框底部模板 -->
<template #footer>
<div class="dialog-footer">
<!-- 取消按钮点击关闭对话框 -->
<el-button @click="editPassVisible = false">取消</el-button>
<!-- 确认修改按钮点击触发 handleEditPass 方法显示加载状态 -->
<el-button
class="bg-blue"
type="primary"
@ -109,61 +87,43 @@
</template>
<script setup lang="ts">
// Vuex
import store from '@/store'
//
import { useRenderIcon } from '@/hooks/useIcons'
// Vue
import { reactive, ref } from 'vue'
// API
import { editPass, forgetPass, getLogout, IEditPassImpl } from '@/apis/user'
// Element Plus
import { ElMessage, FormInstance, FormRules } from 'element-plus'
// Vuex
const avator = store.state.app.userPeofile.avator
// Vuex
const username = store.state.app.userPeofile.username
//
const editPassVisible = ref(false)
//
const ruleFormRef = ref<FormInstance | null>(null)
//
const loading = ref(false)
//
const formData = ref({
oldPass: '12345',
newPass: '123456',
confirmPassword: '123456'
})
//
//
const editPassShow = () => {
editPassVisible.value = true
}
//
//
const handleEditPass = (formRef: FormInstance | null) => {
//
loading.value = true
//
if (!formRef) return
//
formRef.validate(async (valid, fields) => {
if (valid) {
// API
// const res: any = await editPass({
// oldPass: formData.value.oldPass,
// newPass: formData.value.newPass
// })
// 使 API
const res: any = await editPass(new IEditPassImpl('1', '1'))
if (res.code === 200) {
// 退
logout()
} else {
//
loading.value = false
ElMessage({
message: res.msg,
@ -171,84 +131,63 @@ const handleEditPass = (formRef: FormInstance | null) => {
})
}
} else {
//
loading.value = false
return fields
}
})
}
// 退
// 退
const logout = async () => {
// 退 API
await getLogout()
// Vuex 退
store.dispatch('app/logout')
//
ElMessage({
message: '操作成功',
type: 'success'
})
}
/* 修改密码校验规则 */
/* 修改密码校验 */
const editPassRules = reactive<FormRules>({
oldPass: [
{
//
validator: (rule, value, callback) => {
//
let oldPass = value?.trim()
if (oldPass === '') {
//
callback(new Error('旧密码不能为空'))
} else {
//
callback()
}
},
//
trigger: 'blur'
}
],
newPass: [
{
//
validator: (rule, value, callback) => {
//
const newPass = value?.trim()
if (newPass === '') {
//
callback(new Error('新密码不能为空'))
} else {
//
callback()
}
},
//
trigger: 'blur'
}
],
confirmPassword: [
{
//
validator: (rule, value, callback) => {
//
const confirmPass = value?.trim()
//
const newPass = formData.value.newPass.trim()
if (confirmPass === '') {
//
callback(new Error('确认密码不能为空'))
} else if (confirmPass!== newPass) {
//
} else if (confirmPass !== newPass) {
callback('与新密码不一致')
} else {
//
callback()
}
},
//
trigger: 'blur'
}
]
@ -258,13 +197,9 @@ const editPassRules = reactive<FormRules>({
<style lang="scss" scoped>
.navbar-bg-hover {
img {
//
border-radius: 50%;
//
height: 22px;
//
width: 22px;
//
margin-right: 10px;
}
}

@ -1,21 +1,11 @@
<template>
<!-- Element Plus 的面包屑导航组件 el-breadcrumb -->
<!-- 添加了自定义的类名 "breadcrumb" 用于样式设置 -->
<!-- separator="/" 设置面包屑导航的分隔符为 "/" -->
<el-breadcrumb class="breadcrumb" separator="/">
<!-- 过渡组组件 transition-group用于实现面包屑导航项的过渡效果 -->
<!-- 定义了过渡的名称为 "breadcrumb" -->
<transition-group name="breadcrumb">
<!-- 循环渲染面包屑导航项 el-breadcrumb-item -->
<!-- v-for="item in breadcrumbList" 表示遍历 breadcrumbList 数组中的每一项 -->
<!-- :key="item.path" 为每个面包屑导航项设置唯一的 key -->
<!-- :to="{ path: item.path }" 为面包屑导航项设置跳转的路由路径 -->
<el-breadcrumb-item
v-for="item in breadcrumbList"
:key="item.path"
:to="{ path: item.path }"
>
<!-- 显示面包屑导航项的标题 item.meta.title 中获取如果不存在则显示空 -->
{{ item.meta?.title }}
</el-breadcrumb-item>
</transition-group>
@ -23,47 +13,32 @@
</template>
<script setup lang="ts">
// Vue watch ref
import { watch, ref } from 'vue'
// vue-router useRoute
import { useRoute } from 'vue-router'
// vue-router RouteRecordRaw
import { RouteRecordRaw } from 'vue-router'
//
const route = useRoute()
// breadcrumbList
//
const breadcrumbList = ref<RouteRecordRaw[]>([])
// initBreadcrumbList
const initBreadcrumbList = () => {
// layout layout 使 route.matched.slice(1)
// layout
breadcrumbList.value = route.matched.slice(1)
}
// route
watch(
route,
() => {
// route initBreadcrumbList
initBreadcrumbList()
},
{
// deep: true route
// immediate: true
deep: true,
immediate: true
}
{ deep: true, immediate: true }
)
</script>
<style lang="scss" scoped>
// .el-breadcrumb
.el-breadcrumb {
//
display: flex;
// 使
align-items: center;
// 10px
margin-left: 10px;
}
</style>

@ -1,50 +1,32 @@
<template>
<!-- 定义一个具有类名 "nav-container" 的顶级 div 元素作为导航栏的容器 -->
<div class="nav-container">
<!-- 导航栏左侧区域类名为 "nav-left" -->
<div class="nav-left">
<!-- 引入并使用名为 Breadcrumb 的组件该组件可能是用于显示面包屑导航 -->
<Breadcrumb />
</div>
<!-- 导航栏右侧区域类名为 "nav-right" -->
<div class="nav-right">
<!-- 引入并使用名为 Avatar 的组件该组件可能是用于显示用户头像等信息 -->
<Avatar class="nav-item" />
</div>
</div>
</template>
<script setup lang="ts">
// components Avatar Vue
import Avatar from './components/Avatar.vue'
// components Breadcrumb Vue
import Breadcrumb from './components/Breadcrumb.vue'
</script>
<style lang="scss" scoped>
// .nav-container
.nav-container {
//
display: flex;
// 使
justify-content: space-between;
// 使
align-items: center;
// 100%
width: 100%;
// 48
height: 48px;
//
overflow: hidden;
//
background-color: #fff;
// 1 线 60%
border-bottom: 1px solid #d8d8d860;
// .nav-right .nav-left
.nav-right,
.nav-left {
//
display: flex;
}
}

@ -1,15 +1,6 @@
<template>
<!-- 定义一个具有类名 "container" div 元素 -->
<div class="container">
<!-- Element Plus 的工具提示组件 el-tooltip -->
<!-- effect="light" 设置工具提示的效果为淡色 -->
<!-- :content="content" 绑定工具提示的内容内容通过计算属性 content 获取 -->
<!-- placement="right" 设置工具提示显示在目标元素的右侧 -->
<el-tooltip effect="light" :content="content" placement="right">
<!-- 自定义的 SVG 图标组件 svg-icon -->
<!-- icon="menu-fold" 设置图标为 "menu-fold" -->
<!-- @click="changeSiderType" 绑定点击事件点击时调用 changeSiderType 方法 -->
<!-- :style="style" 绑定样式样式通过计算属性 style 获取 -->
<svg-icon
icon="menu-fold"
@click="changeSiderType"
@ -20,43 +11,31 @@
</template>
<script setup lang="ts">
// '@/store' useStore 访 Vuex
import { useStore } from '@/store'
// 'vue' computed
import { computed } from 'vue'
// Vuex
const store = useStore()
// content store.state.app.siderType
const content = computed(() => {
return store.state.app.siderType? '点击折叠' : '点击展开'
return store.state.app.siderType ? '点击折叠' : '点击展开'
})
// style store.state.app.siderType
const style = computed(() => {
return store.state.app.siderType? 'none' : 'transform: rotateY(180deg);'
return store.state.app.siderType ? 'none' : 'transform: rotateY(180deg);'
})
// changeSiderType
const changeSiderType = () => {
// 'app/setSiderType' mutation Vuex
store.commit('app/setSiderType')
}
</script>
<style lang="scss" scoped>
// .svg-icon svg-icon
.svg-icon {
// Element Plus
color: var(--el-color-primary);
//
margin: 0 0 4px 16px !important;
vertical-align: middle;
//
outline: none;
// 0.36
transition-duration: 0.36s;
//
cursor: pointer;
}
</style>

@ -1,28 +1,15 @@
<template>
<!-- 使用 v-for 循环遍历 menuList 数组为每个菜单项生成对应的 DOM 结构 -->
<!-- :key="menu.id" 为每个循环项设置唯一的 key用于 Vue 的虚拟 DOM 优化 -->
<template v-for="menu in menuList" :key="menu.id">
<!-- Element Plus 的子菜单组件 el-sub-menu -->
<!-- v-if="menu.children && menu.children.length > 0" 只有当菜单有子菜单时才渲染该子菜单 -->
<!-- :index="menu.name + ''" 设置子菜单的索引 menu.name 转换为字符串类型 -->
<el-sub-menu
v-if="menu.children && menu.children.length > 0"
:index="menu.name + ''"
>
<!-- 子菜单的标题模板 #title -->
<template #title>
<!-- 如果菜单有 meta.icon 属性渲染自定义的 SVG 图标组件 svg-icon -->
<svg-icon
v-if="menu.meta.icon"
:icon="menu.meta.icon"
class="sub-menu-icon"
></svg-icon>
<!-- Element Plus 的工具提示组件 el-tooltip -->
<!-- effect="light" 设置工具提示的效果为淡色 -->
<!-- :content="menu.meta.title" 绑定工具提示的内容为菜单的标题 -->
<!-- placement="top-start" 设置工具提示显示在目标元素的顶部偏左位置 -->
<!-- :offset="-10" 设置工具提示与目标元素的偏移量为 -10 像素 -->
<!-- :disabled="!showTooltip" 根据 showTooltip 的值决定是否禁用工具提示 -->
<el-tooltip
effect="light"
:content="menu.meta.title"
@ -30,40 +17,24 @@
:offset="-10"
:disabled="!showTooltip"
>
<!-- 用于显示菜单标题的 span 元素 -->
<!-- ref="menuTextRef" 为元素设置引用方便在脚本中获取 -->
<!-- @mouseover="hoverMenu" 绑定鼠标移入事件调用 hoverMenu 方法 -->
<span ref="menuTextRef" @mouseover="hoverMenu">{{
menu.meta.title
}}</span>
menu.meta.title
}}</span>
</el-tooltip>
</template>
<!-- 递归调用 MenuItem 组件传入当前菜单的子菜单列表 -->
<MenuItem :menuList="menu.children" />
</el-sub-menu>
<!-- Element Plus 的菜单选项组件 el-menu-item -->
<!-- v-else 当菜单没有子菜单时渲染该菜单选项 -->
<!-- :index="menu.name + ''" 设置菜单选项的索引 menu.name 转换为字符串类型 -->
<!-- @click="handleMenuClick(menu.name)" 绑定点击事件调用 handleMenuClick 方法并传入菜单的 name -->
<el-menu-item
:index="menu.name + ''"
@click="handleMenuClick(menu.name)"
v-else
>
<!-- 如果菜单有 meta.icon 属性渲染自定义的 SVG 图标组件 svg-icon -->
<svg-icon
v-if="menu.meta.icon"
:icon="menu.meta.icon"
class="sub-menu-icon"
></svg-icon>
<!-- 菜单选项的标题模板 #title -->
<template #title>
<!-- Element Plus 的工具提示组件 el-tooltip -->
<!-- effect="light" 设置工具提示的效果为淡色 -->
<!-- :content="menu.meta.title" 绑定工具提示的内容为菜单的标题 -->
<!-- placement="top-start" 设置工具提示显示在目标元素的顶部偏左位置 -->
<!-- :offset="-10" 设置工具提示与目标元素的偏移量为 -10 像素 -->
<!-- :disabled="!showTooltip" 根据 showTooltip 的值决定是否禁用工具提示 -->
<el-tooltip
effect="light"
:content="menu.meta.title"
@ -71,12 +42,9 @@
:offset="-10"
:disabled="!showTooltip"
>
<!-- 用于显示菜单标题的 span 元素 -->
<!-- ref="menuTextRef" 为元素设置引用方便在脚本中获取 -->
<!-- @mouseover="hoverMenu" 绑定鼠标移入事件调用 hoverMenu 方法 -->
<span ref="menuTextRef" @mouseover="hoverMenu">{{
menu.meta.title
}}</span>
menu.meta.title
}}</span>
</el-tooltip>
</template>
</el-menu-item>
@ -84,35 +52,26 @@
</template>
<script setup lang="ts">
// Vue defineProps ref
import { defineProps, ref } from 'vue'
// IRoute
import { IRoute } from '@/router/types'
//
import router from '@/router'
// Props menuList IRoute
export interface Props {
menuList: IRoute[]
}
// Props
defineProps<Props>()
// showTooltip false
const showTooltip = ref(false)
// handleMenuClick
const handleMenuClick = (name: string) => {
// 使 router.push name
router.push({ name })
}
// hoverMenu
// tooltip
const hoverMenu = (e: Event) => {
// HTMLSpanElement
const target = e.target as HTMLSpanElement
//
//
showTooltip.value = target.scrollWidth > target.clientWidth
}
</script>

@ -1,25 +1,12 @@
<template>
<!-- 定义一个具有类名 "sidebar-container" div 元素作为侧边栏的容器 -->
<div class="sidebar-container">
<!-- 定义一个具有类名 "logo-container" div 元素用于放置 logo 和标题 -->
<div class="logo-container">
<!-- 使用 router-link 组件创建一个到根路径 "/" 的链接标题为 "敬老院管理系统" -->
<router-link title="敬老院管理系统" to="/">
<!-- 显示侧边栏 logo 的图片使用相对路径引用项目中的 logo.png 文件 -->
<img class="sidebar-logo" src="@/assets/imgs/logo.png" />
<!-- 显示侧边栏标题的 span 元素 -->
<span class="sidebar-title">敬老院管理系统</span>
</router-link>
</div>
<!-- 使用 Element Plus el-scrollbar 组件为侧边栏添加滚动条 -->
<el-scrollbar>
<!-- 使用 Element Plus el-menu 组件创建侧边栏菜单 -->
<!-- :active-text-color="variables.menuActiveText" 绑定激活菜单项的文本颜色 variables 对象中获取 -->
<!-- :background-color="variables.menuBg" 绑定菜单的背景颜色 variables 对象中获取 -->
<!-- :default-active="active" 绑定默认激活的菜单项通过响应式变量 active 控制 -->
<!-- text-color="#fefefea6" 设置菜单文本的颜色 -->
<!-- unique-opened 确保同一时间只有一个子菜单可以展开 -->
<!-- :collapse="!$store.state.app.siderType" 根据 store app.siderType 的值控制菜单是否折叠 -->
<el-menu
:active-text-color="variables.menuActiveText"
:background-color="variables.menuBg"
@ -28,120 +15,76 @@
unique-opened
:collapse="!$store.state.app.siderType"
>
<!-- 递归调用 MenuItem 组件传入 store app.routeTree 的值作为菜单列表 -->
<MenuItem :menuList="store.state.app.routeTree" />
</el-menu>
</el-scrollbar>
<!-- 定义一个具有类名 "menufold-container" div 元素用于放置菜单折叠按钮 -->
<div class="menufold-container">
<!-- 引入并使用 MenuFold 组件 -->
<MenuFold />
</div>
</div>
</template>
<script setup lang="ts">
// components MenuItem
import MenuItem from './components/MenuItem.vue'
// components MenuFold
import MenuFold from './components/MenuFold.vue'
// variables.module.scss
import variables from '@/styles/variables.module.scss'
// Vue ref watch
import { ref, watch } from 'vue'
// vue-router RouteRecordName useRoute
import { RouteRecordName, useRoute } from 'vue-router'
// Vuex
import store from '@/store'
//
const route = useRoute()
// active 'Home'
let active = ref<RouteRecordName>('Home')
//
//
watch(
//
() => route,
//
newVal => {
// name
if (newVal.name) {
// active name
active.value = newVal.name
}
},
{
// immediate: true
immediate: true,
// deep: true
deep: true
}
)
</script>
<style lang="scss">
// .logo-container logo
.logo-container {
// router-link
.router-link-active {
//
display: flex;
// 48
height: 48px;
// 100%
width: 100%;
// 使
align-items: center;
// 0 10
padding: 0 10px;
// #002140
background-color: #002140;
//
flex-wrap: nowrap;
// .sidebar-logo logo
.sidebar-logo {
// 30
height: 30px;
// 30
width: 30px;
}
// .sidebar-title
.sidebar-title {
//
overflow: hidden;
//
text-overflow: ellipsis;
//
white-space: nowrap;
// 8
margin-left: 8px;
// 18
font-size: 18px;
//
color: #fff;
}
}
}
// .menufold-container
.menufold-container {
// 0
bottom: 0;
// Element Plus 6 -2
box-shadow: 0 0 6px -2px var(--el-color-primary);
// 40
height: 40px;
// 40
line-height: 40px;
//
position: absolute;
// 100%
width: 100%;
// z-index 999使
z-index: 999;
}
</style>

@ -1,30 +1,17 @@
<template>
<!-- 定义一个具有类名 "tags" div 元素 -->
<div class="tags">
<!-- 定义一个一级标题 h1显示文本 "tags" -->
<h1>tags</h1>
</div>
</template>
<script setup lang="ts">
// useTabList
//
// import { useTabList } from '~/composables/useTabList.js'
// useTabList
// activeTab
// tabList
// changeTab
// removeTab
// handleClose
// const { activeTab, tabList, changeTab, removeTab, handleClose } = useTabList()
</script>
<style lang="scss" scoped>
// .tags "tags"
.tags {
// 38
height: 38px;
// 0 1 #888
box-shadow: 0 0 1px #888;
}
</style>

@ -1,32 +1,19 @@
<template>
<!-- Element Plus 的容器组件 el-container添加了自定义类名 "layout-container" -->
<!-- :class="{ hideSidebar: !$store.state.app.siderType }" 根据 store app.siderType 的值动态添加 "hideSidebar" 类名 -->
<el-container
class="layout-container"
:class="{ hideSidebar: !$store.state.app.siderType }"
>
<!-- Element Plus 的侧边栏组件 el-aside -->
<!-- :width="$store.state.app.siderType? '230px' : '64px'" 根据 store app.siderType 的值动态设置侧边栏宽度 -->
<el-aside :width="$store.state.app.siderType? '230px' : '64px'">
<!-- 引入并使用自定义的 SideBar 组件 -->
<el-aside :width="$store.state.app.siderType ? '230px' : '64px'">
<SideBar />
</el-aside>
<!-- Element Plus 的容器组件 el-container添加了自定义类名 "main-container" -->
<el-container class="main-container">
<!-- Element Plus 的头部组件 el-header -->
<el-header>
<!-- 引入并使用自定义的 NavBar 组件 -->
<NavBar />
</el-header>
<!-- Element Plus 的主体组件 el-main -->
<el-main>
<!-- Element Plus 的滚动条组件 el-scrollbar -->
<el-scrollbar>
<!-- 路由视图 router-view使用插槽获取当前要渲染的组件 Component -->
<router-view v-slot="{ Component }">
<!-- 过渡组件 transition设置过渡名称为 "fade-transform"过渡模式为 "out-in" -->
<transition name="fade-transform" mode="out-in">
<!-- 动态组件 component根据 Component 的值渲染对应的组件 -->
<component :is="Component" />
</transition>
</router-view>
@ -37,14 +24,10 @@
</template>
<script setup lang="ts">
// SideBar
import SideBar from './components/SideBar/index.vue'
// NavBar
import NavBar from './components/NavBar/index.vue'
// Vuex
import store from '@/store'
//
// window.onresize = () =>
// (() => {
// /** width app-wrapper
@ -53,10 +36,8 @@ import store from '@/store'
// * width > 990
// */
// // body
// let width = document.body.clientWidth
// // mutation
// if (width > 0 && width <= 760) { //
// store.commit('app/setDeviceType', 'phone')
// } else if (width > 760 && width <= 990) { //
@ -68,41 +49,27 @@ import store from '@/store'
</script>
<style lang="scss" scoped>
// .layout-container
.layout-container {
//
position: relative;
// 100%
width: 100%;
// 100%
height: 100%;
}
// .el-header Element Plus
//
.el-header {
//
position: relative;
// 0!important
padding: 0 !important;
// 48 !important
height: 48px !important;
}
// .el-main Element Plus
//
.el-main {
// 0!important
padding: 0 !important;
// #f0f2f5
background-color: #f0f2f5;
}
// .el-scrollbar Element Plus
.el-scrollbar {
// rgb(246, 246, 246)!important
background-color: rgb(246, 246, 246) !important;
// 10px
padding: 10px;
}
</style>

@ -1,23 +1,15 @@
// 从当前目录的 index 文件中导入 routes、users、IRoute 和 IUser
import { routes, users, IRoute, IUser } from './index'
// 导入项目的 Vuex 存储实例
import store from '@/store'
// 获取路由列表的函数,接受一个用户 IDuid作为参数
// 获取路由列表
export const getRouterList = (uid: number) => {
// 从 Vuex 存储中获取当前用户的权限 ID 列表
const authIdList: number[] = store.state.app.userPeofile.authIdList
// 过滤出当前用户有权限访问的路由列表
const routeList: any[] = routes.filter(route => authIdList.includes(route.id))
// 如果传入了用户 IDuid
if (uid) {
// 查找具有指定 ID 的用户信息,userInfo 有可能是 undefined
// userInfo 有可能是 undefined
const userInfo: IUser | undefined = users.find(user => user.id === uid)
// 如果找到了用户信息
if (userInfo) {
// 以下是一段被注释掉的代码,功能可能是进一步筛选用户的授权路由列表
// const authRouteList: IRoute[] = []
// rid = router id
// userInfo.auth.map(rid => {
@ -27,14 +19,12 @@ export const getRouterList = (uid: number) => {
// }
// })
// })
// 返回成功响应,包含状态码、消息和筛选后的路由列表
return {
code: 0,
msg: 'ok',
data: routeList
}
} else {
// 如果没有找到用户信息,返回错误响应
return {
code: 1001,
msg: 'No userInfo for this UID',
@ -42,7 +32,6 @@ export const getRouterList = (uid: number) => {
}
}
} else {
// 如果没有传入用户 ID返回错误响应
return {
code: 1002,
msg: 'No UID received',

@ -1,9 +1,5 @@
// 从当前目录下的 routes 文件中导入 routes 变量和 IRoute 类型
import routes, { IRoute } from './routes'
// 从当前目录下的 users 文件中导入 users 变量和 IUser 类型
import users, { IUser } from './users'
// 导出 routes 变量,这样在其他文件中可以导入使用该变量
export { routes, users }
// 导出 IRoute 和 IUser 类型,方便其他文件导入使用这些类型定义
export type { IRoute, IUser }

@ -1,29 +1,17 @@
// 定义一个接口 IRoute用于描述路由的结构
export interface IRoute {
// 路由的唯一标识 ID类型为数字
id: number
// 父路由的 ID类型为数字
pid: number
// 路由的名称,类型为字符串
name: string
// 路由的路径,类型为字符串
path: string
// 重定向的路径,是一个可选属性,类型为字符串
redirect?: string
// 路由对应的组件路径,类型为字符串
component: string
// 路由的元数据,是一个对象
meta: {
// 路由的标题,类型为字符串
title: string
// 路由的图标名称,是一个可选属性,类型为字符串
icon?: string
}
}
// 定义一个名为 routes 的数组,元素类型为 IRoute存储路由信息
const routes: IRoute[] = [
// 第一个路由对象
{
id: 1,
pid: 0,
@ -35,7 +23,6 @@ const routes: IRoute[] = [
icon: 'home'
}
},
// 第二个路由对象
{
id: 2,
pid: 0,
@ -48,43 +35,39 @@ const routes: IRoute[] = [
icon: 'sale'
}
},
// 第三个路由对象
{
id: 3,
pid: 2,
path: 'counsel',
name: 'CounselSale',
component:'sale/counsel/index.vue',
component: 'sale/counsel/index.vue',
meta: {
title: '咨询管理',
icon: ''
}
},
// 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 4,
// pid: 2,
// path: 'intention',
// name: 'IntentionSale',
// component:'sale/intention/index.vue',
// component: 'sale/intention/index.vue',
// meta: {
// title: '意向客户',
// icon: ''
// }
// },
// 第五个路由对象
{
id: 5,
pid: 2,
path: 'book',
name: 'BookSale',
component:'sale/book/index.vue',
component: 'sale/book/index.vue',
meta: {
title: '预定管理',
icon: ''
}
},
// 第六个路由对象
{
id: 6,
pid: 0,
@ -97,7 +80,6 @@ const routes: IRoute[] = [
icon: 'live'
}
},
// 第七个路由对象
{
id: 7,
pid: 6,
@ -109,7 +91,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第八个路由对象
{
id: 8,
pid: 6,
@ -121,7 +102,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第九个路由对象
{
id: 9,
pid: 6,
@ -133,7 +113,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第十个路由对象
{
id: 10,
pid: 6,
@ -145,7 +124,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第十一个路由对象
{
id: 11,
pid: 6,
@ -157,7 +135,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第十二个路由对象
{
id: 12,
pid: 6,
@ -169,7 +146,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第十三个路由对象
{
id: 13,
pid: 0,
@ -182,7 +158,6 @@ const routes: IRoute[] = [
icon: 'people'
}
},
// 第十四个路由对象
{
id: 14,
pid: 13,
@ -194,11 +169,10 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第十五个路由对象
{
id: 15,
pid: 13,
path:'staff',
path: 'staff',
name: 'StaffPeople',
component: 'people/staff/index.vue',
meta: {
@ -206,7 +180,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 16,
// pid: 13,
@ -218,66 +191,61 @@ const routes: IRoute[] = [
// icon: ''
// }
// },
// 第十七个路由对象
{
id: 17,
pid: 0,
path: '/serve',
name: 'Serve',
redirect: '/serve/project',
component:'serve/index.vue',
component: 'serve/index.vue',
meta: {
title: '服务管理',
icon:'serve'
icon: 'serve'
}
},
// 第十八个路由对象
{
id: 18,
pid: 17,
path: 'project',
name: 'ProjectServe',
component:'serve/project/index.vue',
component: 'serve/project/index.vue',
meta: {
title: '服务项目',
icon: ''
}
},
// 第十九个路由对象
{
id: 19,
pid: 17,
path: 'level',
name: 'LevelServe',
component:'serve/level/index.vue',
component: 'serve/level/index.vue',
meta: {
title: '护理等级',
icon: ''
}
},
// 第二十个路由对象
{
id: 20,
pid: 17,
path: 'book',
name: 'BookServe',
component:'serve/book/index.vue',
component: 'serve/book/index.vue',
meta: {
title: '服务预定',
icon: ''
}
},
// 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 21,
// pid: 0,
// path: '/resource',
// name: 'Resource',
// redirect: '/resource/info',
// component:'resource/index.vue',
// component: 'resource/index.vue',
// meta: {
// title: '物资管理',
// icon:'resource'
// icon: 'resource'
// }
// },
// {
@ -285,7 +253,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'info',
// name: 'InfoResource',
// component:'resource/info/index.vue',
// component: 'resource/info/index.vue',
// meta: {
// title: '物资信息',
// icon: ''
@ -296,7 +264,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'Storage',
// name: 'StorageResource',
// component:'resource/storage/index.vue',
// component: 'resource/storage/index.vue',
// meta: {
// title: '仓库设置',
// icon: ''
@ -307,7 +275,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'enter',
// name: 'EnterResource',
// component:'resource/enter/index.vue',
// component: 'resource/enter/index.vue',
// meta: {
// title: '入库管理',
// icon: ''
@ -318,7 +286,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'leave',
// name: 'LeaveResource',
// component:'resource/leave/index.vue',
// component: 'resource/leave/index.vue',
// meta: {
// title: '出库管理',
// icon: ''
@ -327,15 +295,14 @@ const routes: IRoute[] = [
// {
// id: 26,
// pid: 21,
// path:'search',
// path: 'search',
// name: 'SearchResource',
// component:'resource/search/index.vue',
// component: 'resource/search/index.vue',
// meta: {
// title: '库存查询',
// icon: ''
// }
// },
// 第二十七个路由对象
{
id: 27,
pid: 0,
@ -348,7 +315,6 @@ const routes: IRoute[] = [
icon: 'diet'
}
},
// 第二十八个路由对象
{
id: 28,
pid: 27,
@ -360,7 +326,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第二十九个路由对象
{
id: 29,
pid: 27,
@ -372,7 +337,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十个路由对象
{
id: 30,
pid: 27,
@ -384,7 +348,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十一个路由对象
{
id: 31,
pid: 0,
@ -397,7 +360,6 @@ const routes: IRoute[] = [
icon: 'charge'
}
},
// 第三十二个路由对象
{
id: 32,
pid: 31,
@ -409,11 +371,10 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十三个路由对象
{
id: 33,
pid: 31,
path:'record',
path: 'record',
name: 'RecordCharge',
component: 'charge/record/index.vue',
meta: {
@ -421,7 +382,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十四个路由对象
{
id: 34,
pid: 31,
@ -433,7 +393,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十五个路由对象
{
id: 35,
pid: 0,
@ -446,11 +405,10 @@ const routes: IRoute[] = [
icon: 'base'
}
},
// 第三十六个路由对象
{
id: 36,
pid: 35,
path:'sale',
path: 'sale',
name: 'SaleBase',
redirect: '/base/sale/origin',
component: 'base/sale/index.vue',
@ -459,7 +417,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第三十七个路由对象
{
id: 37,
pid: 36,
@ -471,7 +428,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 38,
// pid: 36,
@ -483,7 +439,6 @@ const routes: IRoute[] = [
// icon: ''
// }
// },
// 第三十九个路由对象
{
id: 39,
pid: 35,
@ -496,7 +451,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第四十个路由对象
{
id: 40,
pid: 39,
@ -508,7 +462,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 第四十一个路由对象
{
id: 41,
pid: 39,
@ -520,7 +473,6 @@ const routes: IRoute[] = [
icon: ''
}
},
// 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 42,
// pid: 35,
@ -531,5 +483,4 @@ const routes: IRoute[] = [
// }
]
// 导出 routes 数组,使其可以在其他模块中被导入和使用
export default routes

@ -1,20 +1,13 @@
// 定义一个接口 IUser用于描述用户对象的结构
export interface IUser {
// 用户的唯一标识 ID类型为数字
id: number
// 用户的用户名,类型为字符串
username: string
// 用户拥有的权限 ID 数组,数组中的元素类型为数字
auth: number[]
}
// 导出一个默认的用户数组,类型为 IUser 数组
// 数组中包含一个用户对象
export default <IUser[]>[
{
id: 1,
username: 'zhangsan',
// 该用户拥有的权限 ID 数组,包含多个权限 ID
auth: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,

@ -1,17 +1,11 @@
// 从 '@element-plus/icons-vue' 模块中导入所有的图标组件
import * as ElIcons from '@element-plus/icons-vue'
// 从 'vue' 模块中导入 App 类型,用于表示 Vue 应用实例
import { App } from 'vue'
// 定义一个名为 useElementPlus 的函数,该函数接受一个 App 类型的参数 app
const useElementPlus = (app: App) => {
// 遍历 ElIcons 对象的所有属性
// 注册图标
for (const [key, component] of Object.entries(ElIcons)) {
// 使用 app.component 方法将每个图标组件注册为全局组件
// 组件的名称为属性名 key组件本身为 component
app.component(key, component)
}
}
// 导出 useElementPlus 函数,使其可以在其他模块中被导入和使用
export default useElementPlus

@ -1,6 +1,3 @@
// 从当前目录下的 element-plus 文件中导入名为 useElementPlus 的函数
import useElementPlus from './element-plus'
// 重新导出 useElementPlus 函数,这样其他模块在导入这个文件时
// 可以通过解构赋值等方式获取到 useElementPlus 函数
export { useElementPlus }

@ -1,87 +1,62 @@
// 从 vue-router 库中导入创建路由实例、路由记录类型和哈希路由历史模式的方法
import { createRouter, RouteRecordRaw, createWebHashHistory } from 'vue-router'
// 导入布局组件
import Layout from '@/layout/index.vue'
// 导入 Vuex 存储实例
import store from '@/store'
// 导入初始化动态路由的工具函数
import { initRoutes } from './utils'
// 定义静态路由数组,包含应用中固定的路由配置
// 静态路由
const routes: Array<RouteRecordRaw> = [
{
// 根路径
path: '/',
// 路由名称
name: 'Layout',
// 路由对应的组件
component: Layout,
// 重定向到 /home 路径
redirect: '/home',
// 子路由数组,初始为空
children: []
},
{
// 登录页面路径
path: '/login',
// 路由名称
name: 'Login',
// 路由元信息,包含页面标题
meta: {
title: '登录'
},
// 使用动态导入方式加载登录页面组件
component: () =>
import(/* webpackChunkName: "Login" */ '@/views/login/index.vue')
},
{
// 匹配所有未定义的路径
path: '/:pathMatch(.*)*',
// 路由名称
name: 'NotFound',
// 路由元信息,包含页面标题
meta: {
title: '404'
},
// 使用动态导入方式加载 404 错误页面组件
component: () =>
import(/* webpackChunkName: "404" */ '@/views/error/404.vue')
}
]
// 创建路由实例
const router = createRouter({
// 使用哈希路由历史模式
history: createWebHashHistory(),
// 路由配置
routes
})
// 定义路由白名单,包含无需验证即可访问的路径
const ROUTER_WHITE_LIST = ['/login']
// 全局前置守卫,在每次路由跳转前执行
router.beforeEach(async (to, from, next) => {
// 设置页面标题,将目标路由的元信息中的标题与固定后缀拼接
document.title = to.meta.title + ' | 敬老院管理系统'
// 设置页面标题
document["title"] = to.meta.title + " | 敬老院管理系统"
// 判断访问页面路径是否在路由白名单中,如果存在直接放行
// .判断访问页面是否在路由白名单地址中,如果存在直接放行
if (ROUTER_WHITE_LIST.includes(to.path)) return next()
// 判断是否有 Token如果没有则重定向到登录页面
//.判断 是否有 Token没有重定向到 login
if (!store.state.app.token) return next({ path: '/login', replace: true })
// 如果没有初始化动态路由且存在 Token则初始化动态路由
//如果没有初始化动态路由就初始化
if (!store.state.app.hasAuth && store.state.app.token) {
// 调用初始化动态路由的工具函数
await initRoutes()
// 重新跳转至目标路径
return next({ path: to.path })
}
// 正常访问页面,放行路由跳转
// 7.正常访问页面
next()
})
// 导出路由实例,供应用使用
export default router

@ -1,25 +1,14 @@
/** 路由 */
// 定义一个接口 IRoute用于规范路由对象的结构
export interface IRoute {
// 路由的唯一标识 ID类型为数字
id: number
// 父路由的 ID类型为数字用于表示路由的层级关系
pid: number
// 路由的名称,在路由配置和导航中使用,类型为字符串
name: string
// 路由的路径,用于在浏览器地址栏中显示和导航,类型为字符串
path: string
// 重定向的路径,是一个可选属性,当访问该路由时会自动重定向到指定路径,类型为字符串
redirect?: string
// 路由对应的组件路径,指定该路由应渲染的 Vue 组件的路径,类型为字符串
component: string
// 路由的元数据,是一个对象,包含与路由相关的额外信息
meta: {
// 路由的标题,可用于页面标题、菜单显示等,类型为字符串
title: string
// 路由的图标名称,是一个可选属性,可用于在菜单中显示图标,类型为字符串
icon?: string
}
// 子路由数组,是一个可选属性,用于表示该路由下的子路由列表,元素类型为 IRoute
children?: IRoute[]
}

@ -1,53 +1,31 @@
// 从项目的路由类型文件中导入 IRoute 接口,用于描述路由的结构
import { IRoute } from "@/router/types";
// 从 vue-router 库中导入 Router 和 RouteRecordRaw 类型
// Router 是 Vue Router 的实例类型RouteRecordRaw 用于定义路由记录
import { Router, RouteRecordRaw } from "vue-router";
// 导入项目的路由实例
import router from "./index";
// 导入项目的 Vuex 存储实例
import store from "@/store";
// 从项目的工具函数文件中导入数组去重的工具函数
import { arrayDeduplicationByFiled } from "@/utils/commonUtil";
/** 将后端返回的路由转换成生成树形结构 */
function formatRouteTree(data: IRoute[]) {
// 过滤出父路由,即 pid 为 0 的路由
const parents = data.filter(routeInfo => routeInfo.pid === 0);
// 过滤出子路由,即 pid 不为 0 的路由
const children = data.filter(routeInfo => routeInfo.pid !== 0);
// 调用递归函数将数据转换为树形结构
dataToTree(parents, children);
// 返回转换后的父路由数组,此时父路由数组中包含了子路由信息
return parents;
/**
*
* @param parents
* @param children
*/
function dataToTree(parents: IRoute[], children: IRoute[]) {
// 遍历父路由数组
parents.map(parent => {
// 遍历子路由数组
children.map((child, index) => {
// 如果子路由的 pid 等于父路由的 id
if (child.pid === parent.id) {
// 复制一份子路由数组,避免在原数组上进行操作
const _children: IRoute[] = JSON.parse(JSON.stringify(children));
// 从复制的子路由数组中移除当前处理的子路由
_children.splice(index, 1);
// 递归调用 dataToTree 函数,处理当前子路由的子路由
dataToTree([child], _children);
if (parent.children) {
// 如果父路由已经有子路由数组,将当前子路由添加到该数组中
// 添加
parent.children.push(child);
// 对父路由的子路由数组进行去重操作,根据 id 字段去重
// 菜单去重
parent.children = arrayDeduplicationByFiled(parent.children, "id");
} else {
// 如果父路由还没有子路由数组,创建一个包含当前子路由的数组
parent.children = [child];
}
}
@ -58,66 +36,46 @@ function formatRouteTree(data: IRoute[]) {
/** 将树形结构路由转化成真实的路由 */
function generateRouter(routeTree: IRoute[]) {
// 遍历树形结构的路由数组
const newRoutes = routeTree.map(route => {
// 创建一个新的路由记录对象
const _route: RouteRecordRaw = {
// 路由的路径
path: route.path,
// 路由的名称
name: route.name,
// 路由的元信息
meta: route.meta,
// 路由的重定向路径
redirect: route.redirect,
// 使用动态导入的方式加载路由对应的组件,组件位于 @/views 目录下
component: () => import("@/views/" + route.component),
// 子路由数组,初始为空
component: () => import("@/views/" + route.component), // 注意views目录下才能引入否则ts不识别
children: []
};
// 如果当前路由有子路由
if (route.children) {
// 递归调用 generateRouter 函数,处理子路由
_route.children = generateRouter(route.children);
}
// 返回新创建的路由记录对象
return _route;
});
// 返回转换后的路由记录数组
return newRoutes;
}
// 初始化动态路由的函数
//初始化动态路由
export async function initRoutes() {
// 调用 Vuex 的 action获取路由树形结构数据
await store.dispatch("app/getRouterTree");
// 将获取到的路由树形结构数据转换为真实的路由记录数组
const newRoutes = generateRouter(store.state.app.routeTree);
// 遍历新的路由记录数组,将每个路由添加到名为 "Layout" 的父路由下
newRoutes.forEach(route => router.addRoute("Layout", route));
}
// 清除路由的函数
//清除路由
export function clearRoutes() {
// 定义默认的路由名称数组
//删除之前注册的路由 默认状态下只有三个,如果超过三个删除多余的路由
const defaultRoutes = ["Layout", "Login", "NotFound"];
// 获取当前路由实例中的所有路由记录
const currentRoutes = router.getRoutes();
// 如果当前路由记录的数量不等于 3
if (currentRoutes.length != 3) {
// 遍历当前的路由记录数组
//执行删除
currentRoutes.forEach(item => {
// 如果当前路由的名称不在默认路由名称数组中
if (!defaultRoutes.includes(String(item.name))) {
// 从路由实例中移除该路由
router.removeRoute(String(item.name));
}
});
}
}
// 导出 formatRouteTree 和 generateRouter 函数,供其他模块使用
export { formatRouteTree, generateRouter };

@ -1,46 +1,29 @@
// 从 vue 库中导入 InjectionKey 类型,用于在 Vue 3 中为 provide 和 inject 提供类型约束
import { InjectionKey } from 'vue'
// 从 vuex 库中导入创建 store 的函数、基础的 useStore 函数和 Store 类型
import { createStore, useStore as baseUseStore, Store } from 'vuex'
// 从项目的 store 类型文件中导入根状态类型
import { IRootState } from '@/store/types'
// 从当前模块的 app 子模块中导入名为 store 的对象
import { store as app } from './modules/app'
// 从当前模块的工具文件中导入自定义的 CommonStore 类型
import { CommonStore } from './utils'
// 导入 vuex-persistedstate 插件,用于将 store 中的状态持久化到本地存储
import createPersistedState from 'vuex-persistedstate'
// 定义一个包含所有模块的对象,这里目前只有 app 模块
export const modules = {
app
}
// 定义一个注入键,用于在使用 useStore 时约束 state 的类型
// 这里使用 Symbol 创建一个唯一的键,类型为 Store<IRootState>
// injectionKey约束state类型
export const key: InjectionKey<Store<IRootState>> = Symbol()
// 创建一个 Vuex store 实例,指定根状态类型为 IRootState
const store = createStore<IRootState>({
// 注册模块
modules,
// 应用插件
plugins: [
// 使用 vuex-persistedstate 插件
createPersistedState({
// 存储在本地存储中的键名
key: 'stateData',
// 指定需要持久化的模块路径,这里只持久化 app 模块
paths: ['app']
})
]
}) as CommonStore
// 定义一个自定义的 useStore 函数,返回类型为 CommonStore
// 调用 baseUseStore 函数并传入注入键,确保类型安全
export function useStore(): CommonStore {
return baseUseStore(key)
}
// 导出创建好的 store 实例,供应用使用
export default store

@ -1,46 +1,26 @@
// 从 vuex 中导入 ActionContext 类型,用于在 action 中获取上下文
import { ActionContext } from 'vuex'
// 从项目的 store 类型文件中导入根状态类型
import { IRootState } from '@/store/types'
// 从当前模块的类型文件中导入当前模块的状态类型
import { IAppState } from './types'
// 从项目的路由类型文件中导入路由类型
import { IRoute } from '@/router/types'
// 从项目的模拟数据获取器中导入获取路由列表的函数
import { getRouterList } from '@/mock/getters'
// 从项目的路由工具文件中导入清除路由和格式化路由树的函数
import { clearRoutes, formatRouteTree } from '@/router/utils'
// 从项目的 API 模块中导入获取用户路由列表的函数(当前注释掉未使用)
// import { getUserRouteList } from '@/apis'
// 从项目的用户 API 模块中导入登录请求函数
import { getLogin } from '@/apis/user'
// 导入项目的路由实例
import router from '@/router'
// 定义默认状态对象
const defaultState = {
// 用户 ID初始为 1
uid: 1,
// 用户令牌,初始为空字符串
token: '',
// 是否有路由权限,初始为 false
hasAuth: false,
// 路由树,初始为空数组
routeTree: [],
// 侧边栏是否展开,初始为 true 表示展开
siderType: true,
// 用户信息,初始为空对象
userPeofile: {},
// 是否记住密码,初始为 false
rememberPWD: false
}
// 导出当前模块的 store 配置
export const store = {
// 开启命名空间,使模块的 action、mutation 和 getter 名称唯一
namespaced: true,
// 模块的状态
state: {
uid: 1,
token: '',
@ -50,53 +30,38 @@ export const store = {
userPeofile: {},
rememberPWD: false
},
// 模块的 mutations用于修改状态
mutations: {
// 设置用户令牌的 mutation
setToken(state: IAppState, token: string) {
state.token = token
},
// 设置路由树的 mutation
setRouteTree(state: IAppState, routeTree: IRoute[]) {
state.routeTree = routeTree
},
// 设置是否有路由权限的 mutation
setAuth(state: IAppState, auth: boolean) {
state.hasAuth = auth
},
// 切换侧边栏展开状态的 mutation
setSiderType(state: IAppState) {
state.siderType = !state.siderType
},
// 设置用户信息的 mutation
setUserProfile(state: IAppState, userPeofile: any) {
state.userPeofile = userPeofile
},
// 设置是否记住密码的 mutation
setRememberPWD(state: IAppState, rememberPWD: boolean) {
state.rememberPWD = rememberPWD
},
// 清除 store 状态的 mutation将状态重置为默认状态
clearStore(state: IAppState) {
Object.assign(state, defaultState)
}
},
// 模块的 actions用于处理异步操作和提交 mutations
actions: {
// 登录 action
//登录
async actionLogin(
// 从上下文获取 commit 和 state
{ commit, state }: ActionContext<IAppState, IRootState>,
// 登录数据
data: any
) {
// 调用登录请求函数
const res: any = await getLogin(data)
// 如果登录成功
if (res.code === 200) {
// 提交设置令牌的 mutation
commit('setToken', res?.data?.token)
// 提交设置用户信息的 mutation
commit('setUserProfile', {
username: res?.data.name,
userid: res?.data.id,
@ -104,31 +69,22 @@ export const store = {
authIdList: res?.data.authIdList
})
}
// 提交设置是否记住密码的 mutation
commit('setRememberPWD', data?.rememberPWD)
// 返回登录请求的响应
return res
},
// 获取权限菜单 action
//获取权限菜单
getRouterTree({ commit, state }: ActionContext<IAppState, IRootState>) {
// 模拟获取路由列表
// 模拟数据
const routeList = getRouterList(state.uid).data as unknown as IRoute[]
// 格式化路由列表为路由树
const routeTree = formatRouteTree(routeList)
// 提交设置路由树的 mutation
commit('setRouteTree', routeTree)
// 提交设置有路由权限的 mutation
commit('setAuth', true)
},
// 点击登出 action
// 点击登出
logout({ commit, state }: ActionContext<IAppState, IRootState>) {
// 提交清除 store 状态的 mutation
commit('clearStore')
// 清除本地存储
localStorage.clear()
// 清除动态添加的路由
clearRoutes()
// 路由跳转到登录页
router.replace('/login')
}
}

@ -1,20 +1,11 @@
// 从项目的路由类型文件中导入 IRoute 接口,用于描述路由的结构
import { IRoute } from '@/router/types'
// 定义一个接口 IAppState用于描述应用状态的结构
export interface IAppState {
// 用户 ID类型为数字
uid: number
// 用户令牌,类型为字符串
token: string
// 是否有路由权限,类型为布尔值
hasAuth: boolean
// 路由树,是一个 IRoute 类型的数组,用于存储路由信息
routeTree: IRoute[]
// 侧边栏是否展开,类型为布尔值
siderType: boolean
// 用户信息,类型为 any表示可以是任意类型的数据
userPeofile: any
// 是否记住密码,类型为布尔值
rememberPWD: boolean
}

@ -1,16 +1,9 @@
// 从 vuex 中导入 ActionContext 类型,它用于在 actions 里获取上下文,能访问 state、getters、mutations 等
import { ActionContext } from 'vuex'
// 从项目的路由配置文件导入路由实例,后续可能会在 actions 里使用路由进行页面跳转
import router from '@/router'
// 导出一个名为 store 的对象,这是一个 Vuex 模块
export const store = {
// 设置为 true 表示开启命名空间,可避免不同模块间的 action、mutation 和 getter 名称冲突
namespaced: true,
// state 是存储数据的地方,这里初始为空对象,后续可添加应用所需的状态数据
state: {},
// mutations 用于修改 state 中的数据,是同步操作,这里初始为空对象,后续可添加具体的 mutation 函数
mutations: {},
// actions 用于处理异步操作,如发起网络请求等,这里初始为空对象,后续可添加具体的 action 函数
actions: {}
}

@ -1,11 +1,5 @@
// 从项目的 app 模块的类型文件中导入 IAppState 类型,该类型描述了 app 模块的状态结构
import { IAppState } from '@/store/modules/app/types'
/**
* IRootState Vuex
* Vuex app
*/
export type IRootState = {
// app 字段的类型为 IAppState意味着根状态中的 app 模块状态遵循 IAppState 类型的定义
app: IAppState
}

@ -1,29 +1,25 @@
/** 智能提示 */
// 从当前目录的 types 文件中导入 IRootState 类型,用于表示根状态
import { IRootState } from './types'
// 从当前目录的 index 文件中导入 modules 对象,该对象包含了所有的 Vuex 模块
import { modules } from './index'
// 从 vuex 库中导入 CommitOptions、DispatchOptions 和 Store 类型
import { CommitOptions, DispatchOptions, Store as VuexStore } from 'vuex'
// 获取 modules 的类型
// 获取modules的类型
type Modules = typeof modules
// 获取所有模块下的 mutations
type GetMutation<T> = T extends { mutations: infer G }? G : never
// 获取所有模块下的mutations
type GetMutation<T> = T extends { mutations: infer G } ? G : never
type GetMutations<T> = {
[K in keyof T]: GetMutation<T[K]>
}
type mutationsObj = GetMutations<Modules>
// 获取所有模块下的 actions
type GetAction<T> = T extends { actions: infer G }? G : never
// 获取所有模块下的actions
type GetAction<T> = T extends { actions: infer G } ? G : never
type GetActions<T> = {
[K in keyof T]: GetAction<T[K]>
}
type actionsObj = GetActions<Modules>
// 获取所有模块下的 getters
type GetGetter<T> = T extends { getters: infer G }? G : never
// 获取所有模块下的getters
type GetGetter<T> = T extends { getters: infer G } ? G : never
type GetGetters<T> = {
[K in keyof T]: GetGetter<T[K]>
}

@ -1,27 +1,22 @@
/* 为.el-breadcrumb__inner 和.el-breadcrumb__inner a 元素设置字体加粗为 400!important 提高优先级 */
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
/* 隐藏.el-upload 元素内的 input[type='file'] 元素,!important 提高优先级 */
.el-upload {
input[type='file'] {
display: none !important;
}
}
/* 隐藏.el-upload__input 元素 */
.el-upload__input {
display: none;
}
/* 为.upload-container 元素内的.el-upload 元素设置宽度为 100% */
.upload-container {
.el-upload {
width: 100%;
/* 为.upload-container 元素内的.el-upload 元素的.el-upload-dragger 子元素设置宽度为 100%,高度为 200px */
.el-upload-dragger {
width: 100%;
height: 200px;
@ -29,70 +24,62 @@
}
}
/* 为.el-dropdown-menu 元素设置内边距为 0!important 提高优先级 */
.el-dropdown-menu {
padding: 0 !important;
}
/* 为.el-range-separator 元素设置盒模型为 content-box */
.el-range-separator {
box-sizing: content-box;
}
/* 为.is-dark 元素设置 z-index 为 9999!important 提高优先级 */
.is-dark {
z-index: 9999 !important;
}
/* 重置带有 [class*='el-icon'] 类且后面跟着 span 元素的 margin-left 为 2px!important 提高优先级 */
/* 重置 el-button 中 icon 的 margin */
.reset-margin [class*='el-icon'] + span {
margin-left: 2px !important;
}
/* 为.pure-popper 元素设置内边距为 0!important 提高优先级 */
/* 自定义 popover 的类名 */
.pure-popper {
padding: 0 !important;
}
/* 为.pure-tooltip 元素设置 z-index 为 41000!important 提高优先级,因为右侧操作面板 right-panel 类名的 z-index 为 40000tooltip 需要大于它才能显示 */
/* 自定义 tooltip 的类名 */
.pure-tooltip {
// right-panelz-index40000tooltip
z-index: 41000 !important;
}
/* 为 #nprogress 元素及其子元素设置样式 */
/* nprogress 适配 element-plus 的主题色 */
#nprogress {
/* 为 #nprogress 元素的.bar 子元素设置背景颜色为 --el-color-primary 变量的值,!important 提高优先级 */
&.bar {
& .bar {
background-color: var(--el-color-primary) !important;
}
/* 为 #nprogress 元素的.peg 子元素设置 box-shadow颜色为 --el-color-primary 变量的值,!important 提高优先级 */
&.peg {
& .peg {
box-shadow: 0 0 10px var(--el-color-primary),
0 0 5px var(--el-color-primary) !important;
}
/* 为 #nprogress 元素的.spinner-icon 子元素设置边框颜色为 --el-color-primary 变量的值 */
&.spinner-icon {
& .spinner-icon {
border-top-color: var(--el-color-primary);
border-left-color: var(--el-color-primary);
}
}
/* 为.el-dialog__headerbtn 和.el-message-box__headerbtn 元素的:hover 状态设置样式 */
/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标的样式表现更鲜明 */
.el-dialog__headerbtn,
.el-message-box__headerbtn {
&:hover {
/* 为.el-dialog__headerbtn 和.el-message-box__headerbtn 元素在:hover 状态下的.el-dialog__close 子元素设置颜色为 --el-color-info 变量的值,!important 提高优先级 */
.el-dialog__close {
color: var(--el-color-info) !important;
}
}
}
/* 为.el-icon 元素及其特定子元素设置样式 */
.el-icon {
/* 为.el-icon 元素的.el-dialog__close、.el-drawer__close、.el-message-box__close 和.el-notification__closeBtn 子元素设置样式 */
&.el-dialog__close,
&.el-drawer__close,
&.el-message-box__close,
@ -103,7 +90,6 @@
border-radius: 4px;
transition: background-color 0.2s, color 0.2s;
/* 为这些子元素的:hover 状态设置样式 */
&:hover {
color: rgba(0, 0, 0, 0.88) !important;
background-color: rgba(0, 0, 0, 0.06);
@ -112,7 +98,7 @@
}
}
/* 克隆并自定义 ElMessage 样式,为.pure-message 元素设置样式 */
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,暗黑模式在 src/style/dark.scss 文件进行了适配 */
.pure-message {
border-width: 0 !important;
background: #fff !important;
@ -120,85 +106,69 @@
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014,
0 9px 28px 8px #0000000d !important;
/* 为.pure-message 元素的.is-closable 子元素的.el-message__content 子元素设置内边距 */
&.el-message.is-closable.el-message__content {
&.el-message.is-closable .el-message__content {
padding-right: 17px !important;
}
/* 为.pure-message 元素的.el-message__content 子元素设置颜色、指针事件和背景图像 */
&.el-message__content {
& .el-message__content {
color: #000000d9 !important;
pointer-events: all !important;
background-image: initial !important;
}
/* 为.pure-message 元素的.el-message__icon 子元素设置外边距 */
&.el-message__icon {
& .el-message__icon {
margin-right: 8px !important;
}
/* 为.pure-message 元素的.el-message__closeBtn 子元素设置样式 */
&.el-message__closeBtn {
& .el-message__closeBtn {
outline: none;
border-radius: 4px;
right: 9px !important;
transition: background-color 0.2s, color 0.2s;
/* 为.el-message__closeBtn 子元素的:hover 状态设置背景颜色 */
&:hover {
background-color: rgba(0, 0, 0, 0.06);
}
}
}
/* 为.el-popconfirm 元素的.el-popconfirm__action 子元素内的不同类型的.el-button 元素设置样式 */
.el-popconfirm {
.el-popconfirm__action {
/* 为.el-popconfirm__action 子元素内的.el-button--primary 类型的按钮设置背景颜色 */
.el-button--primary {
background-color: #409eff !important;
/* 为.el-button--primary 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #79bbff !important;
}
}
/* 为.el-popconfirm__action 子元素内的.el-button--success 类型的按钮设置背景颜色 */
.el-button--success {
background-color: #67C23A !important;
/* 为.el-button--success 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #95d475 !important;
}
}
/* 为.el-popconfirm__action 子元素内的.el-button--warning 类型的按钮设置背景颜色 */
.el-button--warning {
background-color: #E6A23C !important;
/* 为.el-button--warning 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #eebe77 !important;
}
}
/* 为.el-popconfirm__action 子元素内的.el-button--danger 类型的按钮设置背景颜色 */
.el-button--danger {
background-color: #F56C6C !important;
background-color: #f56c6c !important;
/* 为.el-button--danger 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #f89898 !important;
}
}
/* 为.el-popconfirm__action 子元素内的.el-button--info 类型的按钮设置背景颜色 */
.el-button--info {
background-color: #909399 !important;
/* 为.el-button--info 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #b1b3b8 !important;
}
@ -206,56 +176,46 @@
}
}
/* 为.el-button--primary 类型的按钮设置颜色和背景颜色 */
.el-button--primary {
color: white !important;
background-color: #409EFF !important;
/* 为.el-button--primary 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #79bbff !important;
}
}
/* 为.el-button--success 类型的按钮设置颜色和背景颜色 */
.el-button--success {
color: white !important;
background-color: #67C23A !important;
/* 为.el-button--success 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #95d475 !important;
}
}
/* 为.el-button--warning 类型的按钮设置颜色和背景颜色 */
.el-button--warning {
color: white !important;
background-color: #E6A23C !important;
/* 为.el-button--warning 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #eebe77 !important;
}
}
/* 为.el-button--danger 类型的按钮设置颜色和背景颜色 */
.el-button--danger {
color: white !important;
background-color: #F56C6C !important;
/* 为.el-button--danger 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #f89898 !important;
}
}
/* 为.el-button--info 类型的按钮设置颜色和背景颜色 */
.el-button--info {
color: white !important;
background-color: #909399 !important;
/* 为.el-button--info 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #b1b3b8 !important;
}

@ -1,26 +1,9 @@
//
@import './variables.module.scss';
// mixin
@import './mixin.scss';
//
@import './base.scss';
// 使
@import './reset.scss';
//
@import './variables.module.scss'; //
@import './mixin.scss'; //
@import './base.scss'; //
@import './reset.scss'; //
@import './login.scss';
//
@import './navbar.scss';
//
@import './sidebar.scss';
// Element Plus Element Plus
@import './element.scss';
//
@import './transition.scss';

@ -1,116 +1,70 @@
// .login-container
.login-container {
//
position: relative;
// 100%
height: 100vh;
// 100%
width: 100vw;
//
display: flex;
// 使
justify-content: space-between;
// .login-container .left-box .right-box
.left-box,
.right-box {
flex: 1;
}
// .login-container .right-box
.right-box {
//
display: flex;
// 使
align-items: center;
// 90
margin-top: -90px;
// .right-box .login-form .forget-pass-form
.login-form,
.login-form ,
.forget-pass-form {
// 360
width: 360px;
// 50
margin-left: 50px;
// .login-form .forget-pass-form .title
.title {
//
display: flex;
flex-direction: column;
// 使
align-items: center;
// .title img
img {
width: 80px;
height: 80px;
}
// .title h2
h2 {
//
color: #9193a3;
// 10 0 15 0
margin: 10px 0 15px 0;
}
}
// .login-form .forget-pass-form .password-set
.password-set {
//
display: flex;
// 100%
width: 100%;
// -10 0 10 0
margin: -10px 0 10px 0;
// 使
justify-content: right;
}
}
}
// .login-container .left-box
.left-box {
//
position: relative;
// 100%
width: 100%;
// .left-box
&::before {
content: '';
//
position: absolute;
//
top: 0;
//
left: 0;
// 100%
width: 100%;
// 100%
height: 100%;
// 使 bg.png
background-image: url('~@/assets/imgs/bg.png');
//
background-repeat: no-repeat;
// 100%
background-size: auto 100%;
// z -1使.left-box
z-index: -1;
}
// .left-box .img
.img {
// 100%
width: 100%;
// 100%
height: 100%;
//
display: flex;
// 使
align-items: center;
// 使
justify-content: center;
// .img img
img {
width: 500px;
}

@ -1,34 +1,26 @@
// clearfix mixin
@mixin clearfix {
// 使:after
&:after {
content: '';
//
display: table;
clear: both;
}
}
// scrollBar mixin
@mixin scrollBar {
//
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
//
&::-webkit-scrollbar {
width: 6px;
}
//
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
// relative mixin
@mixin relative {
position: relative;
width: 100%;

@ -1,31 +1,19 @@
/* 定义一个名为.navbar-bg-hover 的类选择器,用于设置导航栏背景悬停效果的样式 */
//
.navbar-bg-hover {
/* 设置为弹性盒子布局 */
display: flex;
/* 使弹性盒子内的子元素在垂直方向上居中对齐 */
align-items: center;
/* 使弹性盒子内的子元素在水平方向上居中对齐 */
justify-content: center;
/* 设置高度为 48 像素 */
height: 48px;
/* 设置内边距为 12 像素 */
padding: 12px;
/* 设置所有属性的过渡效果,持续时间为 0.3 秒 */
transition: all 0.3s;
}
/* 当.navbar-bg-hover 元素被鼠标悬停时的样式 */
&:hover {
/* 设置背景颜色为 #f6f6f6 */
background-color: #f6f6f6;
/* 设置鼠标指针样式为指针 */
cursor: pointer;
/* 再次设置所有属性的过渡效果,持续时间为 0.3 秒 */
transition: all 0.3s;
}
&:hover {
background-color: #f6f6f6;
cursor: pointer;
transition: all 0.3s;
}
/* 选择.navbar-bg-hover 元素内的.svg-icon 元素,设置其样式 */
.svg-icon {
/* 去除轮廓线 */
outline: none;
.svg-icon {
outline: none;
}
}

@ -1,97 +1,61 @@
/* 对 html 和 body 元素设置样式 */
html,
body {
/* 设置高度为视口高度的 100% */
height: 100%;
/* 去除外边距 */
margin: 0;
/* 去除内边距 */
padding: 0;
/* 针对 Firefox 浏览器,设置字体抗锯齿为灰度模式,提高字体显示质量 */
-moz-osx-font-smoothing: grayscale;
/* 针对 WebKit 内核的浏览器(如 Chrome、Safari设置字体抗锯齿提高字体显示质量 */
-webkit-font-smoothing: antialiased;
/* 设置文本渲染方式为优化可读性 */
text-rendering: optimizeLegibility;
//
// font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
// Microsoft YaHei, Arial, sans-serif;
}
/* 对 id 为 app 的元素设置样式 */
#app {
/* 设置高度为视口高度的 100% */
height: 100%;
}
/* 对所有元素及其伪元素(:before 和 :after设置样式 */
*,
*:before,
*:after {
/* 使元素的 box-sizing 属性继承自父元素,通常用于统一盒模型的计算方式 */
box-sizing: inherit;
/* 去除外边距 */
margin: 0;
/* 去除内边距 */
padding: 0;
}
/* 对处于激活active和获得焦点focus状态的 a 元素设置样式 */
a:focus,
a:active {
/* 去除轮廓线 */
outline: none;
}
/* 对 a 元素及其处于获得焦点focus和鼠标悬停hover状态时设置样式 */
a,
a:focus,
a:hover {
/* 设置鼠标指针样式为指针 */
cursor: pointer;
/* 使链接文本颜色继承自父元素 */
color: inherit;
/* 去除链接的下划线 */
text-decoration: none;
}
/* 对获得焦点的 div 元素设置样式 */
div:focus {
/* 去除轮廓线 */
outline: none;
}
/* 定义一个名为 clearfix 的类选择器,用于清除浮动,通过伪元素:after 实现 */
.clearfix {
&:after {
/* 使伪元素不可见 */
visibility: hidden;
/* 设置伪元素的显示方式为块级元素 */
display: block;
/* 设置伪元素的字体大小为 0 */
font-size: 0;
/* 设置伪元素的内容为空字符串 */
content: ' ';
/* 清除浮动 */
clear: both;
/* 设置伪元素的高度为 0 */
height: 0;
}
}
/* 选择 id 为 driver-popover-item 的 div 元素内的.driver-popover-title 元素,设置其文本颜色 */
div#driver-popover-item.driver-popover-title {
div#driver-popover-item .driver-popover-title {
color: #1890ff;
}
/* 选择 id 为 driver-popover-item 的 div 元素内的.driver-popover-footer 元素内的.driver-next-btn 元素,设置其样式 */
div#driver-popover-item.driver-popover-footer.driver-next-btn {
/* 设置背景颜色 */
div#driver-popover-item .driver-popover-footer .driver-next-btn {
background-color: #1890ff;
/* 设置文本颜色为白色 */
color: white;
/* 去除文本阴影 */
text-shadow: none;
/* 设置元素的边框圆角为 4 像素 */
border-radius: 4px;
}

@ -1,221 +1,144 @@
//
.main-container {
//
width: calc(100% - $sideBarWidth);
//
height: 100%;
//
position: fixed;
top: 0;
right: 0;
// z-index 9
z-index: 9;
// 0.28
transition: all 0.28s;
}
//
//
.sidebar-container {
// 0.3
transition: all 0.3s;
// !important
width: $sideBarWidth !important;
//
height: 100%;
//
position: fixed;
top: 0;
bottom: 0;
left: 0;
// z-index 1001
z-index: 1001;
// 使 $menuBg
background-color: $menuBg;
//
.scrollbar-wrapper {
// !important
overflow-x: hidden !important;
}
//
.el-scrollbar__bar.is-vertical {
//
right: 0;
}
//
.el-scrollbar {
// 92px
height: calc(100% - 92px);
}
// logo
&.has-logo {
// PC
.el-scrollbar.pc {
/* logo: 48px、leftCollapse: 40px、leftCollapse-shadow: 4px */
// 92px
height: calc(100% - 92px);
}
//
.el-scrollbar.mobile {
//
height: 100%;
}
}
//
.is-horizontal {
//
display: none;
}
//
a {
//
display: inline-block;
display: flex;
// 10px
padding-left: 10px;
//
flex-wrap: wrap;
// 100%
width: 100%;
}
// Element UI
.el-menu {
//
border: none;
//
height: 100%;
// !important
background-color: transparent !important;
}
//
.el-menu-item,
.el-sub-menu__title {
// 50px
height: 50px;
// 使 $menuText
color: $menuText;
// !important
background-color: transparent !important;
// 18px!important
padding-left: 18px !important;
//
&:hover {
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
.svg-icon {
// 使 $menuActiveText
color: $menuActiveText;
// 0.3
transition: color 0.3s;
}
}
//
.svg-icon {
// 使 $menuText
color: $menuText;
// 0.3
transition: color 0.3s;
}
// div span
div,
span {
// 50px
height: 50px;
// 50px
line-height: 50px;
//
overflow: hidden;
//
text-overflow: ellipsis;
}
//
.svg-icon {
// 1em
min-width: 1em;
// 5px
margin-right: 5px;
}
}
//
.submenu-title-noDropdown,
.el-sub-menu__title {
&:hover {
//
background-color: transparent;
}
}
//
//
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
i {
// 使 $menuActiveText!important
color: $menuActiveText !important;
}
}
//
.is-active {
// 0.3
transition: color 0.3s;
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
.svg-icon {
// 使 $menuActiveText
color: $menuActiveText;
// 0.3
transition: color 0.3s;
}
}
//
.el-menu .el-sub-menu .el-menu-item {
// 12px
font-size: 12px;
// 100px!important
min-width: 100px !important;
// 使 $subMenuBg!important
background-color: $subMenuBg !important;
//
&.is-active {
// 使 $menuActiveBg!important
background: $menuActiveBg !important;
// 使 $menuActiveText!important
color: $menuActiveText !important;
}
}
//
.el-menu .el-menu-item {
//
.el-menu-tooltip__trigger {
// 18px
padding: 18px;
}
//
&.is-active {
// 使 $menuActiveBg!important
background: $menuActiveBg !important;
}
}
@ -223,224 +146,153 @@
//
.el-menu--collapse {
//
width: $hideSideBarWidth;
}
//
.hideSidebar {
//
//
.sidebar-container {
// 0.3
transition: width 0.3s;
// !important
width: $hideSideBarWidth !important;
//
.el-sub-menu {
//
&.is-active {
// 0.28
transition: all 0.28s;
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
position: relative;
//
&::after {
//
content: '';
// 50px
height: 50px;
// 2px
left: 2px;
//
position: absolute;
// 0
top: 0;
// 0.28 !important
transition-delay: 0.28s !important;
// 2px
width: 2px;
// !important
background-color: var(--el-color-primary) !important;
// 1
opacity: 1;
}
//
.svg-icon {
// 使 $menuActiveText
color: $menuActiveText;
// 0.3
transition: color 0.3s;
}
}
}
//
//
.el-sub-menu__title {
// 18px
padding: 18px;
}
//
//
.el-menu-item {
//
.el-menu-tooltip__trigger {
// 18px
padding: 18px;
}
}
}
//
//
.el-menu--vertical {
// !important
width: $hideSideBarWidth !important;
// 0.3
transition: width 0.3s;
}
//
//
.main-container {
//
width: calc(100% - $hideSideBarWidth);
}
}
//
//
.el-menu--vertical {
// !important
width: $sideBarWidth !important;
// 0.3
transition: width 0.3s;
/* 子菜单中还有子菜单 */
//
.el-menu .el-sub-menu__title {
// 12px
font-size: 12px;
// 使 $subMenuBg!important
background-color: $subMenuBg !important;
}
}
//
//
.el-menu--popup-container {
//
.el-menu {
// 使 $subMenuBg!important
background-color: $subMenuBg !important;
}
//
.el-menu-item,
.el-sub-menu__title {
// 50px
height: 50px;
// 使 $menuText
color: $menuText;
// !important
background-color: transparent !important;
//
&:hover {
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
.svg-icon {
// 使 $menuActiveText
color: $menuActiveText;
// 0.3
transition: color 0.3s;
}
}
//
.svg-icon {
// 使 $menuText
color: $menuText;
// 0.3
transition: color 0.3s;
}
// div span
div,
span {
// 50px
height: 50px;
// 50px
line-height: 50px;
//
overflow: hidden;
//
text-overflow: ellipsis;
}
}
//
.submenu-title-noDropdown,
.el-sub-menu__title {
&:hover {
//
background-color: transparent;
}
}
//
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
// 使 $menuActiveText!important
color: $menuActiveText !important;
//
i {
// 使 $menuActiveText!important
color: $menuActiveText !important;
}
}
//
.el-menu .el-menu-item {
// 12px!important
font-size: 12px !important;
// 100px!important
min-width: 100px !important;
// 使 $subMenuBg!important
background-color: $subMenuBg !important;
//
&.is-active {
// 使 $menuHover!important
background: $menuHover !important;
}
}
//
.el-menu .el-menu-item {
&.is-active {
// 使 $menuHover!important
background: $menuHover !important;
}
}
}
// bug
// bug
.is-active {
//
&::after {
//
content: '';
// 1!important
opacity: 1 !important;
}
//
.menu-icon {
// !important
transition: none !important;
// !important
color: #fff !important;
}
}

@ -1,19 +1,15 @@
/* 定义一个名为.large-card-font 的类选择器,用于设置卡片上数字的样式 */
//
.large-card-font {
/* 使用 @apply 指令,应用其他样式类的样式,这里应用了 font-semibold半粗体字体和 text-2xl字体大小为 2 倍大)这两个样式类 */
@apply font-semibold text-2xl;
/* 设置文本颜色为 RGB 值为 (41, 137, 255) 的颜色 */
color: rgb(41, 137, 255);
}
/* 定义一个名为.text-main 的类选择器,用于设置文本的主要颜色 */
//
.text-main {
/* 设置文本颜色为十六进制颜色值 #cecece */
color: #cecece;
}
/* 定义一个名为.border-main 的类选择器,用于设置默认的边框颜色和样式 */
//
.border-main {
/* 设置边框为 1 像素宽的实线,颜色为十六进制颜色值 #cfcfcf */
border: #cfcfcf solid 1px;
}

@ -1,43 +1,31 @@
/* 定义面包屑进入和离开时的活跃状态样式,设置过渡效果 */
//
.breadcrumb-enter-active,
.breadcrumb-leave-active {
/* 所有属性的过渡效果,持续时间为 0.5 秒 */
transition: all 0.5s;
}
/* 定义面包屑进入前的状态和离开时的活跃状态(这里似乎重复定义了离开活跃状态,可能存在错误)的样式 */
.breadcrumb-enter-from,
.breadcrumb-leave-active {
/* 透明度设置为 0 */
opacity: 0;
/* 水平方向平移 20 像素 */
transform: translateX(20px);
}
/* 再次定义面包屑离开时的活跃状态样式,设置为绝对定位 */
.breadcrumb-leave-active {
position: absolute;
}
/* 定义页面切换时的过渡动画相关类的样式,设置进入和离开时的活跃状态的过渡效果 */
/* 页面切换过渡动画 */
.fade-transform-leave-active,
.fade-transform-enter-active {
/* 所有属性的过渡效果,持续时间为 0.28 秒 */
transition: all 0.28s;
}
/* 定义页面切换时进入前的状态样式 */
.fade-transform-enter-from {
/* 透明度设置为 0 */
opacity: 0;
/* 水平向左平移 30 像素 */
transform: translateX(-30px);
}
/* 定义页面切换时离开到的状态样式 */
.fade-transform-leave-to {
/* 透明度设置为 0 */
opacity: 0;
/* 水平向右平移 30 像素 */
transform: translateX(30px);
}

@ -1,43 +1,24 @@
//
// #fefefea6
// sidebar
$menuText: #fefefea6;
//
$menuActiveText: #fff;
// #031429
$menuBg: #031429;
// #558df6
$menuActiveBg: #558df6;
// #558df6
$menuHover: #558df6;
// #0e0303
$subMenuBg: #0e0303;
// #00061a
$subHideMenuBg: #00061a;
// 210
$sideBarWidth: 210px;
// 54
$hideSideBarWidth: 54px;
// 使 :export 便 JavaScript 使
:export {
// $menuText menuText
menuText: $menuText;
// $menuActiveText menuActiveText
menuActiveText: $menuActiveText;
// $menuBg menuBg
menuBg: $menuBg;
// $menuHover menuHover
menuHover: $menuHover;
// $subMenuBg subMenuBg
subMenuBg: $subMenuBg;
// $subHideMenuBg subHideMenuBg
subHideMenuBg: $subHideMenuBg;
// $sideBarWidth sideBarWidth
sideBarWidth: $sideBarWidth;
// $hideSideBarWidth hideSideBarWidth
hideSideBarWidth: $hideSideBarWidth;
}

@ -1,25 +1,12 @@
// 定义一个接口 IVariables用于描述包含侧边栏样式相关变量的对象结构
export interface IVariables {
// 菜单文本的颜色,类型为字符串
menuText: string
// 菜单激活时文本的颜色,类型为字符串
menuActiveText: string
// 菜单的背景颜色,类型为字符串
menuBg: string
// 菜单鼠标悬停时的背景颜色,类型为字符串
menuHover: string
// 子菜单的背景颜色,类型为字符串
subMenuBg: string
// 隐藏子菜单的背景颜色,类型为字符串
subHideMenuBg: string
// 侧边栏展开时的宽度,类型为字符串
sideBarWidth: string
// 侧边栏折叠时的宽度,类型为字符串
hideSideBarWidth: string
}
// 声明一个名为 styles 的变量,其类型为 IVariables但未初始化
export const styles: IVariables
// 默认导出 styles 变量,但由于未初始化,可能在使用时需要注意
export default styles

@ -1,23 +1,11 @@
/** 文件类型 */
// 声明一个模块,用于处理.svg 结尾的文件,这样在 TypeScript 中就可以导入.svg 文件而不会报错,
// 但这里只是简单声明,没有定义具体的类型,意味着导入该类型文件时会被视为 any 类型
declare module '*.svg'
// 声明用于处理.png 结尾的文件的模块
declare module '*.png'
// 声明用于处理.jpg 结尾的文件的模块
declare module '*.jpg'
// 声明用于处理.jpeg 结尾的文件的模块
declare module '*.jpeg'
// 声明用于处理.gif 结尾的文件的模块
declare module '*.gif'
// 声明用于处理.bmp 结尾的文件的模块
declare module '*.bmp'
// 声明用于处理.tiff 结尾的文件的模块
declare module '*.tiff'
// 声明用于处理.yaml 结尾的文件的模块
declare module '*.yaml'
// 声明用于处理.json 结尾的文件的模块
declare module '*.json'
// 声明用于处理 vue-count-to 模块,可能是为了在项目中使用 vue-count-to 这个 Vue 插件时,
// 让 TypeScript 知道它的存在,即使没有具体的类型定义,也能正常导入和使用(类型为 any
declare module 'vue-count-to'

@ -1,17 +1,12 @@
// 从 'vuex' 库中导入 Store 和 Module 类型
// vuex.d.ts
import { Store, Module } from 'vuex'
// 从 './store/types' 文件中导入 IStoreType 类型,这个类型应该定义了 Vuex 存储的状态结构
import { type IStoreType } from './store/types'
// 模块扩展,用于在 Vue 运行时核心模块中添加自定义类型声明
// 这样做可以让 TypeScript 知道在 Vue 组件中 this.$store 的具体类型
// 模块扩展
// 模板内$store强类型支持
declare module '@vue/runtime-core' {
// 为 `this.$store` 提供类型声明
// ComponentCustomProperties 是 Vue 中用于扩展组件自定义属性的接口
interface ComponentCustomProperties {
// 声明 $store 属性,其类型为 Store<IStoreType>
// Store 是 Vuex 中的存储类IStoreType 是之前导入的状态类型
// 这意味着在 Vue 组件中使用 this.$store 时TypeScript 会进行类型检查,确保操作符合 IStoreType 的定义
$store: Store<IStoreType>
}
}

@ -1,47 +1,46 @@
// 导出一个函数initArray用于初始化数组
// 如果传入的array存在则返回array否则返回一个空数组
// TODO 初始化Array
export const initArray = (array: any) => {
return array? array : [];
return array ? array : [];
};
// 导出一个函数arrayPushAllByFiled用于将一个数组中某个字段的所有值添加到另一个数组
// TODO 将一个Array的某个字段所有的值全部添加到了一个Array
export const arrayPushAllByFiled = (dataArray: any, pushArray: any, field: any) => {
// 初始化dataArray和pushArray
// 初始化
dataArray = initArray(dataArray);
pushArray = initArray(pushArray);
// 法一使用for...of循环遍历dataArray将每个元素的指定字段值添加到pushArray中
// 法一
// for (const item of dataArray) {
// pushArray.push(item[field]);
// }
// return pushArray;
// 法二使用map方法遍历dataArray返回一个包含所有指定字段值的新数组
// 法二
return dataArray.map((item: any) => item[field]);
};
// 导出一个函数arrayPushAllByObj用于将一个数组的数据全部添加到另一个数组
// TODO 将一个Array的数据全部添加到了一个Array
export const arrayPushAllByObj = (dataArray: any, pushArray: any) => {
// 初始化dataArray和pushArray
// 初始化
dataArray = initArray(dataArray);
pushArray = initArray(pushArray);
// 使用展开运算符将dataArray的所有元素添加到pushArray中
// push
pushArray.push(...dataArray);
return pushArray;
};
// 导出一个函数arrayDeduplicationByFiled用于根据指定字段对数组进行去重
// TODO Array根据字段去重
export const arrayDeduplicationByFiled = (array: any, field: string) => {
// 初始化array
// 初始化
array = initArray(array);
// 去重 法一:使用Set和map方法对指定字段进行去重返回一个包含去重后字段值的新数组
// 去重 法一:该方法对编号进行去重返回的是[1,3,5]的编号数组
// const idArray = [...new Set(array.map((item: any) => item[field]))];
// 再使用for循环依次取出id对应数据即可
// 去重 法二使用reduce方法遍历数组检查当前对象的指定字段是否已存在于新数组中不存在则添加
// 去重 法二
return array.reduce((newArray: any, thisObj: any) => {
// 检查当前对象的属性是否已经存在于新数组中
const exists = newArray.some((item: any) => thisObj[field] === item[field]);
@ -53,16 +52,16 @@ export const arrayDeduplicationByFiled = (array: any, field: string) => {
}, []);
};
// 导出一个函数arrayDeduplicationByObj用于根据对象对数组进行去重适用于非对象数组
// TODO Array根据对象去重(适用于非对象数组)
export const arrayDeduplicationByObj = (array: any) => {
// 初始化array
// 初始化
array = initArray(array);
// 去重 法一:使用Set和map方法对数组元素进行去重返回一个包含去重后元素的新数组
// 去重 法一:该方法对编号进行去重返回的是[1,3,5]的编号数组
// const idArray = [...new Set(array.map((item: any) => item))];
// 再使用for循环依次取出id对应数据即可
// 去重 法二使用reduce方法遍历数组检查当前对象是否已存在于新数组中不存在则添加
// 去重 法二
return array.reduce((newArray: any, thisObj: any) => {
// 检查当前对象的属性是否已经存在于新数组中
const exists = newArray.some((item: any) => thisObj === item);

@ -1,4 +1,4 @@
// 从 @/utils/is 模块中导入多个用于验证的函数
// 电话规则
import {
isNotEmail,
isNotIdNum,
@ -7,58 +7,43 @@ import {
isNotNumber
} from "@/utils/is";
// 电话规则验证函数
// 电话规则
export function phoneRule(rule: any, value: any, callback: any, field: string) {
// 去除输入值的首尾空格
const trim = value?.trim();
// 如果输入值为空
if (!trim) {
// 调用回调函数并传递错误信息,提示电话不能为空
callback(new Error(field + "电话不能为空"));
} else if (isNotPhone(trim)) {
// 如果输入值不是有效的电话号码格式
callback(new Error(field + "电话格式有误"));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
// 邮箱规则验证函数
// 邮箱规则
export function emailRule(rule: any, value: any, callback: any, field: string) {
// 去除输入值的首尾空格
const trim = value?.trim();
// 如果输入值为空
if (!trim) {
// 调用回调函数并传递错误信息,提示邮箱不能为空
callback(new Error(field + "邮箱不能为空"));
} else if (isNotEmail(trim)) {
// 如果输入值不是有效的邮箱格式
callback(new Error(field + "邮箱格式有误"));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
// 身份证号规则验证函数
// 身份证号规则
export function idNumRule(rule: any, value: any, callback: any, field: string) {
// 去除输入值的首尾空格
const trim = value?.trim();
// 如果输入值为空
if (!trim) {
// 调用回调函数并传递错误信息,提示身份证号不能为空
callback(new Error(field + "身份证号不能为空"));
} else if (isNotIdNum(trim)) {
// 如果输入值不是有效的身份证号格式
callback(new Error(field + "身份证号格式有误"));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
// 字符串规则验证函数
// 字符串规则
export function stringRule(
rule: any,
value: any,
@ -67,22 +52,17 @@ export function stringRule(
mixLen: number,
maxLen: number
) {
// 去除输入值的首尾空格
const trim = value?.trim();
// 如果输入值为空
if (!trim) {
// 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else if (trim.length < mixLen || trim.length > maxLen) {
// 如果输入值的长度不在指定范围内
callback(new Error(field + "长度应为" + mixLen + "~" + maxLen));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
// 数字(整数/小数)规则验证函数
// 数字(整数/小数)规则
export function numberRule(
rule: any,
value: any,
@ -91,27 +71,21 @@ export function numberRule(
mix: number,
max: number
) {
// 如果输入值为空
if (!value) {
// 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else {
// 将输入值转换为字符串并去除首尾空格
const trim = value.toString()?.trim();
// 如果输入值不是有效的数字格式
if (isNotNumber(trim)) {
callback(new Error(field + "格式有误"));
} else if (trim < mix || trim > max) {
// 如果输入值不在指定的数字范围内
callback(new Error(field + "应该在" + mix + "~" + max + "之间"));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
}
// 整数规则验证函数
// 整数规则
export function integerRule(
rule: any,
value: any,
@ -120,32 +94,24 @@ export function integerRule(
mix: number,
max: number
) {
// 如果输入值为空
if (!value) {
// 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else {
// 将输入值转换为字符串并去除首尾空格
const trim = value.toString()?.trim();
// 如果输入值不是有效的整数格式
if (isNotInteger(trim)) {
callback(new Error(field + "格式有误"));
} else if (trim < mix || trim > max) {
// 如果输入值不在指定的整数范围内
callback(new Error(field + "应该在" + mix + "~" + max + "之间"));
} else {
// 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
}
// 日期规则验证函数,禁用当前时间之前的日期
// 日期规则
export const disabledNowBeforeDate = (time: Date) => {
return time.getTime() < Date.now();
};
// 日期规则验证函数,禁用当前时间之后的日期
export const disabledNowAfterDate = (time: Date) => {
return time.getTime() > Date.now();
};

@ -1,52 +1,35 @@
// 从 '@/store' 导入 Vuex 的 store 实例
import store from "@/store";
// 导入 axios 库,并解构出 AxiosRequestConfig 和 AxiosResponse 类型
import baseAxios, { AxiosRequestConfig, AxiosResponse } from "axios";
// 从 'element-plus' 导入 ElMessage 用于显示消息提示
import { ElMessage } from "element-plus";
// 定义基础 URL
export const baseUrl = "http://127.0.0.1:9001/";
// 创建一个 axios 实例,设置基础 URL、超时时间和默认 headers
const axios = baseAxios.create({
baseURL: "", // 这里可以根据实际情况设置基础 URL如果为空则使用全局的 baseUrl
timeout: 5000, // 设置请求超时时间为 5000 毫秒
headers: {} // 可以在这里设置默认的请求头
baseURL: "",
timeout: 5000,
headers: {}
});
// 请求拦截器,在请求发送前会被调用
// 请求拦截器
axios.interceptors.request.use((config: any) => {
// 从 localStorage 中获取名为 "stateData" 的数据,并解析为 JSON 对象
// 然后尝试获取其中的 app.token 作为令牌
const token = JSON.parse(localStorage.getItem("stateData")!)?.app?.token;
// 将令牌设置到请求头的 "token" 字段中
config.headers.token = token;
// 返回配置好的请求对象
return config;
});
// 响应拦截器,在接收到响应后会被调用
// 响应拦截器
axios.interceptors.response.use(
(res: AxiosResponse) => {
// 如果响应数据中的 code 为 500 且 msg 为 "令牌无效"
if (res.data.code === 500 && res.data.msg === "令牌无效") {
// 调用 store 的 app/logout 方法进行登出操作
store.dispatch("app/logout");
// 显示错误消息提示 "登录过期,请重新登录"
ElMessage.error({ message: "登录过期,请重新登录" });
}
// 如果响应数据中的 err 为 1
if (res.data.err === 1) {
// 则返回一个被拒绝的 Promise携带响应数据
return Promise.reject(res.data);
}
// 返回响应数据
return res.data;
},
// 如果响应出现错误,返回一个被拒绝的 Promise携带错误信息
err => Promise.reject(err)
err => Promise.reject(err) // 响应出问题
);
// 默认导出创建好的 axios 实例
export default axios;

@ -1,7 +1,3 @@
// 从 './http' 文件中导入名为 http 的模块
// 这里假设 './http' 文件中导出了一个名为 http 的对象,这个对象可能是封装好的 HTTP 请求工具,例如使用 axios 封装的请求实例
import http from './http'
// 导出导入的 http 对象
// 这样其他文件就可以通过导入这个文件来使用 http 对象进行 HTTP 请求操作
export { http }

@ -1,277 +1,174 @@
// 获取 Object.prototype.toString 方法的引用,用于后续类型判断
const toString = Object.prototype.toString;
// 定义一个正则表达式,用于校验保留两位小数的实数
// 支持正负号,整数部分可以是 0 或者以 1 - 9 开头的数字串,小数部分可以有 1 到 2 位
const REGEXP_NUMBER = /^[+-]?(0|([1-9]\d*))(\.\d{1,2})?$/;
// 定义一个正则表达式,用于校验邮箱格式
// 要求邮箱由字母、数字组成,中间有 @ 符号,并且有正确的域名和顶级域名
const REGEXP_EMAIL = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;
// 定义一个正则表达式,用于校验手机号格式
// 要求手机号以 1 开头,第二位是 3 - 9 中的一个数字,后面跟着 9 位数字
const REGEXP_PHONE = /^1[3456789]\d{9}$/;
// 定义一个正则表达式,用于校验身份证号格式
// 符合中国 18 位身份证号码的格式规则
const toString = Object.prototype.toString
// 保留两位小数的实数校验规则
const REGEXP_NUMBER = /^[+-]?(0|([1-9]\d*))(\.\d{1,2})?$/
// 密码校验规则
const REGEXP_EMAIL = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/
// 手机号校验规则
const REGEXP_PHONE = /^1[3456789]\d{9}$/
// 身份证号校验规则
const REGEXP_ID_NUM =
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
/**
* @description: /
* @param {string} account -
* @returns {boolean} - true false
*/
export function isNotAccount(account: string) {
// 使用正则表达式检查账号是否既不是手机号也不是邮箱
return !REGEXP_PHONE.test(account) && !REGEXP_EMAIL.test(account);
return !REGEXP_PHONE.test(account) && !REGEXP_EMAIL.test(account)
}
/**
* @description:
* @param {string} phone -
* @returns {boolean} - true false
*/
export function isNotPhone(phone: string) {
// 使用正则表达式检查是否不是手机号
return !REGEXP_PHONE.test(phone);
return !REGEXP_PHONE.test(phone)
}
/**
* @description:
* @param {string} email -
* @returns {boolean} - true false
*/
export function isNotEmail(email: string) {
// 使用正则表达式检查是否不是邮箱
return !REGEXP_EMAIL.test(email);
return !REGEXP_EMAIL.test(email)
}
/**
* @description:
* @param {string} idNum -
* @returns {boolean} - true false
*/
export function isNotIdNum(idNum: string) {
// 使用正则表达式检查是否不是身份证号
return !REGEXP_ID_NUM.test(idNum);
return !REGEXP_ID_NUM.test(idNum)
}
/**
* @description:
* @param {string} num -
* @returns {boolean} - true false
*/
export function isNotNumber(num: string) {
// 使用正则表达式检查是否不是符合规则的数字
return !REGEXP_NUMBER.test(num);
return !REGEXP_NUMBER.test(num)
}
/**
* @description:
* @param {number} num -
* @returns {boolean} - true false
*/
export function isNotInteger(num: number) {
// 使用 Number.isInteger 方法检查是否不是整数
return !Number.isInteger(Number(num));
return !Number.isInteger(Number(num))
}
/**
* @description:
* @param {unknown} val -
* @param {string} type -
* @returns {boolean} - true false
* @description:
*/
export function is(val: unknown, type: string) {
// 使用 toString 方法获取值的类型字符串,并与指定类型比较
return toString.call(val) === `[object ${type}]`;
return toString.call(val) === `[object ${type}]`
}
/**
* @description:
* @param {unknown} val -
* @returns {val is T} - true false
* @description:
*/
export function isFunction<T = () => void>(val: unknown): val is T {
// 调用 is 函数判断是否为 Function 类型
return is(val, 'Function');
return is(val, 'Function')
}
/**
* @description:
* @param {T} val -
* @returns {val is T} - undefined true false
*/
export const isDef = <T = unknown>(val?: T): val is T => {
// 使用 typeof 检查值是否不是 undefined
return typeof val !== 'undefined';
return typeof val !== 'undefined'
}
/**
* @description:
* @param {T} val -
* @returns {val is T} - undefined true false
*/
export const isUnDef = <T = unknown>(val?: T): val is T => {
// 调用 isDef 函数取反判断是否未定义
return !isDef(val);
return !isDef(val)
}
/**
* @description:
* @param {any} val -
* @returns {val is Record<any, any>} - null true false
*/
export const isObject = (val: any): val is Record<any, any> => {
// 检查值不为 null 且是 Object 类型
return val !== null && is(val, 'Object');
return val !== null && is(val, 'Object')
}
/**
* @description:
* @param {unknown} val -
* @returns {val is Date} - Date true false
* @description:
*/
export function isDate(val: unknown): val is Date {
// 调用 is 函数判断是否为 Date 类型
return is(val, 'Date');
return is(val, 'Date')
}
/**
* @description:
* @param {unknown} val -
* @returns {val is number} - Number true false
* @description:
*/
export function isNumber(val: unknown): val is number {
// 调用 is 函数判断是否为 Number 类型
return is(val, 'Number');
return is(val, 'Number')
}
/**
* @description: AsyncFunction
* @param {unknown} val -
* @returns {val is Promise<T>} - AsyncFunction true false
*
* @description: AsyncFunction
*/
export function isAsyncFunction<T = any>(val: unknown): val is Promise<T> {
// 调用 is 函数判断是否为 AsyncFunction 类型
return is(val, 'AsyncFunction');
return is(val, 'AsyncFunction')
}
/**
* @description: promise
* @param {unknown} val -
* @returns {val is Promise<T>} - Promise true false
* @description: promise
*/
export function isPromise<T = any>(val: unknown): val is Promise<T> {
// 检查值是 Promise 类型,是对象,且有 then 和 catch 方法
return (
is(val, 'Promise') &&
isObject(val) &&
isFunction(val.then) &&
isFunction(val.catch)
);
)
}
/**
* @description:
* @param {unknown} val -
* @returns {val is string} - String true false
* @description:
*/
export function isString(val: unknown): val is string {
// 调用 is 函数判断是否为 String 类型
return is(val, 'String');
return is(val, 'String')
}
/**
* @description: boolean
* @param {unknown} val -
* @returns {val is boolean} - Boolean true false
* @description: boolean
*/
export function isBoolean(val: unknown): val is boolean {
// 调用 is 函数判断是否为 Boolean 类型
return is(val, 'Boolean');
return is(val, 'Boolean')
}
/**
* @description:
* @param {any} val -
* @returns {val is Array<any>} - true false
* @description:
*/
export function isArray(val: any): val is Array<any> {
// 检查值存在且是数组
return val && Array.isArray(val);
return val && Array.isArray(val)
}
/**
* @description:
* @returns {boolean} - window true false
*/
export const isClient = () => {
// 检查 window 对象是否已定义
return typeof window !== 'undefined';
return typeof window !== 'undefined'
}
/**
* @description:
* @param {any} val -
* @returns {val is Window} - window true false
*/
export const isWindow = (val: any): val is Window => {
// 检查 window 对象已定义且值是 Window 类型
return typeof window !== 'undefined' && is(val, 'Window');
return typeof window !== 'undefined' && is(val, 'Window')
}
/**
* @description:
* @param {unknown} val -
* @returns {val is Element} - DOM true false
*/
export const isElement = (val: unknown): val is Element => {
// 检查值是对象且有 tagName 属性
return isObject(val) && !!val.tagName;
return isObject(val) && !!val.tagName
}
/**
* @description:
* @type {boolean} - window true false
*/
export const isServer = typeof window === 'undefined';
export const isServer = typeof window === 'undefined'
/**
* @description:
* @param {Element} o - DOM
* @returns {boolean} - true false
*/
// 是否为图片节点
export function isImageDom(o: Element) {
// 检查元素存在且标签名是 IMAGE 或 IMG
return o && ['IMAGE', 'IMG'].includes(o.tagName);
return o && ['IMAGE', 'IMG'].includes(o.tagName)
}
/**
* @description: null
* @param {unknown} val -
* @returns {val is null} - null true false
*/
export function isNull(val: unknown): val is null {
// 检查值是否等于 null
return val === null;
return val === null
}
/**
* @description: null undefined
* @param {unknown} val -
* @returns {val is null | undefined} - null undefined true false
*/
export function isNullAndUnDef(val: unknown): val is null | undefined {
// 调用 isUnDef 和 isNull 函数判断
return isUnDef(val) && isNull(val);
return isUnDef(val) && isNull(val)
}
/**
* @description: null undefined
* @param {unknown} val -
* @returns {val is null | undefined} - null undefined true false
*/
export function isNullOrUnDef(val: unknown): val is null | undefined {
// 调用 isUnDef 和 isNull 函数取或判断
return isUnDef(val) || isNull(val);
return isUnDef(val) || isNull(val)
}

@ -1,55 +1,37 @@
// 从 './is' 文件中导入 isArray 函数,用于判断一个值是否为数组
import { isArray } from './is'
// 定义一个函数 formatValue用于格式化传入的值
export function formatValue(callValue: any) {
// 如果传入的值是数组,使用 '/' 拼接数组元素(如果数组有元素),否则返回 '--'
if (isArray(callValue)) return callValue.length? callValue.join(' / ') : '--'
// 如果传入的值不是数组,直接返回该值,如果值为 null 或 undefined则返回 '--'
return callValue?? '--'
// 如果当前值为数组,使用 / 拼接(根据需求自定义)
if (isArray(callValue)) return callValue.length ? callValue.join(' / ') : '--'
return callValue ?? '--'
}
// 定义一个函数 handleRowAccordingToProp根据属性路径处理行数据
export function handleRowAccordingToProp(
row: { [key: string]: any }, // 表示一个对象,键为字符串类型,值为任意类型
prop: string // 表示属性路径字符串
row: { [key: string]: any },
prop: string
) {
// 如果属性路径中不包含 '.',直接返回行数据中该属性的值,如果值为 null 或 undefined则返回 '--'
if (!prop.includes('.')) return row[prop]?? '--'
// 如果属性路径中包含 '.',按 '.' 分割属性路径,依次获取嵌套对象的属性值
prop.split('.').forEach(item => (row = row[item]?? '--'))
// 返回最终获取到的值
if (!prop.includes('.')) return row[prop] ?? '--'
prop.split('.').forEach(item => (row = row[item] ?? '--'))
return row
}
// 定义一个函数 handleProp处理属性路径字符串
export function handleProp(prop: string) {
// 按 '.' 分割属性路径字符串,得到一个数组
const propArr = prop.split('.')
// 如果分割后的数组长度为 1说明属性路径没有嵌套直接返回原属性路径字符串
if (propArr.length == 1) return prop
// 如果数组长度大于 1返回属性路径字符串中最后一个部分
return propArr[propArr.length - 1]
}
// 定义一个函数 filterEnum根据枚举数据过滤并格式化值
export function filterEnum(
callValue: any, // 要过滤的值
enumData: any[] | undefined, // 枚举数据数组或 undefined
fieldNames?: { label: string; value: string }, // 可选的字段名称配置对象,默认为 { label: 'label', value: 'value' }
type?: 'tag' // 可选的类型,默认为 undefined
callValue: any,
enumData: any[] | undefined,
fieldNames?: { label: string; value: string },
type?: 'tag'
): string {
// 获取字段名称配置中的 'value' 字段名,如果未提供则默认为 'value'
const value = fieldNames?.value?? 'value'
// 获取字段名称配置中的 'label' 字段名,如果未提供则默认为 'label'
const label = fieldNames?.label?? 'label'
// 定义一个空对象,用于存储过滤后的数据
const value = fieldNames?.value ?? 'value'
const label = fieldNames?.label ?? 'label'
let filterData: { [key: string]: any } = {}
// 如果枚举数据是一个数组,查找与传入值匹配的枚举项
if (Array.isArray(enumData))
filterData = enumData.find((item: any) => item[value] === callValue)
// 如果类型为 'tag',返回过滤数据中的 'tagType' 字段值,如果不存在则返回空字符串
if (type == 'tag') return filterData?.tagType? filterData.tagType : ''
// 返回过滤数据中的 'label' 字段值,如果过滤数据不存在则返回 '--'
return filterData? filterData[label] : '--'
if (type == 'tag') return filterData?.tagType ? filterData.tagType : ''
return filterData ? filterData[label] : '--'
}

@ -1,18 +1,9 @@
<template>
<!-- 定义一个顶级的 div 元素作为组件的根元素用于包裹其他内容 -->
<div>
<!-- 定义一个 h1 标题元素显示文本 "activity" -->
<h1>activity</h1>
</div>
</template>
<script setup lang="ts">
// 使 <script setup> Vue 3
// lang="ts" 使 TypeScript
</script>
<script setup lang="ts"></script>
<style lang="scss" scoped>
// lang="scss" 使 SCSSSass
// scoped
//
</style>
<style lang="scss" scoped></style>

@ -1,22 +1,7 @@
<template>
<!-- router-view Vue Router 中的一个组件它是一个占位符
在使用 Vue Router 构建单页面应用时当定义了不同的路由路径和对应的组件后
当某个路由被匹配时与之对应的组件就会被渲染到 <router-view> 所在的位置
简单来说它起到了显示当前路由所对应的组件内容的作用 -->
<router-view></router-view>
</template>
<script setup lang="ts">
// 使 Vue 3 <script setup> .vue使 API
// lang="ts" 使 TypeScript
//
//
</script>
<script setup lang="ts"></script>
<style lang="scss" scoped>
// lang="scss" 使 SCSSSassy CSS
// SCSS CSS 使
// scoped Vue
//
//
</style>
<style lang="scss" scoped></style>

@ -1,88 +1,66 @@
<template>
<div>
<!-- Element Plus 的对话框组件 -->
<el-dialog
style="width: 70%;"
<!-- 使用 v-model 绑定对话框的显示状态dialogVisible 是一个响应式引用 -->
v-model="dialogVisible"
<!-- 动态绑定对话框的标题 drawerProps.title 获取 -->
:title="drawerProps.title"
<!-- 在对话框关闭时销毁对话框实例 -->
destroy-on-close
style="width: 70%"
v-model="dialogVisible"
:title="drawerProps.title"
destroy-on-close
>
<div>
<!-- Element Plus 的表单组件 -->
<el-form
<!-- 绑定表单的数据模型formData 是一个响应式引用 -->
:model="formData"
class="login-form"
<!-- 为表单添加引用方便在脚本中操作ruleFormRef 是一个响应式引用 -->
ref="ruleFormRef"
<!-- 绑定表单的验证规则rules 是一个响应式对象 -->
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为床位名称:绑定的属性为name -->
<el-form-item label="床位名称:" prop="name">
<!-- Element Plus 的输入框组件双向绑定 formData.name 的值可清除输入内容 -->
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
<div>
<el-form
:model="formData"
class="login-form"
ref="ruleFormRef"
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<el-form-item label="床位名称:" prop="name">
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<!-- drawerProps.isView false 显示对话框的页脚模板 -->
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<!-- 取消按钮点击时关闭对话框 -->
<el-button @click="dialogVisible = false">取消</el-button>
<!-- 提交按钮带有蓝色背景类类型为主要按钮点击时调用 handleSubmit 方法 -->
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
// Vue reactiverefwatch
import { reactive, ref, watch } from "vue";
// element-plus ElMessageFormInstanceFormRules
import { ElMessage, FormInstance, FormRules } from "element-plus";
//
import { integerRule, numberRule, stringRule } from "@/utils/formRules";
// API
import { getRoomTypeById } from "@/apis/roomType";
// API
import { getBedById, getBuildingById, getFloorById } from "@/apis/build";
// null
const ruleFormRef = ref<FormInstance | null>(null);
// false
const dialogVisible = ref(false);
// dialogVisible
watch(dialogVisible, (value, oldValue, onCleanup) => {
if (!value) {
// formData
formData.value = {
id: "",
name: "",
@ -92,35 +70,30 @@ watch(dialogVisible, (value, oldValue, onCleanup) => {
}
});
//
const rules = reactive<FormRules>({
name: [
{
required: true,
// stringRule
validator(rule, value, callback) {
stringRule(rule, value, callback, "床位名称", 2, 40);
},
trigger: "blur" //
trigger: "blur"
}
]
});
//
interface DialogProps {
title: string; //
isView: boolean; //
rowData?: any; //
api?: (params: any) => Promise<any>; // API
getTableList?: () => Promise<any>; //
title: string;
isView: boolean;
rowData?: any;
api?: (params: any) => Promise<any>;
getTableList?: () => Promise<any>;
}
// { isView: false, title: "" }
const drawerProps = ref<DialogProps>({
isView: false,
title: ""
});
//
const formData = ref({
id: "",
name: "",
@ -128,43 +101,35 @@ const formData = ref({
bedLimit: ""
});
//
//
const bedAcceptParams = async (params: DialogProps) => {
drawerProps.value = params;
if (drawerProps.value.title!== "新增床位") {
// API formData
if (drawerProps.value.title !== "新增床位") {
const res: any = await getBedById({
bedId: params.rowData.id
});
formData.value = res.data;
} else {
// 使
formData.value = params.rowData;
}else {
formData.value = params.rowData
}
//
dialogVisible.value = true;
};
//
const emits = defineEmits(["operateNode"]);
//
//
const handleSubmit = () => {
//
ruleFormRef.value!.validate(async valid => {
if (!valid) return;
try {
// API
const res = await drawerProps.value.api!(formData.value);
if (res.code == 200) {
//
ElMessage.success({
message: res.msg
});
emits("operateNode");
dialogVisible.value = false;
} else {
//
ElMessage.error({
message: res.msg
});
@ -175,13 +140,11 @@ const handleSubmit = () => {
});
};
// bedAcceptParams 便
defineExpose({
bedAcceptParams
});
</script>
<style scoped lang="scss">
// 10px
.dialog-footer button:first-child {
margin-right: 10px;
}

@ -1,95 +1,71 @@
<template>
<div>
<!-- Element Plus 的对话框组件 -->
<el-dialog
style="width: 70%;"
<!-- 使用 v-model 双向绑定对话框的显示状态 dialogVisible 控制 -->
v-model="dialogVisible"
<!-- 动态绑定对话框的标题 drawerProps.title 获取 -->
:title="drawerProps.title"
<!-- 当对话框关闭时销毁对话框实例 -->
destroy-on-close
style="width: 70%"
v-model="dialogVisible"
:title="drawerProps.title"
destroy-on-close
>
<div>
<!-- Element Plus 的表单组件 -->
<el-form
<!-- 绑定表单的数据模型数据来源于 formData -->
:model="formData"
class="login-form"
<!-- 为表单添加引用方便在 JavaScript 中获取表单实例ruleFormRef 为引用名称 -->
ref="ruleFormRef"
<!-- 绑定表单的验证规则规则定义在 rules -->
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为楼栋名称:对应表单数据中的 name 属性 -->
<el-form-item label="楼栋名称:" prop="name">
<!-- Element Plus 的输入框组件双向绑定 formData.name 的值并且可清除输入内容 -->
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为楼层数量:对应表单数据中的 floorNum 属性 -->
<el-form-item label="楼层数量:" prop="floorNum">
<!-- Element Plus 的输入框组件双向绑定 formData.floorNum 的值并且可清除输入内容 -->
<el-input v-model="formData.floorNum" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
<div>
<el-form
:model="formData"
class="login-form"
ref="ruleFormRef"
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<el-form-item label="楼栋名称:" prop="name">
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<el-form-item label="楼层数量:" prop="floorNum">
<el-input v-model="formData.floorNum" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<!-- drawerProps.isView false 显示对话框的页脚模板 -->
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<!-- 取消按钮点击时将 dialogVisible 设置为 false关闭对话框 -->
<el-button @click="dialogVisible = false">取消</el-button>
<!-- 提交按钮带有蓝色背景类类型为主要按钮点击时调用 handleSubmit 方法 -->
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
// Vue reactiverefwatch
import { reactive, ref, watch } from "vue";
// element-plus ElMessageFormInstanceFormRules
import { ElMessage, FormInstance, FormRules } from "element-plus";
// integerRulenumberRulestringRule
import { integerRule, numberRule, stringRule } from "@/utils/formRules";
// API ID getRoomTypeById使
import { getRoomTypeById } from "@/apis/roomType";
// API ID getBuildingById
import { getBuildingById } from "@/apis/build";
// null
const ruleFormRef = ref<FormInstance | null>(null);
// false
const dialogVisible = ref(false);
// dialogVisible
watch(dialogVisible, (value, oldValue, onCleanup) => {
if (!value) {
// formData
formData.value = {
id: "",
name: "",
@ -98,85 +74,72 @@ watch(dialogVisible, (value, oldValue, onCleanup) => {
}
});
//
const rules = reactive<FormRules>({
name: [
{
required: true,
// stringRule 2 10
validator(rule, value, callback) {
stringRule(rule, value, callback, "楼栋名称", 2, 10);
},
trigger: "blur" //
trigger: "blur"
}
],
floorNum: [
{
required: true,
// integerRule 1 10
validator(rule, value, callback) {
integerRule(rule, value, callback, "楼层数量", 1, 10);
},
trigger: "blur" //
trigger: "blur"
}
]
});
//
interface DialogProps {
title: string; //
isView: boolean; //
rowData?: any; //
api?: (params: any) => Promise<any>; // API
getTableList?: () => Promise<any>; //
title: string;
isView: boolean;
rowData?: any;
api?: (params: any) => Promise<any>;
getTableList?: () => Promise<any>;
}
// { isView: false, title: "" }
const drawerProps = ref<DialogProps>({
isView: false,
title: ""
});
// idnamefloorNum
const formData = ref({
id: "",
name: "",
floorNum: ""
});
//
//
const buildingAcceptParams = async (params: DialogProps) => {
drawerProps.value = params;
if (drawerProps.value.title!== "新增楼栋") {
// getBuildingById API formData
if (drawerProps.value.title !== "新增楼栋") {
const res: any = await getBuildingById({
buildingId: params.rowData.id
});
formData.value = res.data;
}
//
dialogVisible.value = true;
};
// operateNode
const emits = defineEmits(["operateNode"]);
//
//
const handleSubmit = () => {
//
ruleFormRef.value!.validate(async valid => {
if (!valid) return;
try {
// drawerProps.value.api
const res = await drawerProps.value.api!(formData.value);
if (res.code == 200) {
// operateNode
ElMessage.success({
message: res.msg
});
emits("operateNode");
dialogVisible.value = false;
} else {
//
ElMessage.error({
message: res.msg
});
@ -187,13 +150,11 @@ const handleSubmit = () => {
});
};
// buildingAcceptParams 便
defineExpose({
buildingAcceptParams
});
</script>
<style scoped lang="scss">
// 10px
.dialog-footer button:first-child {
margin-right: 10px;
}

@ -1,95 +1,71 @@
<template>
<div>
<!-- Element Plus 的对话框组件 -->
<el-dialog
style="width: 70%;"
<!-- 使用 v-model 双向绑定对话框的显示状态 dialogVisible 控制 -->
v-model="dialogVisible"
<!-- 动态绑定对话框的标题 drawerProps.title 获取 -->
:title="drawerProps.title"
<!-- 当对话框关闭时销毁对话框实例 -->
destroy-on-close
style="width: 70%"
v-model="dialogVisible"
:title="drawerProps.title"
destroy-on-close
>
<div>
<!-- Element Plus 的表单组件 -->
<el-form
<!-- 绑定表单的数据模型数据来源于 formData -->
:model="formData"
class="login-form"
<!-- 为表单添加引用方便在 JavaScript 中获取表单实例ruleFormRef 为引用名称 -->
ref="ruleFormRef"
<!-- 绑定表单的验证规则规则定义在 rules -->
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为楼层名称:对应表单数据中的 name 属性 -->
<el-form-item label="楼层名称:" prop="name">
<!-- Element Plus 的输入框组件双向绑定 formData.name 的值并且可清除输入内容 -->
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为房间数量:对应表单数据中的 roomNum 属性 -->
<el-form-item label="房间数量:" prop="roomNum">
<!-- Element Plus 的输入框组件双向绑定 formData.roomNum 的值并且可清除输入内容 -->
<el-input v-model="formData.roomNum" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
<div>
<el-form
:model="formData"
class="login-form"
ref="ruleFormRef"
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<el-form-item label="楼层名称:" prop="name">
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<el-form-item label="房间数量:" prop="roomNum">
<el-input v-model="formData.roomNum" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<!-- drawerProps.isView false 显示对话框的页脚模板 -->
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<!-- 取消按钮点击时将 dialogVisible 设置为 false关闭对话框 -->
<el-button @click="dialogVisible = false">取消</el-button>
<!-- 提交按钮带有蓝色背景类类型为主要按钮点击时调用 handleSubmit 方法 -->
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
// Vue reactiverefwatch
import { reactive, ref, watch } from "vue";
// element-plus ElMessageFormInstanceFormRules
import { ElMessage, FormInstance, FormRules } from "element-plus";
// integerRulenumberRulestringRule
import { integerRule, numberRule, stringRule } from "@/utils/formRules";
// API ID getRoomTypeById使
import { getRoomTypeById } from "@/apis/roomType";
// API ID getBuildingById ID getFloorById
import { getBuildingById, getFloorById } from "@/apis/build";
// null
const ruleFormRef = ref<FormInstance | null>(null);
// false
const dialogVisible = ref(false);
// dialogVisible
watch(dialogVisible, (value, oldValue, onCleanup) => {
if (!value) {
// formData
formData.value = {
id: "",
name: "",
@ -100,45 +76,39 @@ watch(dialogVisible, (value, oldValue, onCleanup) => {
}
});
//
const rules = reactive<FormRules>({
name: [
{
required: true,
// stringRule 2 20
validator(rule, value, callback) {
stringRule(rule, value, callback, "楼层名称", 2, 20);
},
trigger: "blur" //
trigger: "blur"
}
],
roomNum: [
{
required: true,
// integerRule 1 50
validator(rule, value, callback) {
integerRule(rule, value, callback, "房间数量", 1, 50);
},
trigger: "blur" //
trigger: "blur"
}
]
});
//
interface DialogProps {
title: string; //
isView: boolean; //
rowData?: any; //
api?: (params: any) => Promise<any>; // API
getTableList?: () => Promise<any>; //
title: string;
isView: boolean;
rowData?: any;
api?: (params: any) => Promise<any>;
getTableList?: () => Promise<any>;
}
// { isView: false, title: "" }
const drawerProps = ref<DialogProps>({
isView: false,
title: ""
});
// idnameroomNumbuildingIdfloorLimit
const formData = ref({
id: "",
name: "",
@ -147,43 +117,35 @@ const formData = ref({
floorLimit: ""
});
//
//
const floorAcceptParams = async (params: DialogProps) => {
drawerProps.value = params;
if (drawerProps.value.title!== "新增楼层") {
// getFloorById API formData
if (drawerProps.value.title !== "新增楼层") {
const res: any = await getFloorById({
floorId: params.rowData.id
});
formData.value = res.data;
} else {
// 使
formData.value = params.rowData;
}else {
formData.value = params.rowData
}
//
dialogVisible.value = true;
};
// operateNode
const emits = defineEmits(["operateNode"]);
//
//
const handleSubmit = () => {
//
ruleFormRef.value!.validate(async valid => {
if (!valid) return;
try {
// drawerProps.value.api
const res = await drawerProps.value.api!(formData.value);
if (res.code == 200) {
// operateNode
ElMessage.success({
message: res.msg
});
emits("operateNode");
dialogVisible.value = false;
} else {
//
ElMessage.error({
message: res.msg
});
@ -194,13 +156,11 @@ const handleSubmit = () => {
});
};
// floorAcceptParams 便
defineExpose({
floorAcceptParams
});
</script>
<style scoped lang="scss">
// 10px
.dialog-footer button:first-child {
margin-right: 10px;
}

@ -1,127 +1,89 @@
<template>
<!-- 根元素包裹整个组件的内容 -->
<div>
<!-- Element Plus 的对话框组件 -->
<el-dialog
<!-- 设置对话框的宽度为 70% -->
style="width: 70%"
<!-- 使用 v-model 双向绑定对话框的显示状态dialogVisible 为控制显示隐藏的响应式变量 -->
v-model="dialogVisible"
<!-- 动态绑定对话框的标题标题内容从 drawerProps.title 获取 -->
:title="drawerProps.title"
<!-- 当对话框关闭时销毁对话框实例 -->
destroy-on-close
style="width: 70%"
v-model="dialogVisible"
:title="drawerProps.title"
destroy-on-close
>
<!-- 对话框的内容区域 -->
<div>
<!-- Element Plus 的表单组件 -->
<el-form
<!-- 绑定表单的数据模型数据存储在 formData -->
:model="formData"
<!-- 为表单添加一个类名方便样式控制 -->
class="login-form"
<!-- 为表单添加引用方便在 JavaScript 中访问表单实例ruleFormRef 为引用名称 -->
ref="ruleFormRef"
<!-- 绑定表单的验证规则规则定义在 rules -->
:rules="rules"
<!-- 设置表单标签的宽度为 120px -->
label-width="120px"
>
<!-- 使用 flex 布局元素均匀分布且换行 -->
<div class="flex justify-around flex-wrap">
<!-- 第一个表单字段区域在小屏幕下宽度为 100%在中等及以上屏幕宽度为 50% -->
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为房间名称:对应表单数据中的 name 属性 -->
<el-form-item label="房间名称:" prop="name">
<!-- 输入框组件双向绑定 formData.name 的值且可清除输入内容 -->
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<!-- 第二个表单字段区域在小屏幕下宽度为 100%在中等及以上屏幕宽度为 50% -->
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为房间类型:对应表单数据中的 typeId 属性 -->
<el-form-item label="房间类型:" prop="typeId">
<!-- 下拉选择框组件双向绑定 formData.typeId 的值有提示文本请选择宽度占满父容器 -->
<el-select
v-model="formData.typeId"
placeholder="请选择"
class="w-full"
>
<!-- 循环渲染房间类型选项每个选项的 label item.namevalue item.idkey item.id -->
<el-option
clearable
:label="item.name"
:value="item.id"
v-for="item in roomTypeList"
:key="item.id"
/>
</el-select>
</el-form-item>
</div>
<!-- 第三个表单字段区域在小屏幕下宽度为 100%在中等及以上屏幕宽度为 50% -->
<div class="w-full md:w-1/2">
<!-- 表单字段项标签为床位数量:对应表单数据中的 bedNum 属性 -->
<el-form-item label="床位数量:" prop="bedNum">
<!-- 输入框组件双向绑定 formData.bedNum 的值且可清除输入内容 -->
<el-input v-model="formData.bedNum" clearable />
</el-form-item>
</div>
<!-- 占位区域在中等及以上屏幕宽度为 50%循环渲染一次高度为 0 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
<div>
<el-form
:model="formData"
class="login-form"
ref="ruleFormRef"
:rules="rules"
label-width="120px"
>
<div class="flex justify-around flex-wrap">
<div class="w-full md:w-1/2">
<el-form-item label="房间名称:" prop="name">
<el-input v-model="formData.name" clearable />
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<el-form-item label="房间类型:" prop="typeId">
<el-select
v-model="formData.typeId"
placeholder="请选择"
class="w-full"
>
<el-option
clearable
:label="item.name"
:value="item.id"
v-for="item in roomTypeList"
:key="item.id"
/>
</el-select>
</el-form-item>
</div>
<div class="w-full md:w-1/2">
<el-form-item label="床位数量:" prop="bedNum">
<el-input v-model="formData.bedNum" clearable />
</el-form-item>
</div>
<!-- 占位 -->
<div
class="md:w-1/2"
v-for="i in 1"
:key="i"
style="height: 0"
></div>
</div>
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<!-- 使用 flex 布局子元素反向排列 -->
<div class="flex flex-row-reverse">
<div></div>
</div>
</el-form>
</div>
<!-- drawerProps.isView false 显示对话框的页脚模板 -->
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<!-- 取消按钮点击时将 dialogVisible 设置为 false关闭对话框 -->
<el-button @click="dialogVisible = false">取消</el-button>
<!-- 提交按钮bg-blue类样式类型为主要按钮点击时调用 handleSubmit 方法 -->
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
<template v-if="!drawerProps.isView" #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
class="bg-blue"
type="primary"
@click="handleSubmit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
// Vue reactiverefwatch
import { reactive, ref, watch } from "vue";
// element-plus ElMessageFormInstanceFormRules
import { ElMessage, FormInstance, FormRules } from "element-plus";
// integerRulenumberRulestringRule
import { integerRule, numberRule, stringRule } from "@/utils/formRules";
// API ID getRoomTypeById使
import { getRoomTypeById } from "@/apis/roomType";
// API ID getBuildingById ID getFloorById ID getRoomById listRoomType
import { getBuildingById, getFloorById, getRoomById, listRoomType } from "@/apis/build";
// null
const ruleFormRef = ref<FormInstance | null>(null);
// false
const dialogVisible = ref(false);
//
const roomTypeList = ref<any>([])
// dialogVisible
watch(dialogVisible, (value, oldValue, onCleanup) => {
if (!value) {
// formData
formData.value = {
id: '',
name: '',
@ -133,55 +95,40 @@ watch(dialogVisible, (value, oldValue, onCleanup) => {
}
});
//
const rules = reactive<FormRules>({
name: [
{
required: true,
// stringRule 2 30
validator(rule, value, callback) {
stringRule(rule, value, callback, "房间名称", 2, 30);
},
//
trigger: "blur"
}
],
typeId: [
{
required: true,
// typeId
message: "请选择房间类型",
trigger: "blur"
}
],
typeId: [{ required: true, message: "请选择房间类型", trigger: "blur" }],
bedNum: [
{
required: true,
// integerRule 1 8
validator(rule, value, callback) {
integerRule(rule, value, callback, "床位数量", 1, 8);
},
//
trigger: "blur"
}
]
});
//
interface DialogProps {
title: string; //
isView: boolean; //
rowData?: any; //
api?: (params: any) => Promise<any>; // API
getTableList?: () => Promise<any>; //
title: string;
isView: boolean;
rowData?: any;
api?: (params: any) => Promise<any>;
getTableList?: () => Promise<any>;
}
// { isView: false, title: "" }
const drawerProps = ref<DialogProps>({
isView: false,
title: ""
});
// idnametypeIdbedNumfloorIdroomLimit
const formData = ref({
id: '',
name: '',
@ -191,68 +138,53 @@ const formData = ref({
roomLimit: ''
});
//
//
const roomAcceptParams = async (params: DialogProps) => {
drawerProps.value = params;
if (drawerProps.value.title!== "新增房间") {
// getRoomById API formData
if (drawerProps.value.title !== "新增房间") {
const res: any = await getRoomById({
roomId: params.rowData.id
});
formData.value = res.data;
} else {
// 使
formData.value = params.rowData;
}else {
formData.value = params.rowData
}
//
const res: any = await listRoomType()
roomTypeList.value = res.data;
// formData
const res:any = await listRoomType()
roomTypeList.value = res.data
console.log(formData.value);
//
dialogVisible.value = true;
};
// operateNode
const emits = defineEmits(["operateNode"]);
//
//
const handleSubmit = () => {
//
ruleFormRef.value!.validate(async valid => {
if (!valid) return;
try {
// drawerProps.value.api
const res = await drawerProps.value.api!(formData.value);
if (res.code == 200) {
//
ElMessage.success({
message: res.msg
});
// operateNode
emits("operateNode");
//
dialogVisible.value = false;
} else {
//
ElMessage.error({
message: res.msg
});
}
} catch (error) {
//
console.log(error);
}
});
};
// roomAcceptParams 便
defineExpose({
roomAcceptParams
});
</script>
<style scoped lang="scss">
// 10px
.dialog-footer button:first-child {
margin-right: 10px;
}

@ -1,132 +1,87 @@
<template>
<!-- 根元素设置为 flex 布局用于包裹页面的主要内容区域 -->
<div style="display: flex;">
<!-- 左侧区域背景颜色为白色flex 占比为 2右边距 10px内边距 10px -->
<div class="bg-white" style="flex:2;margin-right: 10px;padding: 10px;">
<!-- 可滚动区域高度为 560px上边距 10px用于包裹树状结构 -->
<el-scrollbar height="560px" style="margin-top: 10px;">
<!-- Element Plus 的树状组件 -->
<el-tree
<!-- 为树状组件添加引用方便在 JavaScript 中访问树组件实例 -->
ref="treeRef"
<!-- 绑定树状结构的数据buildTree 是存储树数据的响应式变量 -->
:data="buildTree"
<!-- 定义树状结构的属性映射children 对应子节点数组属性名label 对应节点显示名称属性名 -->
:props="defaultProps"
<!-- 设置默认展开所有节点 -->
:default-expand-all="true"
<!-- 显示复选框让用户可以选择节点 -->
show-checkbox
<!-- 开启严格的父子节点选中逻辑即父子节点选中状态互不影响 -->
check-strictly
<!-- 监听复选框的点击事件当复选框状态改变时调用 handleCheck 方法 -->
@check="handleCheck"
ref="treeRef"
:data="buildTree"
:props="defaultProps"
:default-expand-all="true"
show-checkbox
check-strictly
@check="handleCheck"
/>
</el-scrollbar>
</div>
<!-- 右侧区域类名为 table-boxflex 占比为 8用于放置表格和相关操作元素 -->
<div class="table-box" style="flex: 8">
<!-- 自定义的表格组件 ProTable -->
<ProTable
<!-- 为表格组件添加引用方便在 JavaScript 中访问表格组件实例 -->
ref="proTable"
<!-- 设置表格的标题为用户列表 -->
title="用户列表"
<!-- 绑定表格的列配置信息columns 是一个包含列属性的数组 -->
:columns="columns"
<!-- 绑定获取表格数据的 API 函数getTableList 用于发起数据请求 -->
:requestApi="getTableList"
<!-- 绑定初始的请求参数对象initParam 是一个响应式对象 -->
:initParam="initParam"
<!-- 绑定数据处理回调函数dataCallback 用于对从 API 获取的数据进行处理 -->
:dataCallback="dataCallback"
ref="proTable"
title="用户列表"
:columns="columns"
:requestApi="getTableList"
:initParam="initParam"
:dataCallback="dataCallback"
>
<!-- 表格头部按钮的插槽用于自定义表格头部的按钮 -->
<template #tableHeader>
<!-- 新增节点按钮按钮类型为主要按钮绑定 Plus 图标点击时调用 openDrawer 方法传递类型为node和操作名称为新增 -->
<el-button type="primary" :icon="Plus" @click="openDrawer('node','新增')">
<span>新增节点</span>
</el-button>
<!-- 编辑节点按钮按钮类型为警告按钮绑定 EditPen 图标点击时调用 openDrawer 方法传递类型为node和操作名称为编辑 -->
<el-button type="warning" :icon="EditPen" @click="openDrawer('node','编辑')">
<span>编辑节点</span>
</el-button>
<!-- 删除节点按钮按钮类型为危险按钮绑定 Delete 图标点击时调用 deleteTypeData 方法 -->
<el-button type="danger" :icon="Delete" @click="deleteTypeData">
<span>删除节点</span>
</el-button>
</template>
<!-- 表格 header 按钮 -->
<template #tableHeader>
<el-button type="primary" :icon="Plus" @click="openDrawer('node','新增')">
<span>新增节点</span>
</el-button>
<el-button type="warning" :icon="EditPen" @click="openDrawer('node','编辑')">
<span>编辑节点</span>
</el-button>
<el-button type="danger" :icon="Delete" @click="deleteTypeData">
<span>删除节点</span>
</el-button>
</template>
<!-- 表格操作列的插槽scope 包含当前行的数据等信息用于自定义表格的操作按钮 -->
<template #operation="scope">
<!-- 查看按钮按钮尺寸为小为链接样式绑定 View 图标点击时调用 openDrawer 方法传递类型为bed操作名称为查看以及当前行数据 scope -->
<el-button
size="small"
link
:icon="View"
@click="openDrawer('bed','查看',scope)"
>
查看
</el-button>
<!-- 编辑按钮按钮尺寸为小为链接样式绑定 EditPen 图标点击时调用 openDrawer 方法传递类型为bed操作名称为编辑以及当前行数据 scope -->
<el-button
size="small"
link
:icon="EditPen"
@click="openDrawer('bed','编辑',scope)"
>
编辑
</el-button>
<!-- 弹出确认删除的对话框组件 -->
<el-popconfirm
<!-- 设置对话框的提示标题 -->
title="Are you sure to delete this?"
<!-- 确认删除时调用 deleteBedData 方法并传递当前行数据 scope -->
@confirm="deleteBedData(scope)"
<!-- 设置确认按钮的类型为危险按钮 -->
confirm-button-type="danger"
>
<!-- 对话框的触发元素插槽这里是一个删除按钮按钮尺寸为小为链接样式绑定 Delete 图标 -->
<template #reference>
<el-button size="small" link :icon="Delete">删除</el-button>
<!-- 表格操作 -->
<template #operation="scope">
<el-button
size="small"
link
:icon="View"
@click="openDrawer('bed','查看',scope)"
>
查看
</el-button>
<el-button
size="small"
link
:icon="EditPen"
@click="openDrawer('bed','编辑',scope)"
>
编辑
</el-button>
<el-popconfirm
title="Are you sure to delete this?"
@confirm="deleteBedData(scope)"
confirm-button-type="danger"
>
<template #reference>
<el-button size="small" link :icon="Delete">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-popconfirm>
</template>
</ProTable>
<!-- 引入自定义的 buildingDialog 组件监听 operateNode 事件当事件触发时调用 operateNode 方法同时为组件添加引用 buildingDialogRef -->
<buildDialog @operateNode="operateNode" ref="buildingDialogRef" />
<!-- 引入自定义的 floorDialog 组件监听 operateNode 事件当事件触发时调用 operateNode 方法同时为组件添加引用 floorDialogRef -->
<floorDialog @operateNode="operateNode" ref="floorDialogRef" />
<!-- 引入自定义的 roomDialog 组件监听 operateNode 事件当事件触发时调用 operateNode 方法同时为组件添加引用 roomDialogRef -->
<roomDialog @operateNode="operateNode" ref="roomDialogRef" />
<!-- 引入自定义的 bedDialog 组件监听 operateNode 事件当事件触发时调用 operateNode 方法同时为组件添加引用 bedDialogRef -->
<bedDialog @operateNode="operateNode" ref="bedDialogRef" />
</div>
</div>
</template>
<script setup lang="ts" name="useProTable">
// Vue ref
// reactive
// onMounted
import { ref, reactive, onMounted } from "vue";
// element-plus ElMessage
import { ElMessage } from "element-plus";
// buildingDialog
import buildDialog from "./dialog/build.vue";
// floorDialog
import floorDialog from "./dialog/floor.vue";
// roomDialog
import roomDialog from "./dialog/room.vue";
// bedDialog
import bedDialog from "./dialog/bed.vue";
// ColumnProps
import { ColumnProps } from "@/components/ProTable/interface";
// ProTable
import ProTable from "@/components/ProTable/index.vue";
// Element Plus DeleteEditPenViewPlus
import { Delete, EditPen, View, Plus } from "@element-plus/icons-vue";
// API
import {
addBed,
addBuilding, addFloor, addRoom,
@ -138,49 +93,40 @@ import {
pageBedByKey
} from "@/apis/build";
// ProTable
// ProTable 便
const proTable = ref();
//
const initParam = reactive({});
//
const treeRef = ref<any>();
//
const ICheckedNode = ref<any>({});
//
const buildTree = ref<any>([]);
//
const defaultProps = {
children: "childrenList",
label: "name"
};
//
//
const handleCheck = (checkedNode: any, checkedNodeDetail: any) => {
if (checkedNodeDetail.checkedNodes.length > 0) {
//
ICheckedNode.value = checkedNode;
} else {
//
ICheckedNode.value = { id: -1, level: -1 };
}
// 1 10
getTableListHandle(1, 10);
//
//
treeRef.value.getCheckedNodes().forEach((node: any) => {
if (node.onlyMark!== ICheckedNode.value.onlyMark) {
if (node.onlyMark !== ICheckedNode.value.onlyMark) {
treeRef.value.setChecked(node, false);
}
});
};
//
//
onMounted(() => {
//
getBuildTreeHandle();
});
// API
// dataCallback list && total && pageNum && pageSize
// hooks/useTable.ts
const dataCallback = (data: any) => {
return {
list: data.list,
@ -190,22 +136,18 @@ const dataCallback = (data: any) => {
};
};
//
// params
// ProTable :requestApi="getUserList"
const getTableList = (params: any) => {
//
params = addSearchField(params);
//
let newParams = JSON.parse(JSON.stringify(params));
// pageBedByKey API
return pageBedByKey(newParams);
};
//
//
const getTableListHandle = (pageNum: number, pageSize: number) => {
let params: any = {};
//
params = addSearchField(params);
// ProTable getTableList
proTable.value.getTableList({
pageNum: pageNum,
pageSize: pageSize,
@ -216,39 +158,31 @@ const getTableListHandle = (pageNum: number, pageSize: number) => {
});
};
//
//
const getBuildTreeHandle = async () => {
//
ICheckedNode.value = { id: -1, level: -1 };
// getNoBedTree API
const res: any = await getNoBedTree();
//
buildTree.value = res.data;
// 1 10
getTableListHandle(1, 10);
};
//
//
const addSearchField = (params: any) => {
if (ICheckedNode.value.id!== -1) {
if (ICheckedNode.value.id !== -1) {
if (ICheckedNode.value.level === 1) {
// buildingId id floorId roomId
params.buildId = ICheckedNode.value.id;
params.floorId = null;
params.roomId = null;
} else if (ICheckedNode.value.level === 2) {
// floorId id buildingId roomId
params.buildId = null;
params.floorId = ICheckedNode.value.id;
params.roomId = null;
} else if (ICheckedNode.value.level === 3) {
// roomId id buildingId floorId
params.buildId = null;
params.floorId = null;
params.roomId = ICheckedNode.value.id;
}
} else {
// buildingIdfloorId roomId
params.buildId = null;
params.floorId = null;
params.roomId = null;
@ -256,73 +190,61 @@ const addSearchField = (params: any) => {
return params;
};
//
//
const deleteTypeData = async () => {
if ((Object.keys(ICheckedNode.value).length === 0 || ICheckedNode.value.id === -1)) {
//
ElMessage.warning("请选择节点");
return;
}
// deleteNode API id
const res: any = await deleteNode({
id: ICheckedNode.value.id,
mark: ICheckedNode.value.level === 1? "楼栋" : ICheckedNode.value.level === 2? "楼层" : ICheckedNode.value.level === 3? "房间" : ""
mark: ICheckedNode.value.level === 1 ? "楼栋" : ICheckedNode.value.level === 2 ? "楼层" : ICheckedNode.value.level === 3 ? "房间" : ""
});
if (res.code === 200) {
//
ElMessage.success(res.msg);
await getBuildTreeHandle();
} else {
//
ElMessage.error(res.msg);
}
};
//
//
const deleteBedData = async (params: any) => {
// deleteBed API id
const res: any = await deleteBed({
bedId: params.row.id
});
if (res.code === 200) {
//
ElMessage.success(res.msg);
proTable.value.getTableList();
} else {
//
ElMessage.error(res.msg);
}
};
// buildingDialogfloorDialogroomDialogbedDialog
// drawer()
const buildingDialogRef = ref();
const floorDialogRef = ref();
const roomDialogRef = ref();
const bedDialogRef = ref();
//
const openDrawer = (type: string, title: string, rowData: any = {}) => {
if (type === "node") {
//
//
if (title === "编辑" && (Object.keys(ICheckedNode.value).length === 0 || ICheckedNode.value.id === -1)) {
ElMessage.warning("请选择节点");
return;
}
//
//
if (title === "新增") {
const parentNode = treeRef.value.getCheckedNodes()[0];
if (ICheckedNode.value.level === -1) {
//
if (ICheckedNode.value.level === -1) {//
const params = {
title: title + "楼栋",
rowData: {},
isView: false,
api: addBuilding
};
// buildingDialog buildingAcceptParams
buildingDialogRef.value.buildingAcceptParams(params);
} else if (ICheckedNode.value.level === 1) {
//
} else if (ICheckedNode.value.level === 1) {//
const params = {
title: title + "楼层",
rowData: {
@ -332,10 +254,8 @@ const openDrawer = (type: string, title: string, rowData: any = {}) => {
isView: false,
api: addFloor
};
// floorDialog floorAcceptParams
floorDialogRef.value.floorAcceptParams(params);
} else if (ICheckedNode.value.level === 2) {
//
} else if (ICheckedNode.value.level === 2) {//
const params = {
title: title + "房间",
rowData: {
@ -345,10 +265,99 @@ const openDrawer = (type: string, title: string, rowData: any = {}) => {
isView: false,
api: addRoom
};
// roomDialog roomAcceptParams
roomDialogRef.value.roomAcceptParams(params);
} else if (ICheckedNode.value.level === 3) {
//
} else if (ICheckedNode.value.level === 3) {//
const params = {
title: title + "床位",
rowData:
rowData: {
roomId: parentNode.roomId,
bedLimit: parentNode.bedLimit
},
isView: false,
api: addBed
};
bedDialogRef.value.bedAcceptParams(params);
}
} else if (title === "编辑") {
if (ICheckedNode.value.level === 1) {//
const params = {
title: title + "楼栋",
rowData: { ...ICheckedNode.value },
isView: false,
api: editBuilding
};
buildingDialogRef.value.buildingAcceptParams(params);
} else if (ICheckedNode.value.level === 2) {//
const params = {
title: title + "楼层",
rowData: { ...ICheckedNode.value },
isView: false,
api: editFloor
};
floorDialogRef.value.floorAcceptParams(params);
} else if (ICheckedNode.value.level === 3) {//
const params = {
title: title + "房间",
rowData: { ...ICheckedNode.value },
isView: false,
api: editRoom
};
roomDialogRef.value.roomAcceptParams(params);
}
}
} else if (type === "bed") {//
const params = {
title,
rowData: { ...rowData.row },
isView: title === "查看",
api: title === "新增" ? addBed : title === "编辑" ? editBed : "",
};
bedDialogRef.value.bedAcceptParams(params);
}
};
//
const operateNode = () => {
getBuildTreeHandle();
};
//
const columns: ColumnProps<any>[] = [
{ prop: "rank", label: "序号", width: 55 },
{ prop: "name", label: "床位名称" },
{
enum: IBedFlagList,
prop: "bedFlag",
label: "床位状态",
search: { el: "select", props: { filterable: false } }
},
{ prop: "operation", label: "操作", width: 220 }
];
</script>
<style lang="scss" scoped>
:deep(.el-radio__input) {
display: none !important;
}
:deep(.el-radio__label) {
font-size: 1em;
width: 248px;
padding: 5px 0 5px 10px;
transition: all 0.2s;
&:hover {
background-color: #eeeeee;
}
}
.el-radio-group {
display: flex;
flex-wrap: wrap;
.el-radio {
flex: 1;
margin-right: 100%;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save