Compare commits
1 Commits
main
...
waterelect
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c93e1e6e9 |
@@ -11,7 +11,7 @@ VITE_APP_BASE_API = '/dev-api'
|
||||
# # 开发环境 接口代理地址
|
||||
VITE_APP_PROXY_API = 'http://192.168.1.222:8080'
|
||||
# 开发环境 接口代理地址
|
||||
# VITE_APP_PROXY_API = 'http://192.168.0.239:8080'
|
||||
# VITE_APP_PROXY_API = 'http://192.168.1.215:8080'
|
||||
# 图片基础地址
|
||||
VITE_IMG_URL = 'http://192.168.1.222:8080'
|
||||
|
||||
@@ -27,29 +27,6 @@ VITE_APP_SNAILJOB_ADMIN = 'http://192.168.1.215/snail-job'
|
||||
|
||||
VITE_APP_PORT = 5173
|
||||
|
||||
# 登录成功跳转地址
|
||||
# VITE_LOGIN_BACK_URL = '/equipment/WaterDevice'
|
||||
VITE_LOGIN_BACK_URL = '/index'
|
||||
# 工作台正式内容:false 假内容:true
|
||||
VITE_LOGIN_BACK_URL_WORKBENCH_TRUE= true
|
||||
# 是否展示工作台
|
||||
VITE_APP_SHOW_WORK_PLATFORM = true
|
||||
|
||||
|
||||
# 地图类型 天地图 or 高德地图 天地图 WGS84 高德地图 GCJ02, 高德地图 需要在高德地图官网申请key
|
||||
# 高德地图 GCJ02
|
||||
# 天地图 WGS84
|
||||
VITE_APP_MAP_TYPE = 'GCJ02'
|
||||
|
||||
# 高德地图key 建议放入环境变量中,避免泄露
|
||||
VITE_GCJ02_KEY_GD = '8e302fe1be5f4db62bc734db23dca149'
|
||||
VITE_GCJ02_JS_CODE_GD = '09534b3534d8da53968529a9ce164118'
|
||||
|
||||
# 天地图key 建议放入环境变量中,避免泄露
|
||||
VITE_TIANDITU_KEY = 'f71689f9e22158947ebf64ad95e0a595'
|
||||
VITE_TIANDITU_JS_CODE = ''
|
||||
|
||||
|
||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||
VITE_APP_ENCRYPT = true
|
||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||
@@ -64,5 +41,4 @@ VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
VITE_APP_WEBSOCKET = false
|
||||
|
||||
# sse 开关
|
||||
VITE_APP_SSE = true
|
||||
|
||||
VITE_APP_SSE = false
|
||||
|
||||
@@ -18,28 +18,10 @@ VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||
VITE_APP_BASE_API = 'https://wuyeapi.bugtc.com'
|
||||
# VITE_APP_BASE_API = 'http://192.168.0.222:8080'
|
||||
|
||||
# 登录成功跳转地址
|
||||
# VITE_LOGIN_BACK_URL = '/equipment/WaterDevice'
|
||||
VITE_LOGIN_BACK_URL = '/index'
|
||||
# 工作台正式内容:false 假内容:true
|
||||
VITE_LOGIN_BACK_URL_WORKBENCH_TRUE= true
|
||||
# 是否展示工作台
|
||||
VITE_APP_SHOW_WORK_PLATFORM = true
|
||||
|
||||
|
||||
# 地图类型 天地图 or 高德地图 天地图 WGS84 高德地图 GCJ02, 高德地图 需要在高德地图官网申请key
|
||||
# 高德地图 GCJ02
|
||||
# 天地图 WGS84
|
||||
VITE_APP_MAP_TYPE = 'GCJ02'
|
||||
|
||||
# 高德地图key 建议放入环境变量中,避免泄露
|
||||
VITE_GCJ02_KEY_GD = '8e302fe1be5f4db62bc734db23dca149'
|
||||
VITE_GCJ02_JS_CODE_GD = '09534b3534d8da53968529a9ce164118'
|
||||
|
||||
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
# VITE_BUILD_COMPRESS = gzip
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_APP_PORT = 80
|
||||
|
||||
@@ -57,4 +39,4 @@ VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
VITE_APP_WEBSOCKET = false
|
||||
|
||||
# sse 开关
|
||||
VITE_APP_SSE = true
|
||||
VITE_APP_SSE = false
|
||||
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -2,23 +2,6 @@
|
||||
.history
|
||||
node_modules/
|
||||
dist/
|
||||
.env
|
||||
.git
|
||||
.idea
|
||||
.vscode
|
||||
.gitignore
|
||||
.npmrc
|
||||
.yarn
|
||||
.yarnrc
|
||||
.pnp.js
|
||||
.pnp.lock.json
|
||||
.pnp
|
||||
.yarn.lock
|
||||
.bat
|
||||
dist.zip
|
||||
.zip
|
||||
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -44,5 +27,3 @@ pnpm-lock.yaml
|
||||
# 编译生成的文件
|
||||
auto-imports.d.ts
|
||||
components.d.ts
|
||||
|
||||
|
||||
|
||||
12
bin/build.bat
Normal file
12
bin/build.bat
Normal file
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 打包Web工程,生成dist文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn build:prod
|
||||
|
||||
pause
|
||||
12
bin/package.bat
Normal file
12
bin/package.bat
Normal file
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 安装Web工程,生成node_modules文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn --registry=https://registry.npmmirror.com
|
||||
|
||||
pause
|
||||
12
bin/run-web.bat
Normal file
12
bin/run-web.bat
Normal file
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用 Vite 命令运行 Web 工程。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn dev
|
||||
|
||||
pause
|
||||
@@ -35,12 +35,11 @@
|
||||
"echarts": "6.0.0",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"element-plus": "2.13.5",
|
||||
"file-saver": "^2.0.5",
|
||||
"file-saver": "2.0.5",
|
||||
"highlight.js": "11.11.1",
|
||||
"image-conversion": "2.1.1",
|
||||
"js-cookie": "3.0.5",
|
||||
"jsencrypt": "3.5.4",
|
||||
"jszip": "^3.10.1",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
@@ -57,7 +56,7 @@
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.448",
|
||||
"@types/crypto-js": "4.2.2",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/file-saver": "2.0.7",
|
||||
"@types/js-cookie": "3.0.6",
|
||||
"@types/node": "^25.4.0",
|
||||
"@types/nprogress": "0.2.3",
|
||||
@@ -86,7 +85,6 @@
|
||||
"vite": "7.3.1",
|
||||
"vite-plugin-svg-icons-ng": "^1.5.2",
|
||||
"vite-plugin-vue-devtools": "8.0.7",
|
||||
"vite-plugin-zip-pack": "^1.2.4",
|
||||
"vitest": "4.0.18",
|
||||
"vue-tsc": "^3.2.5"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
// autoprefixer: {},
|
||||
autoprefixer: {},
|
||||
'postcss-pxtorem': {
|
||||
rootValue: 16, // 基准根节点字体大小
|
||||
propList: ['*'], // 所有属性都转换
|
||||
|
||||
@@ -61,18 +61,3 @@ export const delBanner = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 改变Banner图管理 状态
|
||||
* @param id
|
||||
*/
|
||||
export const switchBanner = (id: string, status: string) => {
|
||||
return request({
|
||||
url: '/banner/changeStatus',
|
||||
method: 'GET',
|
||||
params: {
|
||||
id,
|
||||
status
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -17,9 +17,9 @@ export interface BannerVO {
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
order: number;
|
||||
url: string;
|
||||
byOrder: number;
|
||||
link: string;
|
||||
jump_link: string;
|
||||
/**
|
||||
* 小区id
|
||||
*/
|
||||
@@ -45,8 +45,7 @@ export interface BannerForm extends BaseEntity {
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
byOrder?: number;
|
||||
link: string;
|
||||
order?: number;
|
||||
|
||||
/**
|
||||
* 小区id
|
||||
@@ -68,8 +67,8 @@ export interface BannerQuery extends PageQuery {
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
byOrder: number;
|
||||
link: string;
|
||||
order?: number;
|
||||
|
||||
/**
|
||||
* 小区id
|
||||
*/
|
||||
|
||||
@@ -60,12 +60,12 @@ export interface DecorationForm extends BaseEntity {
|
||||
* 所属小区id
|
||||
*/
|
||||
villageId?: string;
|
||||
villageName?: string;
|
||||
|
||||
/**
|
||||
* 所属房屋id
|
||||
*/
|
||||
houseId?: string | number;
|
||||
houseName?: string;
|
||||
|
||||
/**
|
||||
* 申请人姓名
|
||||
*/
|
||||
|
||||
@@ -61,15 +61,3 @@ export const delPlan = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 改变巡检计划状态
|
||||
* @param id
|
||||
* @param status
|
||||
*/
|
||||
export const changePlanStatus = (id: string, status: string) => {
|
||||
return request({
|
||||
url: '/inspection/plan/changeStatus',
|
||||
method: 'put',
|
||||
data: { id, status }
|
||||
});
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { PointVO, PointForm, PointQuery } from '@/api/system/InspectionPoint/typ
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listPoint = (query?: PointQuery | {}): AxiosPromise<PointVO[]> => {
|
||||
export const listPoint = (query?: PointQuery): AxiosPromise<PointVO[]> => {
|
||||
return request({
|
||||
url: '/inspection/point/list',
|
||||
method: 'get',
|
||||
@@ -61,13 +61,3 @@ export const delPoint = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 修改巡检点状态
|
||||
* @param id
|
||||
*/
|
||||
export const changePointStatus = (id: string, status: string) => {
|
||||
return request({
|
||||
url: '/inspection/point/changeStatus?id=' + id + '&status=' + status,
|
||||
method: 'PUT'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
export interface RecordVO {
|
||||
actualEndTime?: string;
|
||||
actualStartTime?: string;
|
||||
createByName?: string;
|
||||
actualEndTime?: null;
|
||||
actualStartTime?: null;
|
||||
createByName?: null;
|
||||
createTime?: string;
|
||||
details?: [];
|
||||
details?: null;
|
||||
id?: string;
|
||||
inspectorId?: number;
|
||||
inspectorName?: string;
|
||||
planId?: string;
|
||||
planName?: string;
|
||||
remark?: string;
|
||||
remark?: null;
|
||||
routeId?: string;
|
||||
routeName?: string;
|
||||
status?: number;
|
||||
|
||||
@@ -61,11 +61,3 @@ export const delRoute = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
export const changeStatusRoute = (id: string, status: string) => {
|
||||
return request({
|
||||
url: '/inspection/route/changeStatus',
|
||||
method: 'put',
|
||||
params: { id, status }
|
||||
});
|
||||
};
|
||||
|
||||
@@ -26,8 +26,6 @@ export interface RouteVO {
|
||||
*/
|
||||
estimatedTime: number;
|
||||
|
||||
items: { itemName: string }[];
|
||||
PointsName: string;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
@@ -22,12 +22,12 @@ export interface NoticeVO {
|
||||
/**
|
||||
* 紧急程度 0=普通 1=紧急 2=非常紧急
|
||||
*/
|
||||
urgencyLevel: number;
|
||||
urgencyLevel: string;
|
||||
|
||||
/**
|
||||
* 发布状态 0=草稿 1=已发布
|
||||
*/
|
||||
publishStatus: number;
|
||||
publishStatus: string;
|
||||
|
||||
/**
|
||||
* 发布人
|
||||
@@ -64,12 +64,12 @@ export interface NoticeForm extends BaseEntity {
|
||||
/**
|
||||
* 紧急程度 0=普通 1=紧急 2=非常紧急
|
||||
*/
|
||||
urgencyLevel?: number;
|
||||
urgencyLevel?: string;
|
||||
|
||||
/**
|
||||
* 发布状态 0=草稿 1=已发布
|
||||
*/
|
||||
publishStatus?: number;
|
||||
publishStatus?: string;
|
||||
|
||||
/**
|
||||
* 发布人
|
||||
@@ -101,12 +101,12 @@ export interface NoticeQuery extends PageQuery {
|
||||
/**
|
||||
* 紧急程度 0=普通 1=紧急 2=非常紧急
|
||||
*/
|
||||
urgencyLevel?: number;
|
||||
urgencyLevel?: string;
|
||||
|
||||
/**
|
||||
* 发布状态 0=草稿 1=已发布
|
||||
*/
|
||||
publishStatus?: number;
|
||||
publishStatus?: string;
|
||||
|
||||
/**
|
||||
* 发布人
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export interface NotificationVo {
|
||||
'id': 'string';
|
||||
'title': 'string';
|
||||
'item': 'string';
|
||||
'content': 'string';
|
||||
'manageIsCheck': 'string';
|
||||
'repairIsCheck': 'string';
|
||||
}
|
||||
/**
|
||||
* 查询消息通知列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const getNotificationList = (query): AxiosPromise<NoticeVO[]> => {
|
||||
return request({
|
||||
url: '/notification/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 消息通知 已读
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const ReadNotificationByID = (id: string) => {
|
||||
return request({
|
||||
url: '/notification/read',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -12,7 +12,7 @@ export interface ParkingCostVO {
|
||||
/**
|
||||
* 车位id
|
||||
*/
|
||||
parkingId: string;
|
||||
parkingId: string | number;
|
||||
|
||||
/**
|
||||
* 收费项目 0临时停车
|
||||
@@ -79,7 +79,7 @@ export interface ParkingCostForm extends BaseEntity {
|
||||
/**
|
||||
* 车位id
|
||||
*/
|
||||
parkingId?: string;
|
||||
parkingId?: string | number;
|
||||
|
||||
/**
|
||||
* 收费项目 0临时停车
|
||||
@@ -141,7 +141,7 @@ export interface ParkingCostQuery extends PageQuery {
|
||||
/**
|
||||
* 车位id
|
||||
*/
|
||||
parkingId?: string;
|
||||
parkingId?: string | number;
|
||||
|
||||
/**
|
||||
* 收费项目 0临时停车
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取缴费方式,种类占比
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const income_statsApi = (
|
||||
datetime?: string
|
||||
): Promise<{
|
||||
'totalResident': number;
|
||||
'totalHouse': number;
|
||||
'totalParking': number;
|
||||
'totalDevice': number;
|
||||
'totalMaterial': number;
|
||||
'totalComplaint': number;
|
||||
}> => {
|
||||
return request({
|
||||
url: '/api/analysis/income/stats',
|
||||
method: 'get',
|
||||
params: {
|
||||
datetime: datetime
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 查询入住情况
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const user_movein_list = (query?: {
|
||||
datetime: string;
|
||||
}): Promise<{
|
||||
'totalResident': number;
|
||||
'totalHouse': number;
|
||||
'totalParking': number;
|
||||
'totalDevice': number;
|
||||
'totalMaterial': number;
|
||||
'totalComplaint': number;
|
||||
}> => {
|
||||
return request({
|
||||
url: '/workSpace/totalList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询居住人类型列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const get_movein_user_type = (query?: {
|
||||
datetime: string;
|
||||
}): Promise<{
|
||||
'owner': string;
|
||||
'ownerRate': string;
|
||||
'tenant': string;
|
||||
'tenantRate': string;
|
||||
'relatives': string;
|
||||
'relativeRate': string;
|
||||
'other': string;
|
||||
'otherRate': string;
|
||||
'totalResident': string;
|
||||
}> => {
|
||||
return request({
|
||||
url: '/residentType/selectTotal',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询住户性别比例
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const get_movein_user_sex = (query?: {
|
||||
datetime: string;
|
||||
}): Promise<{
|
||||
'man': number;
|
||||
'woman': number;
|
||||
'total': number;
|
||||
'manRate': string;
|
||||
'womanRate': string;
|
||||
}> => {
|
||||
return request({
|
||||
url: '/gender/overview',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取迁入迁出趋势图
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const get_movein_moveout_list = (query?: {
|
||||
datetime: string;
|
||||
}): Promise<
|
||||
{
|
||||
'date': string;
|
||||
'inCount': number;
|
||||
'outCount': number;
|
||||
}[]
|
||||
> => {
|
||||
return request({
|
||||
url: '/residentDailyStat/selectTotal',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
@@ -37,9 +37,7 @@ export interface QuestionnaireVO {
|
||||
/**
|
||||
* 部分业主串 ”,“号隔开
|
||||
*/
|
||||
residents: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
residents: string | number;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
@@ -71,7 +69,7 @@ export interface QuestionnaireForm extends BaseEntity {
|
||||
/**
|
||||
* 问卷题目结构(JSON数组)
|
||||
*/
|
||||
content?: string | QuestionComponentItem[];
|
||||
content?: string;
|
||||
|
||||
/**
|
||||
* 状态:0-草稿 1-已发布 2-已结束
|
||||
@@ -160,6 +158,6 @@ export interface QuestionComponentItem {
|
||||
export interface QuestionComponentnaireForm {
|
||||
id?: string | number | null;
|
||||
title: string;
|
||||
description?: string;
|
||||
description: string;
|
||||
content: QuestionComponentItem[];
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export interface RepairVO {
|
||||
/**
|
||||
* 报修人id(住户表id)
|
||||
*/
|
||||
residentId: string;
|
||||
residentId: string | number;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
@@ -57,7 +57,7 @@ export interface RepairVO {
|
||||
/**
|
||||
* 维修人员id
|
||||
*/
|
||||
repairId: string;
|
||||
repairId: string | number;
|
||||
/** 名称(小区名-楼栋名-单元号-房间号) */
|
||||
name?: string;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ export interface RepairForm extends BaseEntity {
|
||||
/**
|
||||
* 报修人id(住户表id)
|
||||
*/
|
||||
residentId?: string;
|
||||
residentId?: string | number;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
@@ -163,7 +163,7 @@ export interface RepairQuery extends PageQuery {
|
||||
/**
|
||||
* 报修人id(住户表id)
|
||||
*/
|
||||
residentId?: string;
|
||||
residentId?: string | number;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
|
||||
@@ -2,7 +2,7 @@ export interface RepairProjectVO {
|
||||
/**
|
||||
* 维修项目表id
|
||||
*/
|
||||
id: string;
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 维修项目名
|
||||
@@ -12,7 +12,7 @@ export interface RepairProjectVO {
|
||||
/**
|
||||
* 父级项目id
|
||||
*/
|
||||
parentId: string;
|
||||
parentId: string | number;
|
||||
|
||||
/**
|
||||
* 项目类型 0公共报修 1个人报修
|
||||
@@ -23,7 +23,7 @@ export interface RepairProjectVO {
|
||||
* 项目层级 0,1
|
||||
*/
|
||||
projectLevel: number;
|
||||
children?: [];
|
||||
|
||||
/**
|
||||
* 排序 (数越小越靠前)
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ export interface RepairProjectForm extends BaseEntity {
|
||||
/**
|
||||
* 维修项目表id
|
||||
*/
|
||||
id?: string;
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 维修项目名
|
||||
@@ -49,7 +49,7 @@ export interface RepairProjectForm extends BaseEntity {
|
||||
/**
|
||||
* 父级项目id
|
||||
*/
|
||||
parentId?: string;
|
||||
parentId?: string | number;
|
||||
|
||||
/**
|
||||
* 项目类型 0公共报修 1个人报修
|
||||
@@ -101,7 +101,7 @@ export interface RepairProjectQuery extends PageQuery {
|
||||
/**
|
||||
* 父级项目id
|
||||
*/
|
||||
parentId?: string;
|
||||
parentId?: string | number;
|
||||
|
||||
/**
|
||||
* 项目类型 0公共报修 1个人报修
|
||||
|
||||
@@ -62,10 +62,9 @@ export const delBill = (id: string | number | Array<string | number>) => {
|
||||
});
|
||||
};
|
||||
|
||||
// ! =---------------=================================== 组件
|
||||
export interface BillHouse {
|
||||
'buildingName': string;
|
||||
'houseId': string;
|
||||
'houseId': number;
|
||||
'unitNo': number;
|
||||
'houseNo': string;
|
||||
'floorNo': number;
|
||||
@@ -83,39 +82,3 @@ export const listBillHouse = (query: { pageNum: number; pageSize: number }): Axi
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
// ! =---------------
|
||||
export type BillUserlist = {
|
||||
'gender': string;
|
||||
'phone': string;
|
||||
'house_name': string;
|
||||
'residentName': string;
|
||||
'houseNo': string;
|
||||
'residentId': string;
|
||||
'buildingId': string;
|
||||
};
|
||||
/**
|
||||
* 查询业主列表
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
export const queryResidentList_holder = (query: { pageNum: number; pageSize: number }): AxiosPromise<BillUserlist[]> => {
|
||||
return request({
|
||||
url: '/bill/getResidentList',
|
||||
method: 'GET',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询车位业主列表
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
export const queryResidentList_Cars = (query: { pageNum: number; pageSize: number }): AxiosPromise<BillUserlist[]> => {
|
||||
return request({
|
||||
url: '/bill/getParkingList',
|
||||
method: 'GET',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ export interface BillVO {
|
||||
* 收费项目id
|
||||
*/
|
||||
chargeItemId: string;
|
||||
residentIds: string[];
|
||||
|
||||
/**
|
||||
* 收费范围 0全体业主 1部分业主
|
||||
@@ -118,8 +117,6 @@ export interface BillQuery extends PageQuery {
|
||||
*/
|
||||
chargeItemId?: string | number;
|
||||
|
||||
// type: string;
|
||||
|
||||
/**
|
||||
* 收费范围 0全体业主 1部分业主
|
||||
*/
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export type cashlist = {
|
||||
'residentId': string;
|
||||
'residentName': string;
|
||||
'houseName': string;
|
||||
'phone': string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询住户列表
|
||||
* @param post
|
||||
* @returns {*}
|
||||
*/
|
||||
export const cashQuery = (data: { residentName?: string; queryType: number }): AxiosPromise<cashlist[]> => {
|
||||
return request({
|
||||
url: '/cash/residentList',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
export type billlistType = {
|
||||
'villageId': string;
|
||||
'residentId': string;
|
||||
'houseId': string;
|
||||
'houseName': string;
|
||||
'parkingId': string;
|
||||
'parkingName': string;
|
||||
'billId': string;
|
||||
'chargeTypeName': string;
|
||||
'chargeItemName': string;
|
||||
'billingType': string;
|
||||
'formula': string;
|
||||
'fixedPrice': string;
|
||||
'startDate': string;
|
||||
'endDate': string;
|
||||
'money': string;
|
||||
'payStatus': string;
|
||||
amount: string;
|
||||
};
|
||||
/**
|
||||
* 查询账单列表
|
||||
* @param post
|
||||
* @returns {*}
|
||||
*/
|
||||
export const billQuery = (data: { residentId?: string; payStatus: '0' | '1' }): AxiosPromise<billlistType[]> => {
|
||||
return request({
|
||||
url: '/cash/billList',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const billEdit = (data: { 'detailsId': string[]; 'payType': string; 'payStatus': string }): AxiosPromise<billlistType[]> => {
|
||||
return request({
|
||||
url: '/cash/billEdit',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
@@ -8,7 +8,7 @@ import { ChargeItemVO, ChargeItemForm, ChargeItemQuery } from './type';
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listChargeItem = (query?: ChargeItemQuery | {}): AxiosPromise<ChargeItemVO[]> => {
|
||||
export const listChargeItem = (query?: ChargeItemQuery): AxiosPromise<ChargeItemVO[]> => {
|
||||
return request({
|
||||
url: '/chargeItem/list',
|
||||
method: 'get',
|
||||
|
||||
@@ -68,7 +68,7 @@ export const delElectricityDevice = (id: string | number | Array<string | number
|
||||
*/
|
||||
export const ElectricityDeviceMakerQrcode = (data: { deviceCode: string; id: string }[]) => {
|
||||
return request({
|
||||
url: '/electricityDevice/generateBarCode',
|
||||
url: '/electricityDevice/generateBarCodee',
|
||||
method: 'POST',
|
||||
data: data
|
||||
});
|
||||
|
||||
@@ -61,39 +61,3 @@ export const delTopupRecord = (id: string | number | Array<string | number>) =>
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
export type TopupRecordList = {
|
||||
'id': string;
|
||||
'rechargeTime': string;
|
||||
'villageName': string;
|
||||
'residentName': string;
|
||||
'houseName': string;
|
||||
'fixedPriceUnit': string;
|
||||
'fixedPrice': string;
|
||||
'unit': string;
|
||||
'deviceCode': string;
|
||||
'orderId': string;
|
||||
'rechargeAmount': string;
|
||||
'topUpType': string;
|
||||
};
|
||||
/** 查询所有设备充值记录 */
|
||||
export const getTopupRecordByDate = (query: {
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
pageSize: number;
|
||||
pageNum: number;
|
||||
}): AxiosPromise<TopupRecordList[]> => {
|
||||
return request({
|
||||
url: '/topupRecord/water/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/** 导出 所有设备的 充值记录 */
|
||||
export const exportTopupRecordByDate = (query: { startTime?: string; endTime?: string }): AxiosPromise<TopupRecordList[]> => {
|
||||
return request({
|
||||
url: '/topupRecord/water/export',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
@@ -96,14 +96,3 @@ export const WaterDeviceUpdateBin = (data: { deviceCodes: string[]; urlA: string
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取设备最新的抄表记录
|
||||
* @param deviceCodes
|
||||
*/
|
||||
export const latestRecord = (deviceCodes: string) => {
|
||||
return request({
|
||||
url: `/waterDevice/latestRecord/${deviceCodes}`,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ export interface WarehouseVO {
|
||||
/**
|
||||
* 仓库ID
|
||||
*/
|
||||
id: string;
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 仓库名称*
|
||||
@@ -12,7 +12,7 @@ export interface WarehouseVO {
|
||||
/**
|
||||
* 仓库归属id*(关联com_village)
|
||||
*/
|
||||
villageId: string;
|
||||
villageId: number;
|
||||
|
||||
/**
|
||||
* 联系人*
|
||||
@@ -44,7 +44,7 @@ export interface WarehouseForm extends BaseEntity {
|
||||
/**
|
||||
* 仓库ID
|
||||
*/
|
||||
id?: string;
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 仓库名称*
|
||||
|
||||
@@ -8,7 +8,7 @@ import { AreaVO, AreaForm, AreaQuery } from '@/api/system/carArea/type';
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listArea = (query: AreaQuery | {} = {}): AxiosPromise<AreaVO[]> => {
|
||||
export const listArea = (query?: AreaQuery): AxiosPromise<AreaVO[]> => {
|
||||
return request({
|
||||
url: '/area/list',
|
||||
method: 'get',
|
||||
|
||||
@@ -2,22 +2,22 @@ export interface CarVO {
|
||||
/**
|
||||
* 车辆管理表id
|
||||
*/
|
||||
id: string;
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 区域id
|
||||
*/
|
||||
areaId: string;
|
||||
areaId: string | number;
|
||||
|
||||
/**
|
||||
* 车位id
|
||||
*/
|
||||
parkingId: string;
|
||||
parkingId: string | number;
|
||||
|
||||
/**
|
||||
* 持有人id(住户表id)
|
||||
*/
|
||||
residentId: string;
|
||||
residentId: string | number;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface DeviceCategoryVO {
|
||||
/**
|
||||
* 状态 0正常 1停用
|
||||
*/
|
||||
status: number;
|
||||
status: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
@@ -34,7 +34,7 @@ export interface DeviceCategoryForm extends BaseEntity {
|
||||
/**
|
||||
* 状态 0正常 1停用
|
||||
*/
|
||||
status?: number;
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
@@ -51,7 +51,7 @@ export interface DeviceCategoryQuery extends PageQuery {
|
||||
/**
|
||||
* 状态 0正常 1停用
|
||||
*/
|
||||
status?: number;
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export interface DeviceVO {
|
||||
categoryName: string;
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
|
||||
@@ -5,19 +5,20 @@ import { addBuildingType, addHouseType, BuildingUnit, BuildingVo } from './type'
|
||||
// 楼栋---------------------------------------------------------------------------------------
|
||||
|
||||
/** 根据 小区id 和 类型 查询楼栋信息 */
|
||||
export function getBuildinglistAPI(): AxiosPromise<BuildingVo[]> {
|
||||
export function getBuildinglistAPI(buildingUse: string): AxiosPromise<BuildingVo[]> {
|
||||
return request({
|
||||
url: '/building/byVillage',
|
||||
method: 'get',
|
||||
params: {}
|
||||
params: {
|
||||
buildingUse: buildingUse
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 获取所有楼栋 */
|
||||
export function getBuildinglists(query = {}): AxiosPromise<BuildingVo[]> {
|
||||
export function getBuildinglists(): AxiosPromise<BuildingVo[]> {
|
||||
return request({
|
||||
url: '/building/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
/** 获取单一楼栋 */
|
||||
@@ -45,7 +46,7 @@ export function editBuildingApi(data: addBuildingType & { id: string }) {
|
||||
});
|
||||
}
|
||||
/** 删除楼栋 */
|
||||
export function deleteBuildingApi(id: string) {
|
||||
export function deleteBuildingApi(id: number) {
|
||||
return request({
|
||||
url: `/building/${id}`,
|
||||
method: 'DELETE'
|
||||
@@ -54,9 +55,9 @@ export function deleteBuildingApi(id: string) {
|
||||
|
||||
// 房屋----------------------------------------------------------------------------------------------
|
||||
/** 根据 楼栋id 查询房屋信息 */
|
||||
export function getHouselistAPI(buildingId: string, houseName: string = '', houseUseTypeId: string = ''): AxiosPromise<BuildingUnit> {
|
||||
export function getHouselistAPI(buildingId: string): AxiosPromise<BuildingUnit> {
|
||||
return request({
|
||||
url: `/house/groupByUnitTree/${buildingId}?houseName=${houseName}&houseUseTypeId=${houseUseTypeId}`,
|
||||
url: `/house/groupByUnitTree/${buildingId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -99,87 +100,3 @@ export function getVillageTree(id: string) {
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
|
||||
/** 根据小区id,获取当前小区的树状结构 */
|
||||
export function getHouseMain(id: string): Promise<Response> {
|
||||
return request({
|
||||
url: `/house/ByIdList?houseId=` + id,
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
code: number;
|
||||
data: Data;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
billResidentList: BillResidentList[];
|
||||
chargeItemList: string[];
|
||||
house: House;
|
||||
parking: Parking;
|
||||
residentList: ResidentList[];
|
||||
storeroom: Storeroom;
|
||||
}
|
||||
|
||||
export interface BillResidentList {
|
||||
billCode: string;
|
||||
billName: string;
|
||||
chargeItemId: string;
|
||||
chargeTypeName: string;
|
||||
money: string;
|
||||
payStatus: string;
|
||||
useCount: string;
|
||||
}
|
||||
|
||||
export interface House {
|
||||
buildingName: string;
|
||||
floorNo: number;
|
||||
houseArea: string;
|
||||
houseId: number;
|
||||
houseNo: string;
|
||||
houseType: string;
|
||||
internalArea: string;
|
||||
shareArea: string;
|
||||
unitNoName: string;
|
||||
villageName: string;
|
||||
}
|
||||
|
||||
export interface ResidentList {
|
||||
gender: string;
|
||||
ownerRelationship: string;
|
||||
phone: string;
|
||||
residentId: string;
|
||||
residentName: string;
|
||||
residentStatus: string;
|
||||
residentType: string;
|
||||
}
|
||||
|
||||
export interface Storeroom {
|
||||
buildingName: string;
|
||||
houseArea: string;
|
||||
internalArea: string;
|
||||
shareArea: string;
|
||||
storeroomId: number;
|
||||
storeroomNo: string;
|
||||
remark: string;
|
||||
unitNoId: string;
|
||||
unitNo: number;
|
||||
}
|
||||
|
||||
export interface Parking {
|
||||
'parkingArea': number;
|
||||
'areaName': string;
|
||||
'createTime': string;
|
||||
'parkingId': string;
|
||||
'parkingStatus': string;
|
||||
'remark': string;
|
||||
'parkingFloor': string;
|
||||
'type': string;
|
||||
'villageId': number;
|
||||
'parkingCode': string;
|
||||
'residentName': string;
|
||||
'residentId': string;
|
||||
'createName': string;
|
||||
}
|
||||
|
||||
@@ -47,15 +47,14 @@ export interface BuildingUnit {
|
||||
buildingId: number;
|
||||
buildingName: string;
|
||||
floorCount: number;
|
||||
unitCount: number;
|
||||
units: BuildingUnitlist[];
|
||||
}
|
||||
// 单元
|
||||
export interface BuildingUnitlist {
|
||||
floors: FloorsType[];
|
||||
unitNoName: string;
|
||||
unitNoId: string;
|
||||
unitNo: number;
|
||||
}
|
||||
|
||||
// 楼层
|
||||
export interface FloorsType {
|
||||
floorNo: string;
|
||||
@@ -81,14 +80,11 @@ export interface addHouseType {
|
||||
'houseId'?: string;
|
||||
'buildingId'?: string;
|
||||
'villageId'?: string;
|
||||
'houseUseTypeId': string;
|
||||
'unitNoId': string;
|
||||
'unitNo': string;
|
||||
'floorNo': string;
|
||||
'houseNo': string;
|
||||
'houseArea': string;
|
||||
'internalArea': string;
|
||||
'shareArea': string;
|
||||
'houseType': string;
|
||||
'storeroomId': string;
|
||||
'parkingId': string;
|
||||
}
|
||||
|
||||
@@ -81,9 +81,3 @@ export const uploadHouseImage = (formdata: FormData): AxiosPromise<uploadHouseIm
|
||||
data: formdata
|
||||
});
|
||||
};
|
||||
export const getHouseOwnUser = (houseId: string): AxiosPromise<uploadHouseImagetype> => {
|
||||
return request({
|
||||
url: `/houseRental/ownerName/${houseId}`,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ export interface HouseRentalVO {
|
||||
/**
|
||||
* id 房屋租赁表id
|
||||
*/
|
||||
id: string | number;
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 租户姓名
|
||||
@@ -109,7 +109,7 @@ export interface HouseRentalForm extends BaseEntity {
|
||||
/**
|
||||
* 0 整租 1 合租
|
||||
*/
|
||||
rentalType?: string;
|
||||
rentalType?: number;
|
||||
|
||||
/**
|
||||
* 房屋朝向
|
||||
@@ -171,7 +171,7 @@ export interface HouseRentalQuery extends PageQuery {
|
||||
/**
|
||||
* 房屋用途
|
||||
*/
|
||||
houseUse?: string;
|
||||
houseUse?: number;
|
||||
/**
|
||||
* 租户姓名
|
||||
*/
|
||||
@@ -185,7 +185,7 @@ export interface HouseRentalQuery extends PageQuery {
|
||||
/**
|
||||
* 0 整租 1 合租
|
||||
*/
|
||||
rentalType?: string;
|
||||
rentalType?: number;
|
||||
|
||||
/**
|
||||
* 房屋朝向
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { UnitNoVO, UnitNoForm, UnitNoQuery } from './type';
|
||||
|
||||
/**
|
||||
* 查询单元列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listUnitNo = (query?: UnitNoQuery): AxiosPromise<UnitNoVO[]> => {
|
||||
return request({
|
||||
url: '/unitNo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询单元详细
|
||||
* @param id
|
||||
*/
|
||||
export const getUnitNo = (id: string | number): AxiosPromise<UnitNoVO> => {
|
||||
return request({
|
||||
url: '/unitNo/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增单元
|
||||
* @param data
|
||||
*/
|
||||
export const addUnitNo = (data: UnitNoForm) => {
|
||||
return request({
|
||||
url: '/unitNo',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改单元
|
||||
* @param data
|
||||
*/
|
||||
export const updateUnitNo = (data: UnitNoForm) => {
|
||||
return request({
|
||||
url: '/unitNo',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除单元
|
||||
* @param id
|
||||
*/
|
||||
export const delUnitNo = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/unitNo/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 根据 楼栋id 获取单元
|
||||
* @param id
|
||||
*/
|
||||
export const getByBUildingidtoUnitNo = (id: string) => {
|
||||
return request({
|
||||
url: '/unitNo/byBuildingList',
|
||||
method: 'GET',
|
||||
params: {
|
||||
buildingId: id
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
export interface UnitNoVO {
|
||||
/**
|
||||
* 单元表id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 单元名称
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 小区id
|
||||
*/
|
||||
villageId: string | number;
|
||||
|
||||
/**
|
||||
* 楼栋id
|
||||
*/
|
||||
buildingId: string | number;
|
||||
}
|
||||
|
||||
export interface UnitNoForm extends BaseEntity {
|
||||
/**
|
||||
* 单元表id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 单元名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 小区id
|
||||
*/
|
||||
villageId?: string | number;
|
||||
|
||||
/**
|
||||
* 楼栋id
|
||||
*/
|
||||
buildingId?: string | number;
|
||||
}
|
||||
|
||||
export interface UnitNoQuery extends PageQuery {
|
||||
/**
|
||||
* 单元名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 小区id
|
||||
*/
|
||||
villageId?: string | number;
|
||||
|
||||
/**
|
||||
* 楼栋id
|
||||
*/
|
||||
buildingId?: string | number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { HouseUseTypeVO, HouseUseTypeForm, HouseUseTypeQuery } from './type';
|
||||
|
||||
/**
|
||||
* 查询房屋类型列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listHouseUseType = (query?: HouseUseTypeQuery): AxiosPromise<HouseUseTypeVO[]> => {
|
||||
return request({
|
||||
url: '/houseUseType/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
export const listHouseUseType_add_house = (query?: HouseUseTypeQuery): AxiosPromise<HouseUseTypeVO[]> => {
|
||||
return request({
|
||||
url: '/houseUseType/getList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询房屋类型详细
|
||||
* @param id
|
||||
*/
|
||||
export const getHouseUseType = (id: string | number): AxiosPromise<HouseUseTypeVO> => {
|
||||
return request({
|
||||
url: '/houseUseType/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增房屋类型
|
||||
* @param data
|
||||
*/
|
||||
export const addHouseUseType = (data: HouseUseTypeForm) => {
|
||||
return request({
|
||||
url: '/houseUseType',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改房屋类型
|
||||
* @param data
|
||||
*/
|
||||
export const updateHouseUseType = (data: HouseUseTypeForm) => {
|
||||
return request({
|
||||
url: '/houseUseType',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除房屋类型
|
||||
* @param id
|
||||
*/
|
||||
export const delHouseUseType = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/houseUseType/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
export interface HouseUseTypeVO {
|
||||
/**
|
||||
* 房屋类型id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 用途名称
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface HouseUseTypeForm extends BaseEntity {
|
||||
/**
|
||||
* 房屋类型id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 用途名称
|
||||
*/
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface HouseUseTypeQuery extends PageQuery {
|
||||
/**
|
||||
* 用途名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
@@ -61,43 +61,3 @@ export const delParking = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 改变车位审核装填
|
||||
* @param id
|
||||
*/
|
||||
export const getParkingReview = (data: { id: string; propertyReviewFeedback: string; propertyStatus: number }) => {
|
||||
return request({
|
||||
url: '/parkingReview/checkStatus',
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取车位审核信息
|
||||
* @param id
|
||||
*/
|
||||
export const getParkingReviewInfo = (id: string) => {
|
||||
return request({
|
||||
url: '/parking/checkInfo',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询小区内车位列表
|
||||
* @param { string } villageid
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const GetVillageListParking = (villageid: string, houseId: string = undefined): AxiosPromise<ParkingVO[]> => {
|
||||
return request({
|
||||
url: `/parking/getList`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
villageId: villageid,
|
||||
houseId: houseId
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface ParkingVO {
|
||||
/**
|
||||
* 住户id
|
||||
*/
|
||||
residentId: string;
|
||||
residentId: string | number;
|
||||
|
||||
/**
|
||||
* 添加时间
|
||||
@@ -88,7 +88,7 @@ export interface ParkingForm extends BaseEntity {
|
||||
/**
|
||||
* 住户id
|
||||
*/
|
||||
residentId?: string;
|
||||
residentId?: string | number;
|
||||
|
||||
/**
|
||||
* 添加时间
|
||||
@@ -160,7 +160,7 @@ export interface ParkingQuery extends PageQuery {
|
||||
/**
|
||||
* 住户id
|
||||
*/
|
||||
residentId?: string;
|
||||
residentId?: string | number;
|
||||
|
||||
/**
|
||||
* 添加时间
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface ResidentVO {
|
||||
/**
|
||||
* 0 男性 1女性
|
||||
*/
|
||||
gender: string;
|
||||
gender: number;
|
||||
|
||||
/**
|
||||
* 身份证号
|
||||
@@ -90,17 +90,14 @@ export interface ResidentForm extends BaseEntity {
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 0业主
|
||||
* 1亲属
|
||||
* 2租户
|
||||
* 3朋友
|
||||
* 0业主 1租户
|
||||
*/
|
||||
ownerRelationship?: string;
|
||||
type?: string;
|
||||
|
||||
/**
|
||||
* 0 男性 1女性
|
||||
*/
|
||||
gender?: string;
|
||||
gender?: number;
|
||||
|
||||
/**
|
||||
* 身份证号
|
||||
@@ -155,12 +152,10 @@ export interface ResidentQuery extends PageQuery {
|
||||
date?: any;
|
||||
|
||||
/**
|
||||
* 0业主
|
||||
* 1亲属
|
||||
* 2租户
|
||||
* 3朋友
|
||||
* 住户类型
|
||||
* 0业主 1租户
|
||||
*/
|
||||
ownerRelationship?: string;
|
||||
type?: string;
|
||||
/**
|
||||
* 住户状态
|
||||
* 0审核中 1 已认证
|
||||
@@ -170,5 +165,5 @@ export interface ResidentQuery extends PageQuery {
|
||||
houseId?: number;
|
||||
villageId?: string;
|
||||
buildingId?: number;
|
||||
unitNoId?: number;
|
||||
unitNo?: number;
|
||||
}
|
||||
|
||||
@@ -61,28 +61,3 @@ export const delStoreroom = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询小区内储藏室管理列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const GetVillagelistStoreroom = (
|
||||
data: { villageid: string; unitNoId: string; houseId?: string; buildingId: string } = {
|
||||
villageid: null,
|
||||
buildingId: null,
|
||||
houseId: null,
|
||||
unitNoId: null
|
||||
}
|
||||
): AxiosPromise<StoreroomVO[]> => {
|
||||
return request({
|
||||
url: `/storeroom/getList`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
villageId: data.villageid,
|
||||
buildingId: data.buildingId,
|
||||
unitNoId: data.unitNoId,
|
||||
houseId: data.houseId
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,18 +2,17 @@ export interface StoreroomVO {
|
||||
/**
|
||||
* 储藏室ID
|
||||
*/
|
||||
id: string;
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 所属楼栋ID
|
||||
*/
|
||||
buildingId: string;
|
||||
buildingId: string | number;
|
||||
|
||||
/**
|
||||
* 单元号
|
||||
*/
|
||||
unitNoId: string | number;
|
||||
unitName: string;
|
||||
unitNo: string | number;
|
||||
|
||||
/**
|
||||
* 储藏室号
|
||||
@@ -55,12 +54,12 @@ export interface StoreroomForm extends BaseEntity {
|
||||
/**
|
||||
* 储藏室ID
|
||||
*/
|
||||
id?: string;
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 所属楼栋ID
|
||||
*/
|
||||
buildingId?: string;
|
||||
buildingId?: string | number;
|
||||
|
||||
/**
|
||||
* 单元号
|
||||
@@ -107,7 +106,7 @@ export interface StoreroomQuery extends PageQuery {
|
||||
/**
|
||||
* 所属楼栋ID
|
||||
*/
|
||||
buildingId?: string;
|
||||
buildingId?: string | number;
|
||||
|
||||
/**
|
||||
* 单元号
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface UserQuery extends PageQuery {
|
||||
* 用户返回对象
|
||||
*/
|
||||
export interface UserVO extends BaseEntity {
|
||||
userId: string;
|
||||
userId: string | number;
|
||||
tenantId: string;
|
||||
deptId: number;
|
||||
userName: string;
|
||||
@@ -70,8 +70,8 @@ export interface UserForm {
|
||||
sex?: string;
|
||||
status: string;
|
||||
remark?: string;
|
||||
postIds?: string[];
|
||||
roleIds?: string[];
|
||||
postIds: string[];
|
||||
roleIds: string[];
|
||||
}
|
||||
|
||||
export interface UserInfoVO {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
export interface CategoryTreeVO {
|
||||
id: string;
|
||||
id: number | string;
|
||||
label: string;
|
||||
parentId: number | string;
|
||||
weight: number;
|
||||
categoryName: string;
|
||||
children: CategoryTreeVO[];
|
||||
}
|
||||
export interface CategoryVO {
|
||||
|
||||
@@ -12,8 +12,6 @@ export const workSpaceTotalListApi = (
|
||||
totalResident: number;
|
||||
totalHouse: number;
|
||||
totalParking: number;
|
||||
totalDevice: number;
|
||||
totalMaterial: number;
|
||||
totalComplaint: number;
|
||||
}> => {
|
||||
return request({
|
||||
@@ -24,300 +22,3 @@ export const workSpaceTotalListApi = (
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询近一周报修趋势
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const workSpaceRepairTrendListApi = (
|
||||
villageId: string
|
||||
): Promise<
|
||||
{
|
||||
date: string;
|
||||
count: number;
|
||||
}[]
|
||||
> => {
|
||||
return request({
|
||||
url: '/workSpace/last7DaysRepairCount',
|
||||
method: 'GET',
|
||||
params: {
|
||||
villageId: villageId
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询近一周收入趋势
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const workSpaceIncomeTrendListApi = (
|
||||
villageId: string,
|
||||
type: number
|
||||
): Promise<
|
||||
{
|
||||
date: string;
|
||||
income: number;
|
||||
}[]
|
||||
> => {
|
||||
return request({
|
||||
url: '/workSpace/last7DaysIncomeTrend',
|
||||
method: 'GET',
|
||||
params: {
|
||||
villageId: villageId,
|
||||
type: type
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询当日天气
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const workSpaceWeatherApi = (city: string): Promise<reponseType> => {
|
||||
const url = 'https://uapis.cn/api/v1/misc/weather?city=' + city + '&lang=zh';
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url, {
|
||||
method: 'GET'
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
type reponseType = {
|
||||
// 省份
|
||||
'province': string;
|
||||
// 城市名
|
||||
'city': string;
|
||||
// 区县或更细一级的行政区名称。自动按 IP 定位时更常见。
|
||||
'district': string;
|
||||
// 行政区划代码(部分数据源可能为空)
|
||||
'adcode': string;
|
||||
// 天气状况描述。默认返回中文,传 `lang=en` 时返回英文。非固定枚举。
|
||||
'weather': string;
|
||||
// 天气图标代码。请从[天气图标代码表](#enum-list)中查看所有可能的值。
|
||||
'weather_icon': string;
|
||||
// 当前温度 °C
|
||||
'temperature': number;
|
||||
// 风向
|
||||
'wind_direction': string;
|
||||
// 风力等级
|
||||
'wind_power': string;
|
||||
// 相对湿度 %
|
||||
'humidity': number;
|
||||
// 数据更新时间
|
||||
'report_time': string;
|
||||
// 体感温度 °C(extended=true 时返回)
|
||||
'feels_like': number;
|
||||
// 能见度 km(extended=true 时返回)
|
||||
'visibility': number;
|
||||
// 气压 hPa(extended=true 时返回)
|
||||
'pressure': number;
|
||||
// 紫外线指数(extended=true 时返回)
|
||||
'uv': number;
|
||||
// 当前降水量 mm(extended=true 时返回)
|
||||
'precipitation': number;
|
||||
// 云量 %(extended=true 时返回)
|
||||
'cloud': number;
|
||||
// 空气质量指数 0-500(extended=true 时返回)
|
||||
'aqi': number;
|
||||
// AQI 等级 1-6(extended=true 时返回)
|
||||
'aqi_level': number;
|
||||
// AQI 等级描述(优/良/轻度污染/中度污染/重度污染/严重污染)(extended=true 时返回)
|
||||
'aqi_category': string;
|
||||
// 主要污染物(如 PM2.5、PM10、O3 等)(extended=true 时返回)
|
||||
'aqi_primary': string;
|
||||
// 空气污染物分项数据(extended=true 时返回,部分数据源可能不返回)
|
||||
'air_pollutants': {
|
||||
// PM2.5 μg/m³
|
||||
'pm25': number;
|
||||
// PM10 μg/m³
|
||||
'pm10': number;
|
||||
// 臭氧 μg/m³
|
||||
'o3': number;
|
||||
// 二氧化氮 μg/m³
|
||||
'no2': number;
|
||||
// 二氧化硫 μg/m³
|
||||
'so2': number;
|
||||
// 一氧化碳 mg/m³
|
||||
'co': number;
|
||||
};
|
||||
// 官方气象预警列表(存在有效预警时返回)
|
||||
'alerts': {
|
||||
// 预警标题
|
||||
'title': string;
|
||||
// 预警类型,如雷电、暴雨
|
||||
'type': string;
|
||||
// 预警级别,如蓝色、黄色、橙色、红色
|
||||
'level': string;
|
||||
// 预警正文
|
||||
'text': string;
|
||||
// 预警发布时间
|
||||
'publish_time': string;
|
||||
// 发布单位
|
||||
'publisher': string;
|
||||
// 防御指引列表
|
||||
'guidance': string[];
|
||||
}[];
|
||||
// 当天最高温 °C(forecast=true 时返回)
|
||||
'temp_max': number;
|
||||
// 当天最低温 °C(forecast=true 时返回)
|
||||
'temp_min': number;
|
||||
// 多天天气预报,最多7天(forecast=true 时返回)
|
||||
'forecast': {
|
||||
// 日期 YYYY-MM-DD
|
||||
'date': string;
|
||||
// 星期几(`lang=en` 时返回英文星期)
|
||||
'week': string;
|
||||
// 最高温度 °C
|
||||
'temp_max': number;
|
||||
// 最低温度 °C
|
||||
'temp_min': number;
|
||||
// 白天天气(`lang=en` 时返回英文)
|
||||
'weather_day': string;
|
||||
// 夜间天气(`lang=en` 时返回英文)
|
||||
'weather_night': string;
|
||||
// 白天风向(可选,`lang=en` 时返回英文)
|
||||
'wind_dir_day': string;
|
||||
// 夜间风向(可选,`lang=en` 时返回英文)
|
||||
'wind_dir_night': string;
|
||||
// 白天风力(可选,`lang=en` 时返回英文)
|
||||
'wind_scale_day': string;
|
||||
// 夜间风力(可选,`lang=en` 时返回英文)
|
||||
'wind_scale_night': string;
|
||||
// 白天风速 km/h(可选)
|
||||
'wind_speed_day': number;
|
||||
// 湿度 %(可选)
|
||||
'humidity': number;
|
||||
// 降水量 mm(可选)
|
||||
'precip': number;
|
||||
// 能见度 km(可选)
|
||||
'visibility': number;
|
||||
// 紫外线指数(可选)
|
||||
'uv_index': number;
|
||||
// 日出时间 HH:MM(可选)
|
||||
'sunrise': string;
|
||||
// 日落时间 HH:MM(可选)
|
||||
'sunset': string;
|
||||
}[];
|
||||
// 逐小时预报,最多24小时(hourly=true 时返回)
|
||||
'hourly_forecast': {
|
||||
// 预报时间(ISO8601 或 YYYY-MM-DD HH:MM)
|
||||
'time': string;
|
||||
// 温度 °C
|
||||
'temperature': number;
|
||||
// 天气状况
|
||||
'weather': string;
|
||||
// 风向(可选)
|
||||
'wind_direction': string;
|
||||
// 风速 km/h(可选)
|
||||
'wind_speed': number;
|
||||
// 风力等级(可选)
|
||||
'wind_scale': string;
|
||||
// 湿度 %(可选)
|
||||
'humidity': number;
|
||||
// 降水量 mm(可选)
|
||||
'precip': number;
|
||||
// 体感温度 °C(可选)
|
||||
'feels_like': number;
|
||||
// 能见度 km(可选)
|
||||
'visibility': number;
|
||||
// 降水概率 %(可选)
|
||||
'pop': number;
|
||||
// 紫外线指数(可选,国内城市通常不返回)
|
||||
'uv_index': number;
|
||||
}[];
|
||||
// 分钟级降水预报(minutely=true 时返回,仅国内城市可用,精确到2分钟)
|
||||
'minutely_precip': {
|
||||
// 降水描述
|
||||
'summary': string;
|
||||
// 更新时间
|
||||
'update_time': string;
|
||||
// 精确到2分钟的数据点
|
||||
'data': {
|
||||
// 预报时间 ISO8601
|
||||
'time': string;
|
||||
// 该时间点的降水量 mm
|
||||
'precip': number;
|
||||
// 降水类型:rain / snow
|
||||
'type': string;
|
||||
}[];
|
||||
};
|
||||
// 18项生活指数(indices=true 时返回),每项包含 level(等级名称)、brief(简短描述)、advice(详细建议)
|
||||
'life_indices': LifeIndices;
|
||||
};
|
||||
|
||||
// 1. 定义单个生活指数的基础结构
|
||||
type LifeIndexItem = {
|
||||
level: string;
|
||||
brief: string;
|
||||
advice: string;
|
||||
};
|
||||
|
||||
// 2. 定义所有可能的键名
|
||||
type LifeIndexKeys =
|
||||
| 'clothing'
|
||||
| 'uv'
|
||||
| 'car_wash'
|
||||
| 'drying'
|
||||
| 'air_conditioner'
|
||||
| 'cold_risk'
|
||||
| 'exercise'
|
||||
| 'comfort'
|
||||
| 'travel'
|
||||
| 'fishing'
|
||||
| 'allergy'
|
||||
| 'sunscreen'
|
||||
| 'mood'
|
||||
| 'beer'
|
||||
| 'umbrella'
|
||||
| 'traffic'
|
||||
| 'air_purifier'
|
||||
| 'pollen';
|
||||
|
||||
// 3. 使用映射类型自动生成完整结构
|
||||
type LifeIndices = {
|
||||
[K in LifeIndexKeys]: LifeIndexItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询 快捷入口
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const getQuicklyshortcut = () => {
|
||||
return request({
|
||||
url: '/workSpace/shortcut/list',
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加 快捷入口
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const addQuicklyshortcut = (data) => {
|
||||
return request({
|
||||
url: '/workSpace/shortcut/add',
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除 快捷入口
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const delQuicklyshortcut = (id) => {
|
||||
return request({
|
||||
url: '/workSpace/shortcut/remove/' + id,
|
||||
method: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ export interface FlowInstanceQuery extends PageQuery {
|
||||
nodeName?: string;
|
||||
flowCode?: string;
|
||||
flowName?: string;
|
||||
createByIds?: string[];
|
||||
createByIds?: string[] | number[];
|
||||
businessId?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ html.dark svg {
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
min-width: 1024px; /* 最小宽度,防止太小变形 */
|
||||
min-width: 1200px; /* 最小宽度,防止太小变形 */
|
||||
}
|
||||
|
||||
*,
|
||||
@@ -255,35 +255,3 @@ aside {
|
||||
width: 960px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.bgColor {
|
||||
width: 850px;
|
||||
height: 850px;
|
||||
background: #fdf1ee;
|
||||
filter: blur(200px);
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translateY(-50%) translateX(0%);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
border-radius: 50%;
|
||||
|
||||
@media (max-width: 1540px) {
|
||||
width: 800px;
|
||||
height: 400px;
|
||||
}
|
||||
@media (max-width: 1280px) {
|
||||
width: 600px;
|
||||
height: 300px;
|
||||
}
|
||||
@media (max-width: 1030px) {
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
background: var(--el-bg-color-page);
|
||||
background: #dfedff;
|
||||
}
|
||||
|
||||
.sidebarHide {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
// Modern rounded style + soft shadows
|
||||
--app-radius-sm: 6px;
|
||||
--app-radius-md: 5px;
|
||||
--app-radius-md: 10px;
|
||||
--app-radius-lg: 14px;
|
||||
--app-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.08), 0 6px 16px rgba(15, 23, 42, 0.08);
|
||||
--app-shadow-md: 0 8px 24px rgba(15, 23, 42, 0.12);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta?.title }}</span>
|
||||
<span class="no-redirect" v-else>{{ item.meta?.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
<template>
|
||||
<slot name="default" />
|
||||
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050">
|
||||
<el-table ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" width="55" type="index" />
|
||||
<el-table-column label="业主" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.residentName ? scope.row.residentName : '---' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="性别" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_user_sex" :value="scope.row.gender"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" align="center" prop="phone" />
|
||||
<el-table-column label="车位" align="center" prop="parkingName" />
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer flex flex-items-center flex-justify-between">
|
||||
<pagination
|
||||
style="margin-top: 0"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getlist"
|
||||
/>
|
||||
<div>
|
||||
<el-button @click="conback">退出</el-button>
|
||||
<el-button type="primary" @click="confirm"> 确定 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
|
||||
import { BillUserlist, queryResidentList_Cars, queryResidentList_holder } from '@/api/system/SdbBill';
|
||||
import { ref, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
|
||||
|
||||
const props = defineProps({
|
||||
returnvalue: {
|
||||
type: String,
|
||||
default: 'parkingId'
|
||||
},
|
||||
titleName: {
|
||||
type: String,
|
||||
default: '选择业主'
|
||||
},
|
||||
/** 是否多选 false 单选 */
|
||||
isMultiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const { titleName, returnvalue } = toRefs(props);
|
||||
|
||||
const userid = ref([]);
|
||||
// ✅ 手动设置默认值(替代 withDefaults)
|
||||
const emit = defineEmits<{
|
||||
change: [value: string | number | (string | number)[] | BillUserlist | BillUserlist[]]; // 支持返回数组
|
||||
}>();
|
||||
|
||||
const dialog = ref({
|
||||
dialogVisible: false,
|
||||
dialogTitle: titleName.value
|
||||
});
|
||||
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
const multipleTableRef = ref();
|
||||
const tableData = ref<BillUserlist[]>([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const isFetching = ref(false);
|
||||
// 存储选中项
|
||||
const multipleSelection = ref<BillUserlist[]>([]);
|
||||
|
||||
const isMultiple = computed(() => props.isMultiple ?? false);
|
||||
|
||||
// 优化 handleUserSelection,避免重复查找
|
||||
const handleUserSelection = () => {
|
||||
isFetching.value = true;
|
||||
if (!multipleTableRef.value || !tableData.value.length) {
|
||||
isFetching.value = false;
|
||||
return;
|
||||
}
|
||||
const rowsToSelect = tableData.value.filter((row) => {
|
||||
return multipleSelection.value.some((selected) => selected.parkingId === row.parkingId);
|
||||
});
|
||||
multipleTableRef.value.clearSelection();
|
||||
if (rowsToSelect.length > 0) {
|
||||
nextTick(() => {
|
||||
rowsToSelect.forEach((row) => {
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
});
|
||||
isFetching.value = false;
|
||||
});
|
||||
} else {
|
||||
isFetching.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== 方法 ======================
|
||||
|
||||
// 获取列表
|
||||
function getlist() {
|
||||
isFetching.value = true; // 加锁
|
||||
loading.value = true;
|
||||
queryResidentList_Cars(queryParams.value)
|
||||
.then((res) => {
|
||||
tableData.value = res.rows;
|
||||
total.value = res.total;
|
||||
handleUserSelection();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取用户列表失败:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
isFetching.value = false; // 加锁
|
||||
});
|
||||
}
|
||||
|
||||
/** 楼栋列表 */
|
||||
const buildinglist = ref([]);
|
||||
/** 房屋列表 */
|
||||
const unitlist = ref([]);
|
||||
|
||||
/** 筛选房屋类型 */
|
||||
function handleChangeHouse(val: string) {
|
||||
getBuildinglistAPI().then((res) => {
|
||||
buildinglist.value = res.data;
|
||||
});
|
||||
}
|
||||
/** 单元列表 */
|
||||
function handleChangebuilding(val: string) {
|
||||
getHouselistAPI(val).then((res) => {
|
||||
unitlist.value = res.data.units;
|
||||
});
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 新增:处理 selection-change(多选专用)
|
||||
// ==============================================
|
||||
function handleSelectionChange(selection: BillUserlist[]) {
|
||||
if (isFetching.value) return;
|
||||
if (isMultiple.value) {
|
||||
const currentSelectedIds = new Set(selection.map((item) => item.parkingId));
|
||||
const otherPageSelections = multipleSelection.value.filter((item) => {
|
||||
const isCurrentPageItem = tableData.value.some((row) => row.parkingId === item.parkingId);
|
||||
if (isCurrentPageItem) {
|
||||
return currentSelectedIds.has(item.parkingId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 3. 合并:其他页保留的 + 当前页新选中的
|
||||
const finalSelection = [...otherPageSelections, ...selection];
|
||||
// 4. 去重(以防万一)
|
||||
const uniqueMap = new Map();
|
||||
finalSelection.forEach((item) => uniqueMap.set(item.parkingId, item));
|
||||
multipleSelection.value = Array.from(uniqueMap.values());
|
||||
console.log(multipleSelection.value.map((item) => item.parkingId));
|
||||
} else {
|
||||
// --- 单选逻辑 ---
|
||||
if (selection.length > 0) {
|
||||
multipleSelection.value = [selection[selection.length - 1]];
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==============================================
|
||||
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
|
||||
// ==============================================
|
||||
// 优化 handleRowClick,避免重复
|
||||
function handleRowClick(row: BillUserlist) {
|
||||
if (!multipleTableRef.value) return;
|
||||
|
||||
if (isMultiple.value) {
|
||||
const index = multipleSelection.value.findIndex((item) => item.parkingId === row.parkingId);
|
||||
if (index > -1) {
|
||||
// 取消选中
|
||||
multipleSelection.value.splice(index, 1);
|
||||
multipleTableRef.value?.toggleRowSelection(row, false);
|
||||
} else {
|
||||
// 选中
|
||||
multipleSelection.value.push(row);
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
}
|
||||
} else {
|
||||
// 【单选模式】先清空,再选中当前行
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
multipleSelection.value = [row];
|
||||
multipleTableRef.value.toggleRowSelection(row, true);
|
||||
}
|
||||
}
|
||||
// 重置查询
|
||||
function resetQuery() {
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
};
|
||||
getlist();
|
||||
}
|
||||
|
||||
// 退出
|
||||
function conback() {
|
||||
dialog.value.dialogVisible = false;
|
||||
resetQuery();
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 核心修改:根据 returnvalue 返回对应的值
|
||||
// ==============================================
|
||||
function confirm() {
|
||||
dialog.value.dialogVisible = false;
|
||||
if (isMultiple.value) {
|
||||
// 多选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象数组
|
||||
emit('change', multipleSelection.value);
|
||||
} else {
|
||||
// 返回指定字段数组
|
||||
emit(
|
||||
'change',
|
||||
multipleSelection.value.map((item) => item[returnvalue.value as keyof BillUserlist])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 单选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象
|
||||
emit('change', multipleSelection.value[0]);
|
||||
} else {
|
||||
// 返回指定字段
|
||||
emit('change', multipleSelection.value[0][returnvalue.value as keyof BillUserlist]);
|
||||
}
|
||||
}
|
||||
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open: (arr: string[] = []) => {
|
||||
userid.value = arr;
|
||||
if (arr && arr.length > 0) {
|
||||
multipleSelection.value = arr.map((id) => ({
|
||||
parkingId: id
|
||||
}));
|
||||
console.log(multipleSelection.value);
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
getlist();
|
||||
dialog.value.dialogVisible = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.residentBox {
|
||||
width: 385px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 0 10px;
|
||||
.defaultbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f4f8ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,68 +1,46 @@
|
||||
<template>
|
||||
<slot name="default" />
|
||||
|
||||
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1400">
|
||||
<nav class="flex flex-items-center mb-8 justify-between">
|
||||
<!-- <div class="flex flex-items-center">
|
||||
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050">
|
||||
<nav class="flex flex-items-center mb-8">
|
||||
<div class="flex flex-items-center">
|
||||
<div style="width: 70px; text-align: right; padding-right: 10px">房屋类型</div>
|
||||
<div class="flex-1">
|
||||
<el-select @change="handleChangeHouse" style="width: 140px" v-model="queryParams.houseUseTypeId">
|
||||
<el-option v-for="(item, index) in houseUseTypeList" :key="index" :label="item.name" :value="item.id"></el-option>
|
||||
<el-select @change="handleChangeHouse" style="width: 140px" v-model="queryParams.buildingUse">
|
||||
<el-option v-for="(item, index) in com_build_use" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="flex flex-items-center">
|
||||
<div class="flex flex-items-center">
|
||||
<div style="width: 50px; text-align: right; padding-right: 10px">楼栋</div>
|
||||
<div class="flex-1"></div>
|
||||
<el-select @change="handleChangebuilding" clearable style="width: 120px" v-model="queryParams.buildingId">
|
||||
<el-option v-for="(item, index) in buildinglist" :key="index" :label="item.buildingName" :value="item.id"></el-option>
|
||||
<div style="width: 60px; text-align: right; padding-right: 10px">楼栋</div>
|
||||
<div class="flex-1"></div>
|
||||
<el-select @change="handleChangebuilding" style="width: 140px" v-model="queryParams.buildingId">
|
||||
<el-option v-for="(item, index) in buildinglist" :key="index" :label="item.buildingName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="flex flex-items-center mr-20px">
|
||||
<div style="width: 60px; text-align: right; padding-right: 10px">单元</div>
|
||||
<div class="flex-1">
|
||||
<el-select style="width: 140px" v-model="queryParams.unitNo">
|
||||
<el-option v-for="(item, index) in unitlist" :key="index" :label="`${item.unitNo}单元`" :value="item.unitNo"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="flex flex-items-center mr-20px">
|
||||
<div style="width: 50px; text-align: right; padding-right: 10px">单元</div>
|
||||
<div class="flex-1">
|
||||
<el-select @change="handleChangeUnit" clearable style="width: 120px" v-model="queryParams.unitNoId">
|
||||
<el-option v-for="(item, index) in unitlist" :key="index" :label="item.unitNoName" :value="item.unitNoId"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-items-center mr-20px">
|
||||
<div style="width: 80px; text-align: right; padding-right: 10px">房屋类型</div>
|
||||
<div class="flex-1">
|
||||
<el-select clearable @change="handleHouseUseChange" style="width: 120px" v-model="queryParams.houseUseTypeId">
|
||||
<el-option v-for="(item, index) in houseUseTypeList" :key="index" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-items-center mr-20px">
|
||||
<div style="width: 60px; text-align: right; padding-right: 10px">房屋号</div>
|
||||
<div class="flex-1">
|
||||
<el-input clearable @clear="handleClear" style="width: 120px" v-model="queryParams.houseNo" placeholder="请输入房屋号"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-items-center mr-20px">
|
||||
<div style="width: 80px; text-align: right; padding-right: 10px">业主名称</div>
|
||||
<div class="flex-1">
|
||||
<el-input clearable @clear="handleClear" style="width: 120px" v-model="queryParams.residentName" placeholder="请输入业主名称"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="getlist">查询</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
</nav>
|
||||
<el-table row-key="houseId" v-loading="loading" ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<el-table @row-click="handleRowClick" ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" width="55" type="index" />
|
||||
<el-table-column label="小区" align="center" prop="villageName" />
|
||||
<el-table-column label="楼栋" align="center" prop="buildingName" />
|
||||
<el-table-column label="单元" align="center" prop="unitNoName" />
|
||||
<el-table-column label="单元" align="center" prop="unitNo" />
|
||||
<el-table-column label="房间" align="center" prop="houseNo" />
|
||||
<el-table-column label="业主" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.residentName ? scope.row.residentName : '---' }}</span>
|
||||
<span>{{ scope.row.userName ? scope.row.userName : '---' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -88,15 +66,18 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getBuildinglistAPI, getBuildingOnly, getHouselistAPI } from '@/api/system/house';
|
||||
import { listHouseUseType, listHouseUseType_add_house } from '@/api/system/houseUse';
|
||||
import { BillHouse, listBillHouse } from '@/api/system/SdbBill';
|
||||
import { ref, watch, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
|
||||
|
||||
// const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
|
||||
// const { com_build_use } = toRefs<any>(proxy?.useDict('com_build_use'));
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
|
||||
const { com_build_use } = toRefs<any>(proxy?.useDict('com_build_use'));
|
||||
|
||||
const props = defineProps({
|
||||
userid: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
returnvalue: {
|
||||
type: String,
|
||||
default: 'houseId'
|
||||
@@ -112,9 +93,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const { titleName, returnvalue } = toRefs(props);
|
||||
|
||||
const showids = ref([]);
|
||||
const { userid, titleName, returnvalue } = toRefs(props);
|
||||
|
||||
// ✅ 手动设置默认值(替代 withDefaults)
|
||||
const emit = defineEmits<{
|
||||
@@ -129,11 +108,9 @@ const dialog = ref({
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
houseNo: '',
|
||||
buildingUse: null,
|
||||
buildingId: null,
|
||||
unitNoId: null,
|
||||
houseUseTypeId: null,
|
||||
residentName: ''
|
||||
unitNo: null
|
||||
});
|
||||
|
||||
const multipleTableRef = ref();
|
||||
@@ -148,35 +125,30 @@ const isMultiple = computed(() => props.isMultiple ?? false);
|
||||
|
||||
// 优化 handleUserSelection,避免重复查找
|
||||
const handleUserSelection = () => {
|
||||
isFetching.value = true;
|
||||
if (!multipleTableRef.value || !tableData.value.length) {
|
||||
isFetching.value = false;
|
||||
return;
|
||||
}
|
||||
// 1. 获取当前页所有行的 houseId 集合,用于快速判断
|
||||
// const currentPageIds = new Set(tableData.value.map((item) => item.houseId));
|
||||
const rowsToSelect = tableData.value.filter((row) => {
|
||||
return multipleSelection.value.some((selected) => selected.houseId === row.houseId);
|
||||
});
|
||||
multipleTableRef.value.clearSelection();
|
||||
if (rowsToSelect.length > 0) {
|
||||
nextTick(() => {
|
||||
rowsToSelect.forEach((row) => {
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
});
|
||||
isFetching.value = false;
|
||||
if (!userid.value || !tableData.value.length) return;
|
||||
|
||||
multipleSelection.value = [];
|
||||
if (userid.value.trim() !== '') {
|
||||
const arr = userid.value.split(',');
|
||||
arr.forEach((item) => {
|
||||
const target = tableData.value.find((row) => row.userId == item);
|
||||
target && multipleSelection.value.push(target);
|
||||
});
|
||||
nextTick(() => {
|
||||
if (multipleTableRef.value) {
|
||||
multipleTableRef.value.clearSelection();
|
||||
multipleSelection.value.forEach((item) => {
|
||||
multipleTableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isFetching.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== 方法 ======================
|
||||
const houseUseTypeList = ref([]);
|
||||
const isFetching = ref(false);
|
||||
|
||||
// 获取列表
|
||||
function getlist() {
|
||||
isFetching.value = true; // 🔒 加锁:禁止 selection-change 更新数据
|
||||
loading.value = true;
|
||||
listBillHouse(queryParams.value)
|
||||
.then((res) => {
|
||||
@@ -185,11 +157,10 @@ function getlist() {
|
||||
handleUserSelection();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取列表失败:', error);
|
||||
console.error('获取用户列表失败:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
isFetching.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -198,72 +169,51 @@ const buildinglist = ref([]);
|
||||
/** 房屋列表 */
|
||||
const unitlist = ref([]);
|
||||
|
||||
/** 获取楼栋 列表 */
|
||||
function handleChangeHouse() {
|
||||
getBuildinglistAPI().then((res) => {
|
||||
/** 筛选房屋类型 */
|
||||
function handleChangeHouse(val: string) {
|
||||
getBuildinglistAPI(val).then((res) => {
|
||||
buildinglist.value = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
queryParams.value.residentName = '';
|
||||
getlist();
|
||||
}
|
||||
function handleHouseUseChange() {
|
||||
getlist();
|
||||
}
|
||||
/** 单元列表 */
|
||||
function handleChangebuilding(val: string) {
|
||||
queryParams.value.unitNoId = null;
|
||||
unitlist.value = [];
|
||||
|
||||
if (queryParams.value.buildingId) {
|
||||
getHouselistAPI(val).then((res) => {
|
||||
unitlist.value = res.data.units;
|
||||
getlist();
|
||||
});
|
||||
}
|
||||
getlist();
|
||||
}
|
||||
function handleChangeUnit() {
|
||||
getlist();
|
||||
getHouselistAPI(val).then((res) => {
|
||||
unitlist.value = res.data.units;
|
||||
});
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 新增:处理 selection-change(多选专用)
|
||||
// ==============================================
|
||||
function handleSelectionChange(selection: BillHouse[]) {
|
||||
// 🛑 如果正在获取数据/恢复状态,直接返回,不要更新 multipleSelection
|
||||
if (isFetching.value) return;
|
||||
if (isMultiple.value) {
|
||||
// 1. 获取当前表格中所有选中行的 ID
|
||||
const currentSelectedIds = new Set(selection.map((item) => item.houseId));
|
||||
const otherPageSelections = multipleSelection.value.filter((item) => {
|
||||
// 判断 item 是否属于当前页
|
||||
const isCurrentPageItem = tableData.value.some((row) => row.houseId === item.houseId);
|
||||
if (isCurrentPageItem) {
|
||||
// 如果是当前页的数据,检查是否在当前 selection 中
|
||||
return currentSelectedIds.has(item.houseId);
|
||||
} else {
|
||||
// 如果不是当前页的数据,保留(假设是之前页选的)
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 去重合并
|
||||
const finalSelection = [...otherPageSelections, ...selection];
|
||||
// 再次去重以防万一
|
||||
const uniqueMap = new Map();
|
||||
finalSelection.forEach((item) => uniqueMap.set(item.houseId, item));
|
||||
multipleSelection.value = Array.from(uniqueMap.values());
|
||||
console.log(multipleSelection.value.map((item) => item.houseId));
|
||||
} else {
|
||||
// ✅ 补充:单选模式下,selection-change 触发时,直接取最新的一项
|
||||
// 这样配合 handleRowClick 的 clearSelection + toggle 就能实现完美单选
|
||||
if (selection.length > 0) {
|
||||
multipleSelection.value = [selection[selection.length - 1]];
|
||||
multipleSelection.value = selection;
|
||||
}
|
||||
}
|
||||
// ==============================================
|
||||
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
|
||||
// ==============================================
|
||||
// 优化 handleRowClick,避免重复
|
||||
function handleRowClick(row: BillHouse) {
|
||||
if (!multipleTableRef.value) return;
|
||||
|
||||
if (isMultiple.value) {
|
||||
const index = multipleSelection.value.findIndex((item) => item.houseId === row.houseId);
|
||||
if (index > -1) {
|
||||
// 取消选中
|
||||
multipleSelection.value.splice(index, 1);
|
||||
multipleTableRef.value?.toggleRowSelection(row, false);
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
// 选中
|
||||
multipleSelection.value.push(row);
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
}
|
||||
} else {
|
||||
// 【单选模式】先清空,再选中当前行
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
multipleSelection.value = [row];
|
||||
multipleTableRef.value.toggleRowSelection(row, true);
|
||||
}
|
||||
}
|
||||
// 重置查询
|
||||
@@ -271,11 +221,9 @@ function resetQuery() {
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
houseUseTypeId: null,
|
||||
houseuse: null,
|
||||
buildingId: null,
|
||||
unitNoId: null,
|
||||
houseNo: '',
|
||||
residentName: ''
|
||||
unitNo: null
|
||||
};
|
||||
getlist();
|
||||
}
|
||||
@@ -319,23 +267,9 @@ function confirm() {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open: (showidArray: string[] = []) => {
|
||||
multipleSelection.value = [];
|
||||
showids.value = showidArray;
|
||||
if (showidArray && showidArray.length > 0) {
|
||||
multipleSelection.value = showidArray.map(
|
||||
(id) =>
|
||||
({
|
||||
houseId: id
|
||||
}) as BillHouse
|
||||
);
|
||||
}
|
||||
open: () => {
|
||||
getlist();
|
||||
dialog.value.dialogVisible = true;
|
||||
listHouseUseType_add_house().then((res) => {
|
||||
houseUseTypeList.value = res.data;
|
||||
});
|
||||
handleChangeHouse();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<el-table ref="multipleTableRef" row-key="id" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<!-- 关键:去掉 @selection-change,改用 row-click 实现单选,永不报错! -->
|
||||
<el-table ref="multipleTableRef" :data="tableData" border @row-click="handleRowClick" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" width="55" type="index" />
|
||||
<el-table-column label="姓名" align="center" prop="name" />
|
||||
@@ -37,11 +38,6 @@
|
||||
<dict-tag :options="com_resident_type" :value="row.type" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="与业主关系" align="center" width="95" prop="ownerRelationship">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="com_resident_relationship" :value="row.ownerRelationship" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" width="85" prop="status">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="com_certification_status" :value="row.status" />
|
||||
@@ -115,7 +111,7 @@ const props = defineProps<{
|
||||
|
||||
// ✅ 手动设置默认值(替代 withDefaults)
|
||||
const isMultiple = computed(() => props.isMultiple ?? false);
|
||||
const returnvalue = computed(() => props.returnvalue ?? '*'); // 👈 默认 userId
|
||||
const returnvalue = computed(() => props.returnvalue ?? 'id'); // 👈 默认 userId
|
||||
|
||||
const { userid } = toRefs(props);
|
||||
|
||||
@@ -144,68 +140,50 @@ const total = ref(0);
|
||||
const loading = ref(false);
|
||||
|
||||
// ==============================================
|
||||
// ✅ 优化:处理 selection-change
|
||||
// ✅ 新增:处理 selection-change(多选专用)
|
||||
// ==============================================
|
||||
function handleSelectionChange(selection: tableType[]) {
|
||||
if (isMultiple.value) {
|
||||
// 多选逻辑:合并当前页选中项和之前页选中项
|
||||
const currentSelectedIds = new Set(selection.map((item) => item.id));
|
||||
|
||||
// 过滤掉当前页未选中的旧数据
|
||||
const otherPageSelections = multipleSelection.value.filter((item) => {
|
||||
const isCurrentPageItem = tableData.value.some((row) => row.id === item.id);
|
||||
if (isCurrentPageItem) {
|
||||
return currentSelectedIds.has(item.id);
|
||||
}
|
||||
return true; // 保留其他页的数据
|
||||
});
|
||||
|
||||
// 合并当前页新选中的数据
|
||||
const finalSelection = [...otherPageSelections, ...selection];
|
||||
|
||||
// 去重
|
||||
const uniqueMap = new Map();
|
||||
finalSelection.forEach((item) => uniqueMap.set(item.id, item));
|
||||
multipleSelection.value = Array.from(uniqueMap.values());
|
||||
} else {
|
||||
// 单选逻辑:始终只保留最后一个选中的项
|
||||
if (selection.length > 0) {
|
||||
// 获取最后选中的那一项
|
||||
const lastSelected = selection[selection.length - 1];
|
||||
multipleSelection.value = [lastSelected];
|
||||
|
||||
// 关键:如果 selection 长度大于1(比如之前选了一个,现在又选一个,el-table可能暂时上报两个),
|
||||
// 我们需要手动清除表格中其他的勾选状态,只保留最后一个
|
||||
nextTick(() => {
|
||||
if (selection.length > 1) {
|
||||
multipleTableRef.value?.clearSelection();
|
||||
multipleTableRef.value?.toggleRowSelection(lastSelected, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
multipleSelection.value = selection;
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 优化:回显逻辑
|
||||
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
|
||||
// ==============================================
|
||||
function handleRowClick(row) {
|
||||
if (isMultiple.value) {
|
||||
// 多选:点击行切换选中状态
|
||||
const isSelected = multipleSelection.value.some((item) => item.id === row.id);
|
||||
if (isSelected) {
|
||||
multipleSelection.value = multipleSelection.value.filter((item) => item.id !== row.id);
|
||||
multipleTableRef.value?.toggleRowSelection(row, false);
|
||||
} else {
|
||||
multipleSelection.value.push(row);
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
}
|
||||
} else {
|
||||
// 单选:原有逻辑保持不变
|
||||
multipleTableRef.value?.clearSelection();
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
multipleSelection.value = [row];
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 修改:支持多选回显
|
||||
// ==============================================
|
||||
const handleUserSelection = () => {
|
||||
if (!multipleTableRef.value) return;
|
||||
|
||||
// 先清空所有选择
|
||||
multipleTableRef.value.clearSelection();
|
||||
multipleSelection.value = [];
|
||||
|
||||
if (!props.userid && props.userid !== 0) return;
|
||||
if (!userid.value || !tableData.value.length) return;
|
||||
|
||||
nextTick(() => {
|
||||
if (isMultiple.value && Array.isArray(props.userid)) {
|
||||
multipleTableRef.value?.clearSelection();
|
||||
|
||||
if (isMultiple.value && Array.isArray(userid.value)) {
|
||||
// 多选回显
|
||||
const selectedItems: tableType[] = [];
|
||||
props.userid.forEach((id) => {
|
||||
const findItem = tableData.value.find((item) => item.id == id || item.userId == id);
|
||||
userid.value.forEach((id) => {
|
||||
const findItem = tableData.value.find((item) => item.userId == id);
|
||||
if (findItem) {
|
||||
selectedItems.push(findItem);
|
||||
multipleTableRef.value?.toggleRowSelection(findItem, true);
|
||||
@@ -213,45 +191,38 @@ const handleUserSelection = () => {
|
||||
});
|
||||
multipleSelection.value = selectedItems;
|
||||
} else {
|
||||
// 单选回显
|
||||
// 注意:props.userid 可能是单个 ID
|
||||
const targetId = Array.isArray(props.userid) ? props.userid[0] : props.userid;
|
||||
const findItem = tableData.value.find((item) => item.id == targetId || item.userId == targetId);
|
||||
|
||||
// 单选回显(原有逻辑)
|
||||
const findItem = tableData.value.find((item) => item.id == userid.value);
|
||||
if (findItem) {
|
||||
multipleTableRef.value?.toggleRowSelection(findItem, true);
|
||||
multipleSelection.value = [findItem];
|
||||
multipleTableRef.value?.toggleRowSelection(findItem, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
watch(userid, handleUserSelection, { immediate: true });
|
||||
watch(tableData, handleUserSelection);
|
||||
|
||||
// 打开选择框
|
||||
function choiceResidentFun() {
|
||||
// 初始化
|
||||
getlist();
|
||||
dialog.value.dialogVisible = true;
|
||||
}
|
||||
|
||||
// 获取列表
|
||||
function getlist() {
|
||||
console.log('getlist');
|
||||
console.log(props.isMultiple);
|
||||
loading.value = true;
|
||||
listResident(queryParams.value)
|
||||
.then((res) => {
|
||||
tableData.value = res.rows;
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.houseId !== null) {
|
||||
const houselist = getHousePathById(treedata.value, item.houseId, 'label');
|
||||
item.housePath = houselist?.join('-') || '';
|
||||
}
|
||||
});
|
||||
handleUserSelection();
|
||||
total.value = res.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
listResident(queryParams.value).then((res) => {
|
||||
tableData.value = res.rows;
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.houseId !== null) {
|
||||
const houselist = getHousePathById(treedata.value, item.houseId, 'label');
|
||||
item.housePath = houselist?.join('-') || '';
|
||||
}
|
||||
});
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
@@ -297,7 +268,6 @@ function confirm() {
|
||||
}
|
||||
} else {
|
||||
// 单选
|
||||
console.log(multipleSelection.value[0], multipleSelection.value);
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象
|
||||
emit('change', multipleSelection.value[0]);
|
||||
@@ -306,22 +276,13 @@ function confirm() {
|
||||
emit('change', multipleSelection.value[0][returnvalue.value as keyof tableType]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emit('change', null);
|
||||
}
|
||||
}
|
||||
// 初始化
|
||||
getlist();
|
||||
|
||||
defineExpose({
|
||||
open: (arr) => {
|
||||
if (arr && arr.length > 0) {
|
||||
multipleSelection.value = arr.map((id) => ({
|
||||
id: id
|
||||
}));
|
||||
console.log(multipleSelection.value);
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
getlist();
|
||||
open: () => {
|
||||
dialog.value.dialogVisible = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<slot v-if="$slots.default" />
|
||||
|
||||
<div v-else class="residentBox" @click="choiceResidentFun">
|
||||
<div class="defaultbox" v-if="multipleSelection.length === 0 || props.username === ''">
|
||||
<div class="defaultbox" v-if="multipleSelection.length === 0">
|
||||
<span>请选择</span>
|
||||
<el-icon><Search /></el-icon>
|
||||
</div>
|
||||
<div v-else class="overflow-auto overflow-hidden w-full text-ellipsis text-nowrap">
|
||||
<span>姓名:{{ multipleSelection[0]?.name ?? props.username }}</span>
|
||||
<span>姓名:{{ multipleSelection[0]?.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,10 +80,6 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
username: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
returnvalue: {
|
||||
type: String,
|
||||
default: 'id'
|
||||
@@ -164,7 +160,6 @@ const handleUserSelection = () => {
|
||||
// 打开选择框
|
||||
function choiceResidentFun() {
|
||||
dialog.value.dialogVisible = true;
|
||||
handleUserSelection();
|
||||
}
|
||||
|
||||
// 获取列表
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
<template>
|
||||
<slot name="default" />
|
||||
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050">
|
||||
<el-table ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" width="55" type="index" />
|
||||
<el-table-column label="业主" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.residentName ? scope.row.residentName : '---' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="性别" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_user_sex" :value="scope.row.gender"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" align="center" prop="phone" />
|
||||
<el-table-column label="房屋" align="center" prop="house_name" />
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer flex flex-items-center flex-justify-between">
|
||||
<pagination
|
||||
style="margin-top: 0"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getlist"
|
||||
/>
|
||||
<div>
|
||||
<el-button @click="conback">退出</el-button>
|
||||
<el-button type="primary" @click="confirm"> 确定 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
|
||||
import { BillUserlist, queryResidentList_holder } from '@/api/system/SdbBill';
|
||||
import { ref, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
|
||||
|
||||
const props = defineProps({
|
||||
returnvalue: {
|
||||
type: String,
|
||||
default: 'residentId'
|
||||
},
|
||||
titleName: {
|
||||
type: String,
|
||||
default: '选择业主'
|
||||
},
|
||||
/** 是否多选 false 单选 */
|
||||
isMultiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const { titleName, returnvalue } = toRefs(props);
|
||||
|
||||
const userid = ref([]);
|
||||
// ✅ 手动设置默认值(替代 withDefaults)
|
||||
const emit = defineEmits<{
|
||||
change: [value: string | number | (string | number)[] | BillUserlist | BillUserlist[]]; // 支持返回数组
|
||||
}>();
|
||||
|
||||
const dialog = ref({
|
||||
dialogVisible: false,
|
||||
dialogTitle: titleName.value
|
||||
});
|
||||
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
const multipleTableRef = ref();
|
||||
const tableData = ref<BillUserlist[]>([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const isFetching = ref(false);
|
||||
// 存储选中项
|
||||
const multipleSelection = ref<BillUserlist[]>([]);
|
||||
|
||||
const isMultiple = computed(() => props.isMultiple ?? false);
|
||||
|
||||
// 优化 handleUserSelection,避免重复查找
|
||||
const handleUserSelection = () => {
|
||||
isFetching.value = true;
|
||||
if (!multipleTableRef.value || !tableData.value.length) {
|
||||
isFetching.value = false;
|
||||
return;
|
||||
}
|
||||
const rowsToSelect = tableData.value.filter((row) => {
|
||||
return multipleSelection.value.some((selected) => selected.residentId === row.residentId);
|
||||
});
|
||||
multipleTableRef.value.clearSelection();
|
||||
if (rowsToSelect.length > 0) {
|
||||
nextTick(() => {
|
||||
rowsToSelect.forEach((row) => {
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
});
|
||||
isFetching.value = false;
|
||||
});
|
||||
} else {
|
||||
isFetching.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== 方法 ======================
|
||||
|
||||
// 获取列表
|
||||
function getlist() {
|
||||
isFetching.value = true; // 加锁
|
||||
loading.value = true;
|
||||
queryResidentList_holder(queryParams.value)
|
||||
.then((res) => {
|
||||
tableData.value = res.rows;
|
||||
total.value = res.total;
|
||||
handleUserSelection();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取用户列表失败:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
isFetching.value = false; // 加锁
|
||||
});
|
||||
}
|
||||
|
||||
/** 楼栋列表 */
|
||||
const buildinglist = ref([]);
|
||||
/** 房屋列表 */
|
||||
const unitlist = ref([]);
|
||||
|
||||
/** 筛选房屋类型 */
|
||||
function handleChangeHouse(val: string) {
|
||||
getBuildinglistAPI().then((res) => {
|
||||
buildinglist.value = res.data;
|
||||
});
|
||||
}
|
||||
/** 单元列表 */
|
||||
function handleChangebuilding(val: string) {
|
||||
getHouselistAPI(val).then((res) => {
|
||||
unitlist.value = res.data.units;
|
||||
});
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 新增:处理 selection-change(多选专用)
|
||||
// ==============================================
|
||||
function handleSelectionChange(selection: BillUserlist[]) {
|
||||
if (isFetching.value) return;
|
||||
if (isMultiple.value) {
|
||||
const currentSelectedIds = new Set(selection.map((item) => item.residentId));
|
||||
const otherPageSelections = multipleSelection.value.filter((item) => {
|
||||
const isCurrentPageItem = tableData.value.some((row) => row.residentId === item.residentId);
|
||||
if (isCurrentPageItem) {
|
||||
return currentSelectedIds.has(item.residentId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 3. 合并:其他页保留的 + 当前页新选中的
|
||||
const finalSelection = [...otherPageSelections, ...selection];
|
||||
// 4. 去重(以防万一)
|
||||
const uniqueMap = new Map();
|
||||
finalSelection.forEach((item) => uniqueMap.set(item.residentId, item));
|
||||
multipleSelection.value = Array.from(uniqueMap.values());
|
||||
console.log(multipleSelection.value.map((item) => item.residentId));
|
||||
} else {
|
||||
// --- 单选逻辑 ---
|
||||
if (selection.length > 0) {
|
||||
multipleSelection.value = [selection[selection.length - 1]];
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==============================================
|
||||
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
|
||||
// ==============================================
|
||||
// 优化 handleRowClick,避免重复
|
||||
function handleRowClick(row: BillUserlist) {
|
||||
if (!multipleTableRef.value) return;
|
||||
|
||||
if (isMultiple.value) {
|
||||
const index = multipleSelection.value.findIndex((item) => item.residentId === row.residentId);
|
||||
if (index > -1) {
|
||||
// 取消选中
|
||||
multipleSelection.value.splice(index, 1);
|
||||
multipleTableRef.value?.toggleRowSelection(row, false);
|
||||
} else {
|
||||
// 选中
|
||||
multipleSelection.value.push(row);
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
}
|
||||
} else {
|
||||
// 【单选模式】先清空,再选中当前行
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
multipleSelection.value = [row];
|
||||
multipleTableRef.value.toggleRowSelection(row, true);
|
||||
}
|
||||
}
|
||||
// 重置查询
|
||||
function resetQuery() {
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
};
|
||||
getlist();
|
||||
}
|
||||
|
||||
// 退出
|
||||
function conback() {
|
||||
dialog.value.dialogVisible = false;
|
||||
resetQuery();
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 核心修改:根据 returnvalue 返回对应的值
|
||||
// ==============================================
|
||||
function confirm() {
|
||||
dialog.value.dialogVisible = false;
|
||||
if (isMultiple.value) {
|
||||
// 多选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象数组
|
||||
emit('change', multipleSelection.value);
|
||||
} else {
|
||||
// 返回指定字段数组
|
||||
emit(
|
||||
'change',
|
||||
multipleSelection.value.map((item) => item[returnvalue.value as keyof BillUserlist])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 单选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象
|
||||
emit('change', multipleSelection.value[0]);
|
||||
} else {
|
||||
// 返回指定字段
|
||||
emit('change', multipleSelection.value[0][returnvalue.value as keyof BillUserlist]);
|
||||
}
|
||||
}
|
||||
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open: (arr: string[] = []) => {
|
||||
userid.value = arr;
|
||||
if (arr && arr.length > 0) {
|
||||
multipleSelection.value = arr.map(
|
||||
(id) =>
|
||||
({
|
||||
residentId: id
|
||||
}) as BillUserlist
|
||||
);
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
|
||||
getlist();
|
||||
dialog.value.dialogVisible = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.residentBox {
|
||||
width: 385px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 0 10px;
|
||||
.defaultbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f4f8ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,287 +0,0 @@
|
||||
<template>
|
||||
<div class="license-plate-input">
|
||||
<div class="plate_line">
|
||||
<div
|
||||
v-for="(item, index) in chars"
|
||||
:key="index"
|
||||
class="plate-item"
|
||||
:class="{
|
||||
active: activeIndex === index,
|
||||
disabled: disabled,
|
||||
error: hasError
|
||||
}"
|
||||
>
|
||||
<input
|
||||
ref="inputRefs"
|
||||
v-model="chars[index]"
|
||||
type="text"
|
||||
maxlength="1"
|
||||
:disabled="disabled"
|
||||
@input="onInput(index)"
|
||||
@keydown="onKeydown($event, index)"
|
||||
@paste="onPaste"
|
||||
@focus="activeIndex = index"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 错误提示(和 Element Plus 原生完全一致) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { LicensePlateValidator } from '@/utils/Reg';
|
||||
import { ref, watch, nextTick } from 'vue';
|
||||
|
||||
const PROVINCES = [
|
||||
'京',
|
||||
'津',
|
||||
'沪',
|
||||
'渝',
|
||||
'冀',
|
||||
'豫',
|
||||
'云',
|
||||
'辽',
|
||||
'黑',
|
||||
'湘',
|
||||
'皖',
|
||||
'鲁',
|
||||
'新',
|
||||
'苏',
|
||||
'浙',
|
||||
'赣',
|
||||
'鄂',
|
||||
'桂',
|
||||
'甘',
|
||||
'晋',
|
||||
'蒙',
|
||||
'陕',
|
||||
'吉',
|
||||
'闽',
|
||||
'贵',
|
||||
'粤',
|
||||
'青',
|
||||
'藏',
|
||||
'川',
|
||||
'宁',
|
||||
'琼'
|
||||
];
|
||||
const VALID_CHARS = /^[A-HJ-NP-Z0-9]$/i;
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string];
|
||||
'change': [value: string];
|
||||
}>();
|
||||
|
||||
const inputRefs = ref<HTMLInputElement[]>([]);
|
||||
const activeIndex = ref(-1);
|
||||
const chars = ref<string[]>(Array(8).fill(''));
|
||||
const hasError = ref(false);
|
||||
const errorMessage = ref('');
|
||||
|
||||
// 外部值同步
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
const currentValue = chars.value.join('').trim();
|
||||
if (val !== currentValue) {
|
||||
const newChars = Array(8).fill('');
|
||||
if (val) {
|
||||
val
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.forEach((c, i) => {
|
||||
if (i < 8) newChars[i] = c;
|
||||
});
|
||||
}
|
||||
chars.value = newChars;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 内部值同步到外部
|
||||
watch(
|
||||
chars,
|
||||
() => {
|
||||
const value = chars.value.join('').trim();
|
||||
emit('update:modelValue', value);
|
||||
emit('change', value);
|
||||
// 输入时清除错误
|
||||
clearError();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function onInput(index: number) {
|
||||
const char = chars.value[index].toUpperCase();
|
||||
|
||||
if (index === 0 && !PROVINCES.includes(char)) {
|
||||
chars.value[index] = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (index > 0 && !VALID_CHARS.test(char)) {
|
||||
chars.value[index] = '';
|
||||
return;
|
||||
}
|
||||
|
||||
chars.value[index] = char;
|
||||
|
||||
if (char && index < 7) {
|
||||
nextTick(() => inputRefs.value[index + 1]?.focus());
|
||||
}
|
||||
}
|
||||
|
||||
function onKeydown(e: KeyboardEvent, index: number) {
|
||||
if (e.key === 'Backspace' && !chars.value[index] && index > 0) {
|
||||
e.preventDefault();
|
||||
nextTick(() => {
|
||||
inputRefs.value[index - 1]?.focus();
|
||||
inputRefs.value[index - 1]?.select();
|
||||
});
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowLeft' && index > 0) {
|
||||
e.preventDefault();
|
||||
inputRefs.value[index - 1]?.focus();
|
||||
}
|
||||
if (e.key === 'ArrowRight' && index < 7) {
|
||||
e.preventDefault();
|
||||
inputRefs.value[index + 1]?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function onPaste(e: ClipboardEvent) {
|
||||
e.preventDefault();
|
||||
const text = e.clipboardData?.getData('text')?.trim().toUpperCase() || '';
|
||||
if (!text) return;
|
||||
|
||||
const newChars = Array(8).fill('');
|
||||
text.split('').forEach((c, i) => {
|
||||
if (i >= 8) return;
|
||||
if (i === 0 && PROVINCES.includes(c)) newChars[i] = c;
|
||||
if (i > 0 && VALID_CHARS.test(c)) newChars[i] = c;
|
||||
});
|
||||
|
||||
chars.value = newChars;
|
||||
|
||||
const lastIndex = Math.min(text.length - 1, 6);
|
||||
nextTick(() => inputRefs.value[lastIndex + 1]?.focus());
|
||||
}
|
||||
|
||||
function onBlur() {
|
||||
setTimeout(() => {
|
||||
const hasFocus = inputRefs.value.some((input) => document.activeElement === input);
|
||||
if (!hasFocus) {
|
||||
activeIndex.value = -1;
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
// ✅ 手动验证方法(核心)
|
||||
function validate(): { valid: boolean; message?: string } {
|
||||
const value = chars.value.join('').trim();
|
||||
|
||||
// 必填验证
|
||||
if (props.required && !value) {
|
||||
hasError.value = true;
|
||||
errorMessage.value = '请输入车牌号';
|
||||
return { valid: false, message: errorMessage.value };
|
||||
}
|
||||
|
||||
// 格式验证
|
||||
if (value && !isValidPlate(value)) {
|
||||
hasError.value = true;
|
||||
errorMessage.value = '请输入正确的车牌号格式';
|
||||
return { valid: false, message: errorMessage.value };
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
clearError();
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
// 车牌格式验证(内置,不依赖外部工具)
|
||||
function isValidPlate(plate: string): boolean {
|
||||
return LicensePlateValidator.isValidPlate(plate);
|
||||
}
|
||||
|
||||
// 清除错误
|
||||
function clearError() {
|
||||
hasError.value = false;
|
||||
errorMessage.value = '';
|
||||
}
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
focus: () => nextTick(() => inputRefs.value[0]?.focus()),
|
||||
clear: () => {
|
||||
chars.value = Array(8).fill('');
|
||||
},
|
||||
validate,
|
||||
clearError
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.license-plate-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.plate_line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.plate-item {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.plate-item.active {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
.plate-item.error {
|
||||
border-color: #f56c6c;
|
||||
}
|
||||
|
||||
.plate-item.disabled {
|
||||
background-color: #f5f7fa;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.plate-item input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.plate-error {
|
||||
color: #f56c6c;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -22,7 +22,7 @@ const props = defineProps({
|
||||
total: propTypes.number,
|
||||
page: propTypes.number.def(1),
|
||||
limit: propTypes.number.def(20),
|
||||
pageSizes: { type: Array<number>, default: () => [10, 20, 30, 50, 100] },
|
||||
pageSizes: { type: Array<number>, default: () => [10, 20, 30, 50] },
|
||||
// 移动端页码按钮的数量端默认值5
|
||||
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
|
||||
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
|
||||
import UserSelect from '@/components/UserSelect/index.vue';
|
||||
import UserSelect from '@/components/UserSelect';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { getTask, taskOperation, currentTaskAllUser, terminationTask } from '@/api/workflow/task';
|
||||
const props = defineProps({
|
||||
@@ -91,9 +91,7 @@ const task = ref<FlowTaskVO>({
|
||||
nodeRatio: undefined,
|
||||
version: undefined,
|
||||
applyNode: undefined,
|
||||
buttonList: [],
|
||||
businessCode: '',
|
||||
businessTitle: ''
|
||||
buttonList: []
|
||||
});
|
||||
|
||||
const open = (taskId: string) => {
|
||||
|
||||
@@ -152,7 +152,7 @@ import {
|
||||
currentTaskAllUser,
|
||||
getNextNodeList
|
||||
} from '@/api/workflow/task';
|
||||
import UserSelect from '@/components/UserSelect/index.vue';
|
||||
import UserSelect from '@/components/UserSelect';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { FlowCopyVo, FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
<template>
|
||||
<div class="top-right-btn" :style="style">
|
||||
<div class="flex items-center">
|
||||
<!-- 添加按钮 -->
|
||||
<el-button :disabled="props.disableAdd" v-if="props.showAdd" icon="Plus" type="primary" @click="toggleSearch()"> 新建 </el-button>
|
||||
|
||||
<!-- 批量操作下拉框 -->
|
||||
<el-dropdown v-if="props.showDelete || props.showEdit || $slots.dropdown" trigger="click" style="margin-left: 10px">
|
||||
<el-button @click.stop="refresh"> {{ props.moreTitle }} </el-button>
|
||||
|
||||
<!-- 👇 核心:优先使用外部插槽,没有则使用默认内容 -->
|
||||
<template #dropdown>
|
||||
<!-- 这里直接渲染,不嵌套插槽 -->
|
||||
<el-dropdown-menu v-if="!$slots.dropdown">
|
||||
<el-dropdown-item :disabled="props.disableEdit" v-if="props.showEdit" @click="emits('update:edit')"> 编辑 </el-dropdown-item>
|
||||
<el-dropdown-item :disabled="props.disableDelete" v-if="props.showDelete" @click="emits('update:delete')"> 批量删除 </el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
<!-- 外部自定义内容直接渲染,不包任何多余标签 -->
|
||||
<template v-else>
|
||||
<slot name="dropdown" />
|
||||
</template>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<!-- 显隐列(保留你原有逻辑) -->
|
||||
<el-row>
|
||||
<el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
|
||||
<el-button circle icon="Search" @click="toggleSearch()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
||||
<el-button circle icon="Refresh" @click="refresh()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="columns" class="item" effect="dark" content="显示/隐藏列" placement="top">
|
||||
<div class="show-btn">
|
||||
<el-popover placement="bottom" trigger="click">
|
||||
@@ -32,7 +16,7 @@
|
||||
:data="columns"
|
||||
show-checkbox
|
||||
node-key="key"
|
||||
:props="{ label: 'label', children: 'children' }"
|
||||
:props="{ label: 'label', children: 'children' } as any"
|
||||
@check="columnChange"
|
||||
></el-tree>
|
||||
<template #reference>
|
||||
@@ -41,77 +25,65 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import { CSSProperties } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
showSearch: propTypes.bool.def(true),
|
||||
columns: propTypes.fieldOption,
|
||||
gutter: propTypes.number.def(10),
|
||||
moreTitle: propTypes.string.def('批量操作'),
|
||||
|
||||
showAdd: propTypes.bool.def(true),
|
||||
showDelete: propTypes.bool.def(true),
|
||||
showEdit: propTypes.bool.def(true),
|
||||
|
||||
disableAdd: propTypes.bool.def(false),
|
||||
disableDelete: propTypes.bool.def(false),
|
||||
disableEdit: propTypes.bool.def(false)
|
||||
search: propTypes.bool.def(true),
|
||||
gutter: propTypes.number.def(10)
|
||||
});
|
||||
|
||||
const columnRef = ref();
|
||||
const emits = defineEmits(['update:add', 'update:edit', 'update:delete']);
|
||||
const columnRef = ref<ElTreeInstance>();
|
||||
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
||||
|
||||
const style = computed<CSSProperties>(() => {
|
||||
const ret: CSSProperties = {};
|
||||
const style = computed(() => {
|
||||
const ret: any = {};
|
||||
if (props.gutter) {
|
||||
ret.marginRight = `${props.gutter / 2}px`;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
// 添加
|
||||
// 搜索
|
||||
function toggleSearch() {
|
||||
emits('update:add');
|
||||
emits('update:showSearch', !props.showSearch);
|
||||
}
|
||||
|
||||
const isExpent = ref(false);
|
||||
// 批量操作展开
|
||||
// 刷新
|
||||
function refresh() {
|
||||
isExpent.value = !isExpent.value;
|
||||
emits('queryTable');
|
||||
}
|
||||
|
||||
// 更改显示隐藏列
|
||||
function columnChange(...args) {
|
||||
// 更改数据列的显示和隐藏
|
||||
function columnChange(...args: any[]) {
|
||||
props.columns?.forEach((item) => {
|
||||
item.visible = args[1].checkedKeys.includes(item.key);
|
||||
});
|
||||
}
|
||||
|
||||
// 显隐列初始默认隐藏列
|
||||
onMounted(() => {
|
||||
props.columns?.forEach((item) => {
|
||||
if (item.visible) {
|
||||
columnRef.value?.setChecked(item.key, true, false);
|
||||
// value.value.push(item.key);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hiddenActions {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-transfer__button) {
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
:deep(.el-transfer__button:first-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -119,13 +91,11 @@ onMounted(() => {
|
||||
.my-el-transfer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tree-header {
|
||||
width: 100%;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.show-btn {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" @submit.prevent="handleQuery">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="角色名称" prop="roleName">
|
||||
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@@ -13,8 +13,8 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" @submit.prevent="handleQuery" :model="queryParams" :inline="true">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="用户名称" prop="userName">
|
||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@@ -32,8 +32,8 @@
|
||||
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="() => resetQuery()">重置</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="() => resetQuery()">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<div style="background-color: #f2f1f6; height: 100%">
|
||||
<router-view v-slot="{ Component, route }" :key="$route.fullPath">
|
||||
<transition :enter-active-class="animate" mode="out-in">
|
||||
<keep-alive :include="tagsViewStore.cachedViews">
|
||||
<component :is="Component" v-if="!route.meta.link" :key="route.path" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<iframe-toggle />
|
||||
</div>
|
||||
<router-view v-slot="{ Component, route }" :key="$route.fullPath">
|
||||
<transition :enter-active-class="animate" mode="out-in">
|
||||
<keep-alive :include="tagsViewStore.cachedViews">
|
||||
<component :is="Component" v-if="!route.meta.link" :key="route.path" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<iframe-toggle />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -56,14 +54,13 @@ function addIframe() {
|
||||
<style lang="scss" scoped>
|
||||
.app-main {
|
||||
/* 50= navbar 50 */
|
||||
// min-height: calc(100vh - 50px);
|
||||
min-height: calc(100vh - 50px);
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: #f2f1f6;
|
||||
background-color: #dfedff;
|
||||
}
|
||||
|
||||
.fixed-header + .app-main {
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
@toggle-click="toggleSideBar"
|
||||
>
|
||||
</hamburger>
|
||||
<div class="flex-1 h-full"></div>
|
||||
<div class="right-menu flex align-center">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||
<div>
|
||||
<el-popover placement="bottom-end" trigger="click" transition="el-zoom-in-top" :width="400" :persistent="false">
|
||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||
<template #reference>
|
||||
<el-badge :value="newNotice > 0 ? newNotice : ''" :max="99">
|
||||
<div class="right-menu-item hover-effect" style="display: block"><svg-icon icon-class="message" /></div>
|
||||
@@ -37,7 +36,7 @@
|
||||
<el-dropdown-item divided command="changecommunity">
|
||||
<span>{{ proxy.$t('navbar.community') }}</span>
|
||||
</el-dropdown-item>
|
||||
<router-link to="/system/user/profile">
|
||||
<router-link to="/user/profile">
|
||||
<el-dropdown-item>{{ proxy.$t('navbar.personalCenter') }}</el-dropdown-item>
|
||||
</router-link>
|
||||
<el-dropdown-item divided command="logout">
|
||||
@@ -52,7 +51,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import hamburger from '@/components/Hamburger/index.vue';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
@@ -61,13 +59,6 @@ import notice from './notice/index.vue';
|
||||
import router from '@/router';
|
||||
import { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type';
|
||||
|
||||
const props = defineProps({
|
||||
Showhamburger: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
@@ -80,7 +71,13 @@ const navType = computed(() => settingsStore.navType);
|
||||
|
||||
// 是否切换了租户
|
||||
const dynamic = ref(true);
|
||||
|
||||
const props = defineProps({
|
||||
Showhamburger: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
console.log(props.Showhamburger);
|
||||
const toggleSideBar = () => {
|
||||
appStore.toggleSideBar(false);
|
||||
};
|
||||
@@ -150,6 +147,10 @@ watch(
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
align-items: center;
|
||||
}
|
||||
@@ -158,32 +159,42 @@ watch(
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
// background: #1a75ff;
|
||||
background: #dfedff;
|
||||
background: transparent;
|
||||
// border-bottom: 1px solid #1a75ff;
|
||||
border-bottom: 1px solid #dfedff;
|
||||
|
||||
color: #fff;
|
||||
color: #c0c4cc;
|
||||
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
// padding: 0 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
//float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
|
||||
&:hover {
|
||||
background: #fafafa52;
|
||||
background: var(--el-fill-color-lighter);
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
//float: left;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.topmenu-container {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
@@ -204,10 +215,13 @@ watch(
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
//float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
@@ -225,6 +239,10 @@ watch(
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
|
||||
// &:hover {
|
||||
// background: var(--el-fill-color-lighter);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +251,6 @@ watch(
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-top: 5px;
|
||||
// margin-left: 20px;
|
||||
position: relative;
|
||||
|
||||
.user-avatar {
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<el-divider />
|
||||
|
||||
<el-button type="primary" plain icon="DocumentAdd" @click="saveSetting">保存配置</el-button>
|
||||
<el-button plain @click="resetSetting">重置配置</el-button>
|
||||
<el-button plain icon="Refresh" @click="resetSetting">重置配置</el-button>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
@@ -161,15 +161,15 @@ const toggleDark = () => useToggle(isDark);
|
||||
|
||||
/** 菜单导航设置 */
|
||||
watch(
|
||||
navType,
|
||||
() => navType,
|
||||
(val: string) => {
|
||||
if (val === NavTypeEnum.TOP) {
|
||||
if (val.value === NavTypeEnum.TOP) {
|
||||
appStore.toggleSideBarHide(true);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any);
|
||||
} else if (val === NavTypeEnum.LEFT) {
|
||||
} else if (val.value === NavTypeEnum.LEFT) {
|
||||
appStore.toggleSideBarHide(false);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any);
|
||||
} else if (val === NavTypeEnum.MIX) {
|
||||
} else if (val.value === NavTypeEnum.MIX) {
|
||||
appStore.toggleSideBarHide(false);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@ const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
|
||||
// 获取Logo背景色
|
||||
const getLogoBackground = computed(() => {
|
||||
if (settingsStore.dark) {
|
||||
if (settingsStore.isDark) {
|
||||
return 'var(--sidebar-bg)';
|
||||
}
|
||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
||||
@@ -47,7 +47,7 @@ const getLogoBackground = computed(() => {
|
||||
|
||||
// 获取Logo文字颜色
|
||||
const getLogoTextColor = computed(() => {
|
||||
if (settingsStore.dark) {
|
||||
if (settingsStore.isDark) {
|
||||
return 'var(--sidebar-text)';
|
||||
}
|
||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
||||
|
||||
@@ -50,8 +50,7 @@ const activeMenu = computed(() => {
|
||||
}
|
||||
return path;
|
||||
});
|
||||
// const bgColor = '#eaf2ff';
|
||||
const bgColor = '#dfedff';
|
||||
const bgColor = '#eaf2ff';
|
||||
// const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground));
|
||||
const textColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor));
|
||||
</script>
|
||||
|
||||
@@ -72,10 +72,10 @@ const init = async () => {
|
||||
}
|
||||
|
||||
const data: LoginData = {
|
||||
// socialCode: code,
|
||||
// socialState: state,
|
||||
socialCode: code,
|
||||
socialState: state,
|
||||
tenantId: tenantId,
|
||||
// source: source,
|
||||
source: source,
|
||||
clientId: import.meta.env.VITE_APP_CLIENT_ID,
|
||||
grantType: 'social'
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useTagsViewStore } from '@/store/modules/tagsView';
|
||||
const tagAndTagSpacing = ref(4);
|
||||
|
||||
const scrollContainerRef = ref<ElScrollbarInstance>();
|
||||
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as HTMLElement);
|
||||
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef);
|
||||
|
||||
onMounted(() => {
|
||||
scrollWrapper.value?.addEventListener('scroll', emitScroll, true);
|
||||
|
||||
@@ -12,58 +12,58 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import SidebarItem from '../Sidebar/SidebarItem';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
import { usePermissionStore } from '@/store/modules/permission';
|
||||
import SidebarItem from '../Sidebar/SidebarItem'
|
||||
import {useAppStore} from '@/store/modules/app'
|
||||
import {useSettingsStore} from '@/store/modules/settings'
|
||||
import {usePermissionStore} from '@/store/modules/permission'
|
||||
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const route = useRoute()
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
const device = computed(() => appStore.device);
|
||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters)
|
||||
const theme = computed(() => settingsStore.theme)
|
||||
const device = computed(() => appStore.device)
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
const { meta, path } = route
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu;
|
||||
return meta.activeMenu
|
||||
}
|
||||
return path;
|
||||
});
|
||||
return path
|
||||
})
|
||||
|
||||
const visibleNumber = ref(5);
|
||||
const visibleNumber = ref(5)
|
||||
const topMenus = computed(() => {
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(0, visibleNumber.value);
|
||||
});
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(0, visibleNumber.value)
|
||||
})
|
||||
const moreRoutes = computed(() => {
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(visibleNumber.value, sidebarRouters.value.length - visibleNumber.value);
|
||||
});
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(visibleNumber.value, sidebarRouters.value.length - visibleNumber.value)
|
||||
})
|
||||
function setVisibleNumber() {
|
||||
let width = document.body.getBoundingClientRect().width;
|
||||
let width = document.body.getBoundingClientRect().width
|
||||
if (width >= 1000) {
|
||||
width -= 500;
|
||||
width -= 500
|
||||
}
|
||||
visibleNumber.value = parseInt(width / 3 / 85);
|
||||
visibleNumber.value = parseInt(width / 3 / 85)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', setVisibleNumber);
|
||||
});
|
||||
window.addEventListener('resize', setVisibleNumber)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', setVisibleNumber);
|
||||
});
|
||||
window.removeEventListener('resize', setVisibleNumber)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setVisibleNumber();
|
||||
});
|
||||
setVisibleNumber()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
/* menu item */
|
||||
#app .topbar-menu.el-menu--horizontal .el-sub-menu__title,
|
||||
#app .topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
#app .topbar-menu.el-menu--horizontal .el-sub-menu__title, #app .topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
@@ -76,10 +76,7 @@ onMounted(() => {
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
|
||||
.el-sub-menu.is-active .svg-icon,
|
||||
.el-menu-item.is-active .svg-icon + span,
|
||||
.el-sub-menu.is-active .svg-icon + span,
|
||||
.el-sub-menu.is-active .el-sub-menu__title span {
|
||||
.el-sub-menu.is-active .svg-icon, .el-menu-item.is-active .svg-icon + span, .el-sub-menu.is-active .svg-icon + span, .el-sub-menu.is-active .el-sub-menu__title span {
|
||||
color: v-bind(theme);
|
||||
}
|
||||
|
||||
@@ -88,7 +85,7 @@ onMounted(() => {
|
||||
float: left;
|
||||
line-height: 50px !important;
|
||||
color: #303133 !important;
|
||||
margin: 0 15px -3px !important;
|
||||
margin: 0 15px -3px!important;
|
||||
}
|
||||
|
||||
/* topbar more arrow */
|
||||
@@ -100,8 +97,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
/* menu__title el-menu-item */
|
||||
.topbar-menu.el-menu--horizontal .el-sub-menu__title,
|
||||
.topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
.topbar-menu.el-menu--horizontal .el-sub-menu__title, .topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
height: 60px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,14 +19,13 @@
|
||||
</template>
|
||||
<el-empty v-else :description="'消息为空'"></el-empty>
|
||||
</div>
|
||||
<div v-if="newsList.length > 0" class="foot-box" @click="onGoToGiteeClick">前往gitee</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layoutBreadcrumbUserNews">
|
||||
import { useNoticeStore } from '@/store/modules/notice';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const noticeStore = useNoticeStore();
|
||||
const { readAll } = useNoticeStore();
|
||||
|
||||
@@ -49,10 +48,13 @@ const getTableData = async () => {
|
||||
//点击消息,写入已读
|
||||
const onNewsClick = (item: any) => {
|
||||
newsList.value[item].read = true;
|
||||
//并且写入pinia
|
||||
noticeStore.state.notices = newsList.value;
|
||||
router.push({
|
||||
path: '/system/notice'
|
||||
});
|
||||
};
|
||||
|
||||
// 前往通知中心点击
|
||||
const onGoToGiteeClick = () => {
|
||||
window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
@@ -83,8 +85,7 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
.content-box {
|
||||
height: 400px;
|
||||
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
font-size: 13px;
|
||||
.content-box-item {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!-- 👇 加这一层全局缩放容器 -->
|
||||
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
||||
<side-bar class="sidebar-container" />
|
||||
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container" id="main-container">
|
||||
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
||||
<div>
|
||||
<navbar ref="navbarRef" @set-layout="setLayout" />
|
||||
</div>
|
||||
@@ -134,9 +134,6 @@ const setLayout = () => {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
.main-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
|
||||
@@ -22,18 +22,7 @@ let isDynamicRoutesAdded = false;
|
||||
const isWhiteList = (path: string) => {
|
||||
return whiteList.some((pattern) => isPathMatch(pattern, path));
|
||||
};
|
||||
// ✅ 关键修改:记录当前已添加的动态路由名称列表
|
||||
let currentDynamicRouteNames: string[] = [];
|
||||
// ✅ 关键修改:清除所有已记录的动态路由
|
||||
const removeDynamicRoutes = () => {
|
||||
currentDynamicRouteNames.forEach((name) => {
|
||||
if (name && router.hasRoute(name)) {
|
||||
router.removeRoute(name);
|
||||
}
|
||||
});
|
||||
// 清空记录数组
|
||||
currentDynamicRouteNames = [];
|
||||
};
|
||||
|
||||
router.beforeEach(async (to, from) => {
|
||||
NProgress.start();
|
||||
|
||||
@@ -57,7 +46,6 @@ router.beforeEach(async (to, from) => {
|
||||
}
|
||||
if (userStore.roles.length === 0) {
|
||||
isRelogin.show = true;
|
||||
removeDynamicRoutes();
|
||||
|
||||
// 获取用户信息
|
||||
const [err, res] = await tos(userStore.getInfo());
|
||||
@@ -72,19 +60,14 @@ router.beforeEach(async (to, from) => {
|
||||
permissionStore.resetRoutes();
|
||||
// 生成动态路由
|
||||
const accessRoutes = await permissionStore.generateRoutes();
|
||||
|
||||
// 添加路由(避免重复添加)
|
||||
accessRoutes.forEach((route) => {
|
||||
if (route.name && router.hasRoute(route.name)) {
|
||||
router.removeRoute(route.name);
|
||||
}
|
||||
if (!isHttp(route.path) && !router.hasRoute(route.name)) {
|
||||
router.addRoute(route);
|
||||
// 记录顶层路由名称
|
||||
if (route.name) {
|
||||
currentDynamicRouteNames.push(route.name as string);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ 标记:路由已添加
|
||||
isDynamicRoutesAdded = true;
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: 'communitylist',
|
||||
name: 'communitylist',
|
||||
// system:village:list
|
||||
hidden: true,
|
||||
meta: {
|
||||
title: '小区列表'
|
||||
@@ -90,37 +89,32 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '',
|
||||
component: Layout,
|
||||
// redirect: '/index',
|
||||
redirect: import.meta.env.VITE_LOGIN_BACK_URL,
|
||||
// redirect: '/equipment/WaterDevice',
|
||||
redirect: '/equipment/WaterDevice',
|
||||
children: [
|
||||
// {
|
||||
// path: '/index',
|
||||
// component: () => import('@/views/workbench/index2.vue'),
|
||||
// name: 'Index',
|
||||
// // hidden: true,
|
||||
// meta: { title: '工作台', icon: 'dashboard', affix: true }
|
||||
// }
|
||||
{
|
||||
path: '/index',
|
||||
component: () => import('@/views/workbench/index2.vue'),
|
||||
name: 'Index',
|
||||
hidden: true,
|
||||
meta: { title: '工作台', icon: 'dashboard', affix: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/user',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
redirect: 'noredirect',
|
||||
children: [
|
||||
{
|
||||
path: 'profile',
|
||||
component: () => import('@/views/system/user/profile/index.vue'),
|
||||
name: 'Profile',
|
||||
meta: { title: '个人中心', icon: 'user' }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
if (import.meta.env.VITE_APP_SHOW_WORK_PLATFORM === 'true') {
|
||||
const find = constantRoutes.find((item) => item.path === '');
|
||||
if (find) {
|
||||
find.children?.push({
|
||||
path: '/index',
|
||||
component: () => {
|
||||
if (import.meta.env.VITE_LOGIN_BACK_URL_WORKBENCH_TRUE === 'true') {
|
||||
return import('@/views/workbench/index.vue');
|
||||
} else {
|
||||
return import('@/views/workbench/index2.vue');
|
||||
}
|
||||
},
|
||||
name: 'Index',
|
||||
meta: { title: '工作台', icon: 'dashboard', affix: true }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 动态路由,基于用户权限动态去加载
|
||||
export const dynamicRoutes: RouteRecordRaw[] = [];
|
||||
|
||||
@@ -2,7 +2,6 @@ import { LanguageEnum } from '@/enums/LanguageEnum';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
const setting: DefaultSettings = {
|
||||
topNav: false,
|
||||
/**
|
||||
* 网页标题
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,7 @@ export const useHouseStore = defineStore(
|
||||
'buildToward': '',
|
||||
'buildTall': '',
|
||||
'buildStructure': '',
|
||||
'unitCount': null,
|
||||
'floorCount': null,
|
||||
'remark': ''
|
||||
});
|
||||
@@ -72,15 +73,36 @@ export const useHouseStore = defineStore(
|
||||
};
|
||||
|
||||
// 初始化
|
||||
const initHouse = async () => {
|
||||
console.log('initHouse');
|
||||
resertInit();
|
||||
const initHouse = async (currentbuildingtype: string) => {
|
||||
currentBuildingInfoList.value = [];
|
||||
// 获取当前小区 所有楼栋信息
|
||||
const res2 = await getBuildinglistAPI();
|
||||
const res2 = await getBuildinglistAPI(currentbuildingtype);
|
||||
currentBuildingInfoList.value = res2.data;
|
||||
// 得到小区 内 楼栋列表 -> 切换到第一个
|
||||
if (res2.data.length > 0) {
|
||||
switchBuilding(res2.data[0].id);
|
||||
|
||||
// 获取当前小区 第一个楼栋信息
|
||||
// ! 不同住宅类型
|
||||
if ((currentBuildingInfo.value && currentBuildingInfo.value.id === null) || buildingtype.value !== currentbuildingtype) {
|
||||
currentBuildingInfo.value = res2.data[0];
|
||||
// ! 相同住宅类型
|
||||
} else if (buildingtype.value === currentbuildingtype) {
|
||||
// 更新当前楼栋的 信息
|
||||
currentBuildingInfo.value = res2.data.find((item) => item.id === currentBuildingInfo.value.id);
|
||||
}
|
||||
|
||||
if (currentBuildingInfo.value && currentBuildingInfo.value.id) {
|
||||
// 获取当前 第一个楼栋的所有信息
|
||||
const res3 = await getHouselistAPI(currentBuildingInfo.value.id);
|
||||
currentHouseInfoList.value = res3.data;
|
||||
floorslist.value = new Set();
|
||||
// 得到所有的有房屋的 楼层 数组
|
||||
currentHouseInfoList.value.units.forEach((item) => {
|
||||
item.floors.forEach((floor) => {
|
||||
floorslist.value.add(floor.floorNo);
|
||||
});
|
||||
});
|
||||
if (buildingtype.value !== currentbuildingtype) {
|
||||
buildingtype.value = currentbuildingtype;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -96,7 +118,7 @@ export const useHouseStore = defineStore(
|
||||
// 清空
|
||||
currentBuildingInfoList.value = [];
|
||||
// 获取当前小区 所有楼栋信息
|
||||
const res2 = await getBuildinglistAPI();
|
||||
const res2 = await getBuildinglistAPI(housetype);
|
||||
currentBuildingInfoList.value = res2.data;
|
||||
// 获取当前小区 第一个楼栋信息
|
||||
if ((currentBuildingInfo.value && currentBuildingInfo.value.id === null) || buildingtype.value !== housetype) {
|
||||
@@ -112,6 +134,7 @@ export const useHouseStore = defineStore(
|
||||
'buildToward': '',
|
||||
'buildTall': '',
|
||||
'buildStructure': '',
|
||||
'unitCount': null,
|
||||
'floorCount': null,
|
||||
'remark': ''
|
||||
};
|
||||
@@ -128,27 +151,10 @@ export const useHouseStore = defineStore(
|
||||
|
||||
// 更新当前楼栋信息
|
||||
const updateCureentBuilding = async () => {
|
||||
currentHouseInfoList.value = null;
|
||||
if (currentBuildingInfo.value && currentBuildingInfo.value.id) {
|
||||
// 获取当前 楼栋的所有信息
|
||||
const res3 = await getHouselistAPI(currentBuildingInfo.value.id);
|
||||
currentHouseInfoList.value = res3.data;
|
||||
floorslist.value = new Set();
|
||||
// 得到所有的有房屋的 楼层 数组
|
||||
currentHouseInfoList.value.units.forEach((item) => {
|
||||
item.floors.forEach((floor) => {
|
||||
floorslist.value.add(floor.floorNo);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
// 根据房屋号,查询房屋
|
||||
async function getHouseBybuildingNo(houseName: string, houseUseTypeId: string) {
|
||||
currentHouseInfoList.value = null;
|
||||
// 获取当前 楼栋的所有信息
|
||||
const res3 = await getHouselistAPI(currentBuildingInfo.value.id, houseName, houseUseTypeId);
|
||||
const res3 = await getHouselistAPI(currentBuildingInfo.value.id);
|
||||
currentHouseInfoList.value = res3.data;
|
||||
floorslist.value = null;
|
||||
floorslist.value = new Set();
|
||||
// 得到所有的有房屋的 楼层 数组
|
||||
currentHouseInfoList.value.units.forEach((item) => {
|
||||
@@ -156,7 +162,7 @@ export const useHouseStore = defineStore(
|
||||
floorslist.value.add(floor.floorNo);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
// 切换楼栋
|
||||
const switchBuilding = (buildingId: string) => {
|
||||
if (!buildingId) return;
|
||||
@@ -170,15 +176,16 @@ export const useHouseStore = defineStore(
|
||||
'buildToward': '',
|
||||
'buildTall': '',
|
||||
'buildStructure': '',
|
||||
'unitCount': null,
|
||||
'floorCount': null,
|
||||
'remark': ''
|
||||
};
|
||||
currentHouseInfoList.value = null;
|
||||
currentBuildingInfo.value = currentBuildingInfoList.value.find((item) => item.id === buildingId);
|
||||
getHouselistAPI(buildingId).then((res) => {
|
||||
if (!res.data) return;
|
||||
currentHouseInfoList.value = res.data;
|
||||
// 获取当前楼栋信息并 赋值
|
||||
currentBuildingInfo.value = currentBuildingInfoList.value.find((item) => item.id === buildingId);
|
||||
|
||||
// 清空 楼层信息
|
||||
floorslist.value.clear();
|
||||
// 重新获取楼层信息
|
||||
@@ -191,28 +198,9 @@ export const useHouseStore = defineStore(
|
||||
});
|
||||
};
|
||||
|
||||
function resertInit() {
|
||||
console.log('resertInit');
|
||||
currentBuildingInfo.value = {
|
||||
'id': null,
|
||||
'villageId': null,
|
||||
'villageName': '',
|
||||
'buildingName': '',
|
||||
'buildingUse': null,
|
||||
'buildToward': '',
|
||||
'buildTall': '',
|
||||
'buildStructure': '',
|
||||
'floorCount': null,
|
||||
'remark': ''
|
||||
};
|
||||
currentBuildingInfoList.value = [];
|
||||
currentHouseInfoList.value = null;
|
||||
floorslist.value.clear();
|
||||
}
|
||||
|
||||
// 更新数据
|
||||
const updateHouse = () => {
|
||||
initHouse();
|
||||
initHouse(buildingtype.value);
|
||||
};
|
||||
// 删除指定楼栋
|
||||
const deleteBuildingFun = (buildingId: string) => {
|
||||
@@ -230,10 +218,9 @@ export const useHouseStore = defineStore(
|
||||
|
||||
// 房屋 树状结构类型
|
||||
const getCurrentVilageTreeHouse = async () => {
|
||||
const villageid = localStorage.getItem('villageid');
|
||||
try {
|
||||
treedata.value = [];
|
||||
const res = await getVillageTree(villageid);
|
||||
const res = await getVillageTree(currentVilageInfo.value.villageId);
|
||||
treedata.value = convertBuildingToTree(res.data.buildings || []);
|
||||
return treedata.value;
|
||||
} catch (err) {
|
||||
@@ -252,7 +239,6 @@ export const useHouseStore = defineStore(
|
||||
buildingtype,
|
||||
buildingtypelist,
|
||||
treedata,
|
||||
getHouseBybuildingNo,
|
||||
updateVilageinfo,
|
||||
updateCureentBuilding,
|
||||
getviliageinfo,
|
||||
|
||||
@@ -8,42 +8,34 @@ interface NoticeItem {
|
||||
time: string;
|
||||
}
|
||||
|
||||
export const useNoticeStore = defineStore(
|
||||
'notice',
|
||||
() => {
|
||||
const state = reactive({
|
||||
notices: [] as NoticeItem[]
|
||||
export const useNoticeStore = defineStore('notice', () => {
|
||||
const state = reactive({
|
||||
notices: [] as NoticeItem[]
|
||||
});
|
||||
|
||||
const addNotice = (notice: NoticeItem) => {
|
||||
state.notices.push(notice);
|
||||
};
|
||||
|
||||
const removeNotice = (notice: NoticeItem) => {
|
||||
state.notices.splice(state.notices.indexOf(notice), 1);
|
||||
};
|
||||
|
||||
//实现全部已读
|
||||
const readAll = () => {
|
||||
state.notices.forEach((item: any) => {
|
||||
item.read = true;
|
||||
});
|
||||
};
|
||||
|
||||
const addNotice = (notice: NoticeItem) => {
|
||||
state.notices.unshift(notice);
|
||||
};
|
||||
|
||||
const removeNotice = (notice: NoticeItem) => {
|
||||
state.notices.splice(state.notices.indexOf(notice), 1);
|
||||
};
|
||||
|
||||
//实现全部已读
|
||||
const readAll = () => {
|
||||
state.notices.forEach((item: any) => {
|
||||
item.read = true;
|
||||
});
|
||||
};
|
||||
|
||||
const clearNotice = () => {
|
||||
state.notices = [];
|
||||
};
|
||||
return {
|
||||
state,
|
||||
addNotice,
|
||||
removeNotice,
|
||||
readAll,
|
||||
clearNotice
|
||||
};
|
||||
},
|
||||
{
|
||||
persist: {
|
||||
storage: sessionStorage
|
||||
}
|
||||
}
|
||||
);
|
||||
const clearNotice = () => {
|
||||
state.notices = [];
|
||||
};
|
||||
return {
|
||||
state,
|
||||
addNotice,
|
||||
removeNotice,
|
||||
readAll,
|
||||
clearNotice
|
||||
};
|
||||
});
|
||||
|
||||
@@ -70,20 +70,16 @@ export const usePermissionStore = defineStore('permission', () => {
|
||||
};
|
||||
|
||||
const setRoutes = (newRoutes: RouteRecordRaw[]): void => {
|
||||
addRoutes.value = [];
|
||||
addRoutes.value = newRoutes;
|
||||
routes.value = constantRoutes.concat(newRoutes);
|
||||
};
|
||||
const setDefaultRoutes = (routes: RouteRecordRaw[]): void => {
|
||||
defaultRoutes.value = [];
|
||||
defaultRoutes.value = constantRoutes.concat(routes);
|
||||
};
|
||||
const setTopbarRoutes = (routes: RouteRecordRaw[]): void => {
|
||||
topbarRouters.value = [];
|
||||
topbarRouters.value = routes;
|
||||
};
|
||||
const setSidebarRouters = (routes: RouteRecordRaw[]): void => {
|
||||
sidebarRouters.value = [];
|
||||
sidebarRouters.value = routes;
|
||||
};
|
||||
|
||||
@@ -108,6 +104,10 @@ export const usePermissionStore = defineStore('permission', () => {
|
||||
const defaultRoutes = filterAsyncRouter(defaultData);
|
||||
|
||||
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
|
||||
|
||||
asyncRoutes.forEach((route) => {
|
||||
router.addRoute(route);
|
||||
});
|
||||
setRoutes(rewriteRoutes);
|
||||
setSidebarRouters(constantRoutes.concat(sidebarRoutes));
|
||||
setDefaultRoutes(sidebarRoutes);
|
||||
|
||||
10
src/types/global.d.ts
vendored
10
src/types/global.d.ts
vendored
@@ -17,14 +17,10 @@ declare global {
|
||||
}
|
||||
/** 地图 */
|
||||
interface Window {
|
||||
// 高德全局对象
|
||||
_AMapSecurityConfig?: {
|
||||
securityJsCode: string;
|
||||
};
|
||||
// 天地图全局对象
|
||||
T: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗属性
|
||||
*/
|
||||
@@ -69,7 +65,7 @@ declare global {
|
||||
declare interface DictDataOption {
|
||||
label: string;
|
||||
value: string;
|
||||
elTagType?: ElTagType | '' | 'default';
|
||||
elTagType?: ElTagType;
|
||||
elTagClass?: string;
|
||||
}
|
||||
|
||||
@@ -99,10 +95,6 @@ declare global {
|
||||
pageSize: number;
|
||||
}
|
||||
declare interface LayoutSetting {
|
||||
/**
|
||||
* 是否显示顶部导航
|
||||
*/
|
||||
topNav: boolean; // 新增此字段
|
||||
/**
|
||||
* 默认布局
|
||||
*/
|
||||
|
||||
150
src/utils/Reg.ts
150
src/utils/Reg.ts
@@ -64,153 +64,3 @@ export type RegType = keyof typeof reg;
|
||||
export function validator(value: string | number, regType: RegType): boolean {
|
||||
return reg[regType].test(String(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 车牌验证工具类
|
||||
* 支持传统燃油、新能源、军警、武警、使馆、临时、港澳等全量车牌
|
||||
*/
|
||||
export class LicensePlateValidator {
|
||||
/**
|
||||
* 省份简称正则片段
|
||||
*/
|
||||
private static readonly PROVINCE = '[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]';
|
||||
|
||||
/**
|
||||
* 使领馆前缀
|
||||
*/
|
||||
private static readonly EMBASSY_PREFIX = '[使领]';
|
||||
|
||||
/**
|
||||
* 验证传统燃油车牌 (蓝牌/黄牌)
|
||||
* 格式: 省份 + 字母 + 5位字符
|
||||
* 示例: 京A·12345, 粤B·88888
|
||||
*/
|
||||
static isTraditionalPlate(plate: string): boolean {
|
||||
// 包含普通民用以及使领馆非新能源部分(如果使领馆归为此类,通常使领馆有单独规则,这里仅指普通民用)
|
||||
// 注意:使领馆车牌通常格式特殊,见 isEmbassyPlate
|
||||
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][A-HJ-NP-Z0-9]{5}$`);
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证新能源车牌 (绿牌)
|
||||
* 小型: 省份 + 字母 + D/F + 4位数字/字母 或 省份 + 字母 + 5位数字/字母 + D/F
|
||||
* 大型: 省份 + 字母 + 5位数字/字母 + D/F (通常最后一位是D/F)
|
||||
* 示例: 京AD12345, 京A12345D, 沪AF12345
|
||||
*/
|
||||
static isNewEnergyPlate(plate: string): boolean {
|
||||
// 小型新能源:第2位或第7位是D/F
|
||||
// 大型新能源:最后一位是D/F (且总长8位)
|
||||
// 综合正则:
|
||||
// 1. [省份][A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{4} (小型,D/F在第2位)
|
||||
// 2. [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{4}[D-F] (小型/大型,D/F在最后)
|
||||
// 3. [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{3} (较少见,但某些早期试点或特殊编排可能存在,标准通常只认1和2)
|
||||
|
||||
// 更严谨的标准新能源正则 (GA 804-2018):
|
||||
// 小型: [省份][A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{4} | [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{4}[D-F]
|
||||
// 大型: [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{5}[D-F] (其实包含在上面第二种情况的子集里,只要保证总长8位)
|
||||
|
||||
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z](?:[D-F][0-9A-HJ-NP-Z]{4}|[0-9A-HJ-NP-Z]{5}[D-F])$`);
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证警车车牌
|
||||
* 格式: 省份 + 字母 + 4位数字 + 警
|
||||
* 示例: 京A·1234警
|
||||
*/
|
||||
static isPolicePlate(plate: string): boolean {
|
||||
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9]{4}警$`);
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证教练车牌
|
||||
* 格式: 省份 + 字母 + 4位数字 + 学
|
||||
* 示例: 京A·1234学
|
||||
*/
|
||||
static isCoachPlate(plate: string): boolean {
|
||||
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9]{4}学$`);
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证武警车牌 (2013式)
|
||||
* 格式: WJ + 省份/部门简称 + 5位字符
|
||||
* 示例: WJ·京12345, WJ·12345X, WJ·B12345
|
||||
* 注意:WJ后紧跟的可能是省份简称或部门字母
|
||||
*/
|
||||
static isArmedPolicePlate(plate: string): boolean {
|
||||
// WJ + (省份简称 | 部门字母) + 5位字符
|
||||
// 部门字母包括: 内边消水电林通海等,这里简化处理,允许字母或省份
|
||||
const reg = /^WJ(?:[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]|[A-Z])[0-9A-HJ-NP-Z]{5}$/;
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证军队车牌 (2012式)
|
||||
* 格式: 军种字母 + · + 5位字符 (实际输入常不带点)
|
||||
* 军种: V(军委), K(空军), H(海军), B(北京军区), S(沈阳), L(兰州), J(济南), N(南京), G(广州), C(成都) 等
|
||||
* 示例: V·12345, K·A1234
|
||||
*/
|
||||
static isMilitaryPlate(plate: string): boolean {
|
||||
// 简化版:首字母为大写(排除I,O),后跟5位字符
|
||||
// 更严谨应限制首字母为特定军种代号,但考虑到军改变化,此处做通用校验
|
||||
// 2012式军牌格式:XY·12345 (X为军种/大区,Y为单位)
|
||||
// 常见前缀: V, K, H, B, S, L, J, N, G, C, M, P, O, A, E 等
|
||||
const reg = /^[VKBHSLJNGCMPEOA][A-HJ-NP-Z0-9][0-9A-HJ-NP-Z]{4}$/;
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证使馆/领馆车牌
|
||||
* 格式: 使/领 + 3位数字 + 3位数字 (共6位数字,或 使·123456)
|
||||
* 示例: 使·123456, 领·123456
|
||||
*/
|
||||
static isEmbassyPlate(plate: string): boolean {
|
||||
const reg = /^[使领][0-9]{6}$/;
|
||||
return reg.test(plate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证港澳入出境车 (粤Z牌)
|
||||
* 格式: 粤Z + 4位字符 + 港/澳
|
||||
* 示例: 粤Z·1234港, 粤Z·1234澳
|
||||
*/
|
||||
static isHKMacauPlate(plate: string): boolean {
|
||||
const reg = /^粤Z[A-HJ-NP-Z0-9]{4}[港澳]$/;
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证临时车牌
|
||||
* 格式: 省份 + 字母 + 5位字符 + 临 / 超
|
||||
* 示例: 京A·12345临, 沪B·12345超
|
||||
*/
|
||||
static isTemporaryPlate(plate: string): boolean {
|
||||
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9A-HJ-NP-Z]{5}[临超]$`);
|
||||
return reg.test(plate.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证所有合法车牌(全量)
|
||||
* @param plate 车牌号码
|
||||
*/
|
||||
static isValidPlate(plate: string): boolean {
|
||||
if (!plate || typeof plate !== 'string') return false;
|
||||
|
||||
const upperPlate = plate.toUpperCase().replace(/[·\s-]/g, ''); // 去除分隔符和空格
|
||||
|
||||
return (
|
||||
this.isTraditionalPlate(upperPlate) ||
|
||||
this.isNewEnergyPlate(upperPlate) ||
|
||||
this.isPolicePlate(upperPlate) ||
|
||||
this.isCoachPlate(upperPlate) ||
|
||||
this.isArmedPolicePlate(upperPlate) ||
|
||||
this.isMilitaryPlate(upperPlate) ||
|
||||
this.isEmbassyPlate(upperPlate) ||
|
||||
this.isHKMacauPlate(upperPlate) ||
|
||||
this.isTemporaryPlate(upperPlate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
import JSZip from 'jszip';
|
||||
import { saveAs } from 'file-saver';
|
||||
// 假设使用的是 Element Plus,请根据实际 UI 库调整导入
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
/**
|
||||
* 图片数据接口
|
||||
*/
|
||||
interface ImageItem {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导出图片并生成 ZIP
|
||||
* @param imageList 图片数组
|
||||
* @param zipName 压缩包名称
|
||||
* @param concurrency 并发请求数,默认 5,避免浏览器请求过多被拦截
|
||||
*/
|
||||
export async function exportImagesToZip(imageList: ImageItem[], zipName: string = 'images', concurrency: number = 5) {
|
||||
if (!imageList || imageList.length === 0) {
|
||||
ElMessage.warning('没有可导出的图片');
|
||||
return;
|
||||
}
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
try {
|
||||
// 使用并发控制处理图片获取
|
||||
const tasks = imageList.map((item) => () => processImageItem(item, zip));
|
||||
|
||||
// 执行并发任务
|
||||
await runWithConcurrency(tasks, concurrency);
|
||||
|
||||
ElMessage.success('导出完成');
|
||||
|
||||
// 生成 ZIP 并下载
|
||||
const content = await zip.generateAsync({
|
||||
type: 'blob',
|
||||
compression: 'DEFLATE',
|
||||
compressionOptions: { level: 6 }
|
||||
});
|
||||
|
||||
saveAs(content, `${zipName}.zip`);
|
||||
} catch (err) {
|
||||
console.error('ZIP 导出失败:', err);
|
||||
ElMessage.error('图片导出失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个图片项:获取 Blob 并添加到 Zip
|
||||
*/
|
||||
async function processImageItem(item: ImageItem, zip: JSZip): Promise<void> {
|
||||
try {
|
||||
// 清理文件名,防止非法字符或扩展名缺失
|
||||
const safeName = sanitizeFileName(item.name);
|
||||
const blob = await getImageBlobViaCanvas(item.url);
|
||||
zip.file(`${safeName}.png`, blob, { binary: true });
|
||||
} catch (error) {
|
||||
console.warn(`图片加载失败: ${item.url}`, error);
|
||||
throw error; // 抛出错误以便外层统计或处理
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 Canvas 获取图片 Blob (解决 OSS 跨域 fetch 问题)
|
||||
* 注意:这要求 OSS _bucket_ 配置了 CORS 允许 '*' 或你的域名,且允许 GET 方法。
|
||||
* 如果 OSS 完全禁止跨域,此方法也会失败,但通常公共读 OSS 是允许 img 标签跨域显示的。
|
||||
*/
|
||||
async function getImageBlobViaCanvas(url: string): Promise<Blob> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.blob();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单的并发控制执行器
|
||||
*/
|
||||
async function runWithConcurrency(tasks: (() => Promise<void>)[], limit: number): Promise<void> {
|
||||
const results: Promise<void>[] = [];
|
||||
let index = 0;
|
||||
|
||||
async function worker() {
|
||||
while (index < tasks.length) {
|
||||
const currentIndex = index++;
|
||||
const task = tasks[currentIndex];
|
||||
try {
|
||||
await task();
|
||||
} catch (e) {
|
||||
// 这里可以选择忽略单个失败,或者累计错误
|
||||
console.error(`Task ${currentIndex} failed`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建 limit 个工人
|
||||
const workers = Array(Math.min(limit, tasks.length)).fill(null).map(worker);
|
||||
await Promise.all(workers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理文件名,确保合法且唯一(简单版)
|
||||
*/
|
||||
function sanitizeFileName(name: string): string {
|
||||
// 移除非法字符,保留字母、数字、中文、下划线、点、横杠
|
||||
let cleanName = name.replace(/[<>:"/\\|?*]/g, '_');
|
||||
|
||||
// 如果名字为空或只有扩展名,给一个默认名
|
||||
if (!cleanName || cleanName.startsWith('.')) {
|
||||
cleanName = `image_${Date.now()}_${Math.random().toString(36).substr(2, 9)}${cleanName}`;
|
||||
}
|
||||
|
||||
return cleanName;
|
||||
}
|
||||
@@ -26,9 +26,9 @@ export function convertBuildingToTree(buildings: any[]): Tree[] {
|
||||
const units = building.units || [];
|
||||
const unitTrees = units.map((unit: any) => {
|
||||
const unitTree: Tree = {
|
||||
label: unit.unitNoName,
|
||||
value: unit.unitNoId,
|
||||
type: 'unitNoId',
|
||||
label: `${unit.unitNo} 单元`,
|
||||
value: unit.unitNo,
|
||||
type: 'unitNo',
|
||||
children: []
|
||||
};
|
||||
|
||||
@@ -58,6 +58,22 @@ export function convertBuildingToTree(buildings: any[]): Tree[] {
|
||||
});
|
||||
}
|
||||
|
||||
// 与业主关系
|
||||
export const ownerRelationshiplist = [
|
||||
{
|
||||
label: '业主',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: '亲属',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '租户',
|
||||
value: 2
|
||||
}
|
||||
];
|
||||
|
||||
interface Tree {
|
||||
label: string;
|
||||
value: number;
|
||||
@@ -104,6 +120,8 @@ export function getHousePathById(treeData: Tree[], houseId: string | number, res
|
||||
return path;
|
||||
}
|
||||
|
||||
export const houseUselist = ['普通住宅', '商业用地', '商住两用', '其他'];
|
||||
|
||||
// 对字符串 图片地址,处理
|
||||
export function splitStringUrl(str: string, splitLabel: string = ',') {
|
||||
const list = str.split(splitLabel);
|
||||
@@ -131,3 +149,25 @@ export function hasFormData(formData: FormData): boolean {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 方法渲燃模板数据 */
|
||||
type dataType = {
|
||||
'label': string;
|
||||
'value': string;
|
||||
'elTagType': string;
|
||||
'elTagClass': string;
|
||||
};
|
||||
/**
|
||||
* 通用:根据 value 从字典数组中获取 label
|
||||
* @param dict 字典数组
|
||||
* @param value 要匹配的值
|
||||
* @returns 匹配到的label,无则返回原value
|
||||
*/
|
||||
export function getDictLabel(dict: Ref<dataType>, value: number): string {
|
||||
// 空值直接返回
|
||||
if (value == null) return '-';
|
||||
|
||||
// 统一转字符串匹配
|
||||
const item = (dict.value || []).find((i) => String(i.value) === String(value));
|
||||
return item ? item.label : String(value);
|
||||
}
|
||||
|
||||
@@ -220,19 +220,14 @@ export const getTime = (type: string) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建一个防抖函数,确保在指定的等待时间内只执行一次目标函数。
|
||||
*
|
||||
* @param func - 需要被防抖处理的目标函数
|
||||
* @param wait - 等待时间(毫秒),在此时间内重复调用将重置计时器
|
||||
* @param immediate - 是否立即执行。如果为 true,则在第一次调用时立即执行函数,并在等待期结束后才能再次触发;如果为 false,则在等待期结束后执行最后一次调用
|
||||
* @returns 返回一个新的防抖函数,该函数在被调用时会应用防抖逻辑
|
||||
* @param {Function} func
|
||||
* @param {number} wait
|
||||
* @param {boolean} immediate
|
||||
* @return {*}
|
||||
*/
|
||||
export const debounce = (func: any, wait: number, immediate: boolean) => {
|
||||
let timeout: any, args: any, context: any, timestamp: any, result: any;
|
||||
|
||||
/**
|
||||
* 延迟执行的内部函数,用于判断是否真正执行目标函数
|
||||
*/
|
||||
const later = function () {
|
||||
// 据上一次触发时间间隔
|
||||
const last = +new Date() - timestamp;
|
||||
|
||||
@@ -80,71 +80,3 @@ export function convertToChineseCapital(num: number | string): string {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 金额加法
|
||||
export function add(a, b) {
|
||||
let r1, r2;
|
||||
try {
|
||||
r1 = a.toString().split('.')[1].length;
|
||||
} catch (e) {
|
||||
r1 = 0;
|
||||
}
|
||||
try {
|
||||
r2 = b.toString().split('.')[1].length;
|
||||
} catch (e) {
|
||||
r2 = 0;
|
||||
}
|
||||
const m = Math.pow(10, Math.max(r1, r2));
|
||||
return (a * m + b * m) / m;
|
||||
}
|
||||
|
||||
// 金额减法
|
||||
export function sub(a, b) {
|
||||
let r1, r2;
|
||||
try {
|
||||
r1 = a.toString().split('.')[1].length;
|
||||
} catch (e) {
|
||||
r1 = 0;
|
||||
}
|
||||
try {
|
||||
r2 = b.toString().split('.')[1].length;
|
||||
} catch (e) {
|
||||
r2 = 0;
|
||||
}
|
||||
const m = Math.pow(10, Math.max(r1, r2));
|
||||
return (a * m - b * m) / m;
|
||||
}
|
||||
|
||||
// 金额乘法
|
||||
export function mul(a, b) {
|
||||
let m = 0;
|
||||
const s1 = a.toString(),
|
||||
s2 = b.toString();
|
||||
try {
|
||||
m += s1.split('.')[1].length;
|
||||
} catch (e) {}
|
||||
try {
|
||||
m += s2.split('.')[1].length;
|
||||
} catch (e) {}
|
||||
return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m);
|
||||
}
|
||||
|
||||
// 金额除法
|
||||
export function div(a, b) {
|
||||
let t1 = 0,
|
||||
t2 = 0;
|
||||
try {
|
||||
t1 = a.toString().split('.')[1].length;
|
||||
} catch (e) {}
|
||||
try {
|
||||
t2 = b.toString().split('.')[1].length;
|
||||
} catch (e) {}
|
||||
const x = Number(a.toString().replace('.', ''));
|
||||
const y = Number(b.toString().replace('.', ''));
|
||||
return (x / y) * Math.pow(10, t2 - t1);
|
||||
}
|
||||
|
||||
// 保留2位小数(金额专用)
|
||||
export function toFixed2(val) {
|
||||
return Number(val).toFixed(2);
|
||||
}
|
||||
|
||||
@@ -34,16 +34,15 @@ const service = axios.create({
|
||||
clarifyTimeoutError: true
|
||||
}
|
||||
});
|
||||
|
||||
// 不需要小区 ID 的接口白名单(支持 * 通配符)
|
||||
const whiteVillageId = [
|
||||
'/village',
|
||||
'/village/*',
|
||||
'/waterDevice/generateBarCode', // 水表 条码
|
||||
'/electricityDevice/generateBarCode', // 电表 条码
|
||||
'/payRecordList/payRecordList/list',
|
||||
'/electricityDevice/generateBarCodee', // 电表 条码
|
||||
|
||||
'/warehouse/*'
|
||||
// '/storeroom/getList/*'
|
||||
'/payRecordList/payRecordList/list'
|
||||
// 以后直接在这里加新地址,支持 /xxx/*、/xxx/xxx 写法
|
||||
];
|
||||
|
||||
@@ -204,6 +203,9 @@ service.interceptors.response.use(
|
||||
useUserStore().logout().then(() => {
|
||||
router.replace({
|
||||
path: '/login',
|
||||
query: {
|
||||
redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
|
||||
}
|
||||
})
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
const weatherIcons: Record<number, string> = {
|
||||
100: '☀️',
|
||||
101: '⛅',
|
||||
102: '🌤️',
|
||||
103: '⛅',
|
||||
104: '☁️',
|
||||
150: '🌙',
|
||||
151: '🌙',
|
||||
152: '🌙',
|
||||
153: '🌙',
|
||||
300: '🌦️',
|
||||
301: '🌧️',
|
||||
302: '⛈️',
|
||||
303: '⛈️',
|
||||
304: '⛈️',
|
||||
305: '🌧️',
|
||||
306: '🌧️',
|
||||
307: '🌧️',
|
||||
308: '🌧️',
|
||||
309: '🌧️',
|
||||
310: '🌊',
|
||||
311: '🌊',
|
||||
312: '🌊',
|
||||
313: '🧊',
|
||||
314: '🌧️',
|
||||
315: '🌧️',
|
||||
316: '🌊',
|
||||
317: '🌊',
|
||||
318: '🌊',
|
||||
350: '🌙',
|
||||
351: '🌙',
|
||||
399: '🌧️',
|
||||
400: '🌨️',
|
||||
401: '🌨️',
|
||||
402: '❄️',
|
||||
403: '❄️',
|
||||
404: '🌨️',
|
||||
405: '🌨️',
|
||||
406: '🌨️',
|
||||
407: '🌨️',
|
||||
408: '🌨️',
|
||||
409: '❄️',
|
||||
410: '❄️',
|
||||
456: '🌙',
|
||||
457: '🌙',
|
||||
499: '❄️',
|
||||
500: '🌫️',
|
||||
501: '🌫️',
|
||||
502: '😶🌫️',
|
||||
503: '💨',
|
||||
504: '💨',
|
||||
507: '🏜️',
|
||||
508: '🏜️',
|
||||
509: '🌫️',
|
||||
510: '🌫️',
|
||||
511: '😶🌫️',
|
||||
512: '😶🌫️',
|
||||
513: '😶🌫️',
|
||||
514: '🌫️',
|
||||
515: '🌫️',
|
||||
800: '🌑',
|
||||
801: '🌒',
|
||||
802: '🌓',
|
||||
803: '🌔',
|
||||
804: '🌕',
|
||||
805: '🌖',
|
||||
806: '🌗',
|
||||
807: '🌘',
|
||||
900: '🥵',
|
||||
901: '🥶',
|
||||
999: '❓',
|
||||
1001: '🌀',
|
||||
1002: '🌪️',
|
||||
1003: '🌊',
|
||||
1004: '❄️',
|
||||
1005: '🥶',
|
||||
1006: '💨',
|
||||
1007: '🏜️',
|
||||
1008: '🧊',
|
||||
1009: '🌡️',
|
||||
1010: '🥵',
|
||||
1011: '🌾',
|
||||
1012: '💨',
|
||||
1013: '🏔️',
|
||||
1014: '⚡',
|
||||
1015: '🧊',
|
||||
1016: '🥶',
|
||||
1017: '🌫️',
|
||||
1018: '✈️',
|
||||
1019: '😶🌫️',
|
||||
1020: '⛈️',
|
||||
1021: '🧊',
|
||||
1022: '☀️',
|
||||
1023: '🌊',
|
||||
1024: '🥵',
|
||||
1025: '🔥',
|
||||
1026: '🔥',
|
||||
1027: '🧊',
|
||||
1028: '🛰️',
|
||||
1029: '😶🌫️',
|
||||
1030: '🌨️',
|
||||
1031: '⛈️',
|
||||
1032: '☀️',
|
||||
1033: '❄️',
|
||||
1034: '🥶',
|
||||
1035: '🌧️',
|
||||
1036: '🌊',
|
||||
1037: '⛰️',
|
||||
1038: '🌧️',
|
||||
1039: '🌡️',
|
||||
1040: '❄️',
|
||||
1041: '🔥',
|
||||
1042: '🏥',
|
||||
1043: '⛈️',
|
||||
1044: '🏫',
|
||||
1045: '🏭',
|
||||
1046: '🚢',
|
||||
1047: '💨',
|
||||
1048: '🌡️',
|
||||
1049: '🌀',
|
||||
1050: '🥶',
|
||||
1051: '💨',
|
||||
1052: '⛈️',
|
||||
1053: '🌫️',
|
||||
1054: '⚡',
|
||||
1055: '🌀',
|
||||
1056: '🌡️',
|
||||
1057: '🧊',
|
||||
1058: '⛈️',
|
||||
1059: '🥶',
|
||||
1060: '🌫️',
|
||||
1061: '💨',
|
||||
1062: '🌊',
|
||||
1063: '🌧️',
|
||||
1064: '🌧️',
|
||||
1065: '🌫️',
|
||||
1066: '🥵',
|
||||
1067: '😶🌫️',
|
||||
1068: '⚠️',
|
||||
1069: '🏥',
|
||||
1071: '🏥',
|
||||
1072: '🏥',
|
||||
1073: '🌊',
|
||||
1074: '😶🌫️',
|
||||
1075: '🏙️',
|
||||
1076: '🌊',
|
||||
1077: '🔥',
|
||||
1078: '☀️',
|
||||
1079: '🌾',
|
||||
1080: '💨',
|
||||
1081: '🧊',
|
||||
1082: '🏥',
|
||||
1084: '🔥',
|
||||
1085: '⛈️',
|
||||
1086: '🧊',
|
||||
1087: '🌡️',
|
||||
1088: '🌾',
|
||||
1089: '🌾',
|
||||
1201: '🌊',
|
||||
1202: '🏙️',
|
||||
1203: '⚠️',
|
||||
1204: '⚠️',
|
||||
1205: '🧊',
|
||||
1206: '🌊',
|
||||
1207: '🌊',
|
||||
1208: '☀️',
|
||||
1209: '🌊',
|
||||
1210: '💧',
|
||||
1211: '🌊',
|
||||
1212: '🌊',
|
||||
1213: '🏙️',
|
||||
1214: '🌊',
|
||||
1215: '☀️',
|
||||
1216: '💧',
|
||||
1217: '🌿',
|
||||
1218: '⚠️',
|
||||
1219: '🌊',
|
||||
1221: '☀️',
|
||||
1241: '⛰️',
|
||||
1242: '⛰️',
|
||||
1243: '⛰️',
|
||||
1244: '⛰️',
|
||||
1245: '⛰️',
|
||||
1246: '⛰️',
|
||||
1247: '🌋',
|
||||
1248: '⛰️',
|
||||
1249: '⛰️',
|
||||
1250: '⛰️',
|
||||
1251: '⛰️',
|
||||
1271: '😶🌫️',
|
||||
1272: '😶🌫️',
|
||||
1273: '😶🌫️',
|
||||
9999: '⚠️'
|
||||
};
|
||||
|
||||
export const getWeatherIcon = (weatherCode: string): string => {
|
||||
return weatherIcons[weatherCode] || weatherIcons[100];
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="box">
|
||||
<div class="header">
|
||||
<span>智慧物业后台管理系统</span>
|
||||
<navbar :Showhamburger="false" ref="navbarRef" />
|
||||
<navbar ref="navbarRef" />
|
||||
</div>
|
||||
<div class="container AddBuildingBox">
|
||||
<el-form inline class="formBody" ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||
@@ -185,6 +185,7 @@ function getCommunityinfo() {
|
||||
const id = editId.value;
|
||||
getVillageByIdAPI(id).then((res) => {
|
||||
city.value = res.data.city.split('/');
|
||||
console.log(res.data.city.split('/'));
|
||||
if (res.data.villageImageUrl) {
|
||||
villageImg.value = res.data.villageImageUrl
|
||||
.split(',')
|
||||
@@ -310,25 +311,25 @@ const submitForm = () => {
|
||||
};
|
||||
|
||||
function submitFormInfo() {
|
||||
if (form.value.managePhone && form.value.managePhone.trim()) {
|
||||
if (form.value.managePhone.trim()) {
|
||||
if (!reg.phone.test(form.value.managePhone)) {
|
||||
ElMessage.error('请输入正确的手机号码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (form.value.manageVx && form.value.manageVx.trim()) {
|
||||
if (form.value.manageVx.trim()) {
|
||||
if (!reg.wechat.test(form.value.manageVx)) {
|
||||
ElMessage.error('请输入正确的微信号');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (form.value.manageQq && form.value.manageQq.trim()) {
|
||||
if (form.value.manageQq.trim()) {
|
||||
if (!reg.qq.test(form.value.manageQq)) {
|
||||
ElMessage.error('请输入正确的QQ号码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (form.value.manageEmail && form.value.manageEmail.trim()) {
|
||||
if (form.value.manageEmail.trim()) {
|
||||
if (!reg.email.test(form.value.manageEmail)) {
|
||||
ElMessage.error('请输入正确的邮箱号码');
|
||||
return;
|
||||
@@ -348,7 +349,9 @@ function submitFormInfo() {
|
||||
}
|
||||
}
|
||||
const cancelForm = () => {
|
||||
router.back();
|
||||
router.push({
|
||||
path: '/community'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="h-full box">
|
||||
<div class="header">
|
||||
<span class="">智慧物业后台管理系统</span>
|
||||
<navbar :Showhamburger="false" ref="navbarRef" />
|
||||
<navbar ref="navbarRef" />
|
||||
</div>
|
||||
<div class="containerbox">
|
||||
<div class="community_nav_box">
|
||||
@@ -95,7 +95,6 @@ function handleEdit(item: communitylist_rows_type) {
|
||||
/** 管理小区 */
|
||||
function handleclick(item: communitylist_rows_type) {
|
||||
switchVillageAPI(item.villageId).then(() => {
|
||||
localStorage.setItem('villageInfo', JSON.stringify(item));
|
||||
localStorage.setItem('villageid', item.villageId);
|
||||
houseStore.getviliageinfo(item.villageId);
|
||||
router.push({
|
||||
@@ -201,15 +200,12 @@ function handleclick(item: communitylist_rows_type) {
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
@media (max-width: 2350px) {
|
||||
@media (max-width: 1900px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@media (max-width: 1900px) {
|
||||
@media (max-width: 1500px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@media (max-width: 1450px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.coummunity_card {
|
||||
min-width: 369px;
|
||||
max-width: 369px;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" @submit.prevent="handleQuery" :model="queryParams" :inline="true">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="key键" prop="testKey">
|
||||
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@@ -11,8 +11,8 @@
|
||||
<el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@@ -26,7 +26,7 @@
|
||||
<el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">编辑</el-button>
|
||||
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
|
||||
@@ -148,14 +148,10 @@ const { queryParams, form, rules } = toRefs(data);
|
||||
/** 查询测试单列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
listDemo(queryParams.value)
|
||||
.then((res) => {
|
||||
demoList.value = res.rows;
|
||||
total.value = res.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
const res = await listDemo(queryParams.value);
|
||||
demoList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" @submit.prevent="handleQuery" :model="queryParams" :inline="true">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="树节点名" prop="treeName">
|
||||
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="bullshit__info">
|
||||
对不起,您正在寻找的页面不存在。尝试检查URL的错误,然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。
|
||||
</div>
|
||||
<router-link to="/" class="bullshit__return-home"> 返回首页 </router-link>
|
||||
<router-link to="/index" class="bullshit__return-home"> 返回首页 </router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="h-full flex flex-col p-2">
|
||||
<div class="p-2">
|
||||
<pageheader></pageheader>
|
||||
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" @submit.prevent="handleQuery" :model="queryParams" :inline="true">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="登录地址" prop="ipaddr">
|
||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@@ -29,15 +29,15 @@
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card class="flex-1" shadow="hover">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@@ -123,7 +123,7 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const selectName = ref<Array<string>>([]);
|
||||
const total = ref(0);
|
||||
const dateRange = ref<[string, string]>(['', '']);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const defaultSort = ref<any>({ prop: 'loginTime', order: 'descending' });
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
@@ -209,9 +209,3 @@ onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-table {
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
</style>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user