修复小区背景颜色,巡检点顺序一致,投诉处理按钮
This commit is contained in:
@@ -9,9 +9,9 @@ VITE_APP_ENV='development'
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API='/dev-api'
|
||||
# # 开发环境 接口代理地址
|
||||
VITE_APP_PROXY_API='http://192.168.1.222:8080'
|
||||
#VITE_APP_PROXY_API='http://192.168.1.222:8080'
|
||||
# 开发环境 接口代理地址
|
||||
#VITE_APP_PROXY_API='http://192.168.1.6:8080'
|
||||
VITE_APP_PROXY_API='http://192.168.1.6:8080'
|
||||
# 图片基础地址
|
||||
VITE_IMG_URL='http://192.168.1.222:8080'
|
||||
|
||||
|
||||
@@ -80,3 +80,49 @@ export const list_statapi = (query?: { taskTimeBegin: string; taskTimeEnd: strin
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
export type exportPageApiQuery = {
|
||||
/**
|
||||
* 数据类型:1-日报 / 2-周报 / 3-月报
|
||||
*/
|
||||
dataType?: string;
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
pageNum: number;
|
||||
/**
|
||||
* 每页条数
|
||||
*/
|
||||
pageSize: number;
|
||||
/**
|
||||
* 查询开始日期
|
||||
*/
|
||||
queryDateBegin?: string;
|
||||
/**
|
||||
* 查询结束日期
|
||||
*/
|
||||
queryDateEnd?: string;
|
||||
/**
|
||||
* 日期
|
||||
*/
|
||||
statDate?: string;
|
||||
};
|
||||
|
||||
type exportAllApiQuery = Omit<exportPageApiQuery, 'pageSize' | 'pageNum'>;
|
||||
/** 导出当前页 数据api */
|
||||
export const exportPageApi = (data: exportPageApiQuery): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/inspection/data/export/page',
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/** 导出 所有 数据api */
|
||||
export const exportAllApi = (data: exportAllApiQuery): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/inspection/data/export',
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,17 +3,12 @@ export interface PlanVO {
|
||||
* 主键ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
inspectorIds: string;
|
||||
/**
|
||||
* 巡检计划名称
|
||||
*/
|
||||
planName: string;
|
||||
|
||||
/**
|
||||
* 巡检人员ID,多个用逗号分隔
|
||||
*/
|
||||
inspectorIds: string;
|
||||
|
||||
/**
|
||||
* 执行周期,如:开始日期-结束日期
|
||||
*/
|
||||
@@ -33,6 +28,11 @@ export interface PlanVO {
|
||||
* 巡检设置:0-必须拍照,1-可以跳检
|
||||
*/
|
||||
inspectSetting: number;
|
||||
inspectSettingDict: {
|
||||
dictLabel: string;
|
||||
dictValue: string;
|
||||
listClass: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 计划路线,多个用逗号分隔
|
||||
@@ -53,7 +53,11 @@ export interface PlanVO {
|
||||
* 执行周期具体日期
|
||||
*/
|
||||
executeDay: string;
|
||||
|
||||
executeDayList: {
|
||||
dictLabel: string;
|
||||
dictValue: string;
|
||||
listClass: string;
|
||||
}[];
|
||||
/** 巡检人员信息 */
|
||||
inspectorList: {
|
||||
'userId': string;
|
||||
|
||||
@@ -120,3 +120,13 @@ export const queryResidentList_Cars = (query: { pageNum: number; pageSize: numbe
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 生成账单
|
||||
*/
|
||||
export const manualGenerateApi = (data: { billId: string; chargePeriod: string; yearMonths?: string[]; year?: string[] }) => {
|
||||
return request({
|
||||
url: '/bill/manualGenerate',
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ export interface BillVO {
|
||||
* 账单管理表id
|
||||
*/
|
||||
id: string;
|
||||
billName:string;
|
||||
|
||||
/**
|
||||
* 账单编号
|
||||
@@ -106,7 +107,7 @@ export interface BillForm extends BaseEntity {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
cerateTime?: string;
|
||||
createTime?: string;
|
||||
}
|
||||
|
||||
export interface BillQuery extends PageQuery {
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface DeviceVO {
|
||||
* 设备编号
|
||||
*/
|
||||
deviceCode: string;
|
||||
shelfLife:string;
|
||||
|
||||
/**
|
||||
* 设备型号
|
||||
|
||||
@@ -80,7 +80,7 @@ export interface ResidentForm extends BaseEntity {
|
||||
* 主键 住户管理id
|
||||
*/
|
||||
userId?: string;
|
||||
unitNoId: string;
|
||||
unitNoId?: string;
|
||||
|
||||
/**
|
||||
* 住户编号
|
||||
|
||||
@@ -260,30 +260,3 @@ aside {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,31 @@ function clearLocation() {
|
||||
markers.value = [];
|
||||
}
|
||||
|
||||
let lastFitTime = 0;
|
||||
let fitTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
const FIT_THROTTLE_MS = 100; // 节流间隔(ms)
|
||||
// === 新增函数 ===
|
||||
function throttledFitView() {
|
||||
const now = Date.now();
|
||||
if (now - lastFitTime >= FIT_THROTTLE_MS) {
|
||||
// 距离上次调用已超过阈值,立即执行
|
||||
if (fitTimer) {
|
||||
clearTimeout(fitTimer);
|
||||
fitTimer = null;
|
||||
}
|
||||
fitMapView(Array.from(AddMarkered.values()));
|
||||
lastFitTime = now;
|
||||
} else if (!fitTimer) {
|
||||
// 未超过阈值,延迟到阈值时再执行
|
||||
fitTimer = setTimeout(() => {
|
||||
fitMapView(Array.from(AddMarkered.values()));
|
||||
lastFitTime = Date.now();
|
||||
fitTimer = null;
|
||||
}, FIT_THROTTLE_MS);
|
||||
}
|
||||
// 如果已经有定时器在等,不重复创建
|
||||
}
|
||||
|
||||
// ===================== 多点标记(可增删) =====================
|
||||
function addMarker_more(angular: number[], pointName: string, pointId: string) {
|
||||
if (!isMapAvailable()) {
|
||||
@@ -145,7 +170,8 @@ function addMarker_more(angular: number[], pointName: string, pointId: string) {
|
||||
map.value.remove(AddMarkered.get(pointId));
|
||||
AddMarkered.delete(pointId);
|
||||
// 删除后重新适配视野
|
||||
fitMapView(Array.from(AddMarkered.values()));
|
||||
// fitMapView(Array.from(AddMarkered.values()));
|
||||
throttledFitView();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,7 +187,8 @@ function addMarker_more(angular: number[], pointName: string, pointId: string) {
|
||||
});
|
||||
AddMarkered.set(pointId, marker);
|
||||
markers.value.push(marker);
|
||||
fitMapView(Array.from(AddMarkered.values()));
|
||||
// fitMapView(Array.from(AddMarkered.values()));
|
||||
throttledFitView();
|
||||
return marker;
|
||||
}
|
||||
|
||||
@@ -320,6 +347,10 @@ onUnmounted(() => {
|
||||
AMAP.value = null;
|
||||
map.value = null;
|
||||
mapReady.value = false;
|
||||
if (fitTimer) {
|
||||
clearTimeout(fitTimer);
|
||||
fitTimer = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -92,6 +92,28 @@ function loadTDT(): Promise<any> {
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
let lastFitTime = 0;
|
||||
let fitTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
const FIT_THROTTLE_MS = 100; // 节流间隔(ms)
|
||||
function throttledFitView(data: any[]) {
|
||||
const now = Date.now();
|
||||
if (now - lastFitTime >= FIT_THROTTLE_MS) {
|
||||
if (fitTimer) {
|
||||
clearTimeout(fitTimer);
|
||||
fitTimer = null;
|
||||
}
|
||||
const points = data.map((m: any) => m.getLngLat());
|
||||
fitMapView(points);
|
||||
lastFitTime = now;
|
||||
} else if (!fitTimer) {
|
||||
fitTimer = setTimeout(() => {
|
||||
const points = data.map((m: any) => m.getLngLat());
|
||||
fitMapView(points);
|
||||
lastFitTime = Date.now();
|
||||
fitTimer = null;
|
||||
}, FIT_THROTTLE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
/** 根据提供的 坐标点数组 设置地图视野,调整后的视野会保证包含提供的坐标点。 */
|
||||
function fitMapView(overlays: any[] = []) {
|
||||
@@ -106,7 +128,7 @@ function isMapAvailable() {
|
||||
/** 点击事件 */
|
||||
function bindMapClick() {
|
||||
if (!isMapAvailable()) return;
|
||||
map.addEventListener('click', (e) => {
|
||||
map.addEventListener('click', (e: { lnglat: { lng: any; lat: any } }) => {
|
||||
const { lng, lat } = e.lnglat;
|
||||
emits('clickPoint', [lng, lat]);
|
||||
});
|
||||
@@ -125,7 +147,7 @@ function addMarker_only(LngLat: LngLat, pointName: string = '巡检点') {
|
||||
//向地图上添加标注
|
||||
markers = [marker];
|
||||
map.addOverLay(marker);
|
||||
fitMapView(markers.map((item) => item.getLngLat()));
|
||||
throttledFitView(markers);
|
||||
return marker;
|
||||
}
|
||||
/** 清空单点标记 */
|
||||
@@ -151,6 +173,7 @@ function addMarker_more(LngLat: LngLat, pointName: string, pointId: string) {
|
||||
});
|
||||
PointMap.set(pointId, marker);
|
||||
map.addOverLay(marker);
|
||||
throttledFitView([marker]);
|
||||
}
|
||||
|
||||
// !===================================================================
|
||||
@@ -164,7 +187,7 @@ function initDrawTool() {
|
||||
handler.on('draw', lineDraw);
|
||||
}
|
||||
// 监听 绘画完成事件
|
||||
function lineDraw(data) {
|
||||
function lineDraw(data: { currentPolyline: any }) {
|
||||
if (lines.length > 0) {
|
||||
lines.forEach((item) => {
|
||||
map.removeOverLay(item);
|
||||
@@ -225,6 +248,10 @@ function clearMapMarker() {
|
||||
} else {
|
||||
waitQueue.value.clear = true;
|
||||
}
|
||||
if (fitTimer) {
|
||||
clearTimeout(fitTimer);
|
||||
fitTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -271,6 +298,11 @@ onUnmounted(() => {
|
||||
|
||||
// 销毁地图实例
|
||||
map = null;
|
||||
|
||||
if (fitTimer) {
|
||||
clearTimeout(fitTimer);
|
||||
fitTimer = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ import { flowHisTaskList } from '@/api/workflow/instance';
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import { listByIds } from '@/api/system/oss';
|
||||
import FlowChart from '@/components/Process/flowChart.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
|
||||
const props = defineProps({
|
||||
@@ -101,9 +102,8 @@ const init = async (businessId: string | number) => {
|
||||
}
|
||||
});
|
||||
};
|
||||
const getIds = async (ids: string | number) => {
|
||||
const res = await listByIds(ids);
|
||||
return res;
|
||||
const getIds = async (ids: string) => {
|
||||
return listByIds(ids);
|
||||
};
|
||||
|
||||
/** 下载按钮操作 */
|
||||
|
||||
160
src/components/StepTimeline/index.vue
Normal file
160
src/components/StepTimeline/index.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<div class="step-timeline">
|
||||
<div v-for="(item, index) in steps" :key="index" class="step-item" :class="item.status">
|
||||
<div class="step-node">
|
||||
<div class="step-circle">
|
||||
<el-icon v-if="item.status === 'completed'" :size="12"><Check /></el-icon>
|
||||
<span v-else>{{ index + 1 }}</span>
|
||||
</div>
|
||||
<div v-if="index > 0" class="step-line"></div>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="step-title">
|
||||
<slot name="title" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
<div v-if="item.wrap === true">
|
||||
<div class="step-subtitle">
|
||||
<slot name="subtitle" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
<div class="step-time">
|
||||
<slot name="time" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span>
|
||||
<slot name="subtitle" :item="item" :index="index"></slot>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<slot name="time" :item="item" :index="index"></slot>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Check } from '@element-plus/icons-vue';
|
||||
|
||||
export interface StepItem {
|
||||
status: 'completed' | 'pending' | 'waiting';
|
||||
title: string;
|
||||
subtitle: string;
|
||||
time: string;
|
||||
wrap: boolean;
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
steps: StepItem[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.step-timeline {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.step-node {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.step-line {
|
||||
width: 2px;
|
||||
flex: 1;
|
||||
min-height: 20px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 已完成 */
|
||||
.step-item.completed {
|
||||
color: #409eff;
|
||||
.step-circle {
|
||||
background-color: #fff;
|
||||
color: #409eff;
|
||||
border: 1px solid #409eff;
|
||||
}
|
||||
|
||||
.step-line {
|
||||
background-color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 进行中 */
|
||||
.step-item.pending {
|
||||
color: #409eff;
|
||||
.step-circle {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
.step-line {
|
||||
background-color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 未完成 */
|
||||
.step-item.waiting {
|
||||
color: #cccccc;
|
||||
.step-circle {
|
||||
background-color: #fff;
|
||||
color: #cccccc;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
.step-line {
|
||||
border-left: 2px dashed #cccccc;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
.step-content {
|
||||
padding-bottom: 4px;
|
||||
min-height: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.step-subtitle {
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.step-time {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -161,7 +161,7 @@ watch(
|
||||
position: relative;
|
||||
background: #dfedff;
|
||||
background: transparent;
|
||||
border-bottom: 1px solid #dfedff;
|
||||
//border-bottom: 1px solid #dfedff;
|
||||
|
||||
color: #c0c4cc;
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
<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>
|
||||
<div class="navbarContant">
|
||||
<navbar ref="navbarRef" @set-layout="setLayout" />
|
||||
</div>
|
||||
<app-main />
|
||||
<i class="bgColor" v-if="bgColorStore.isShow"></i>
|
||||
<settings ref="settingRef" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -23,9 +24,12 @@ import { AppMain, Navbar, Settings } from './components';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
// import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
import { useBgColor } from '@/store/modules/bgColor';
|
||||
import { initWebSocket } from '@/utils/websocket';
|
||||
import { initSSE } from '@/utils/sse';
|
||||
|
||||
const bgColorStore = useBgColor();
|
||||
|
||||
// ==========================================
|
||||
// ✅ 第2步:缩放逻辑(从旧 script 移过来)
|
||||
// ==========================================
|
||||
@@ -120,7 +124,6 @@ const setLayout = () => {
|
||||
<style lang="scss" scoped>
|
||||
@use '@/assets/styles/mixin.scss';
|
||||
@use '@/assets/styles/variables.module.scss' as *;
|
||||
//8^▐╬╬2╬╬>╘
|
||||
.app-wrapper {
|
||||
@include mixin.clearfix;
|
||||
position: relative;
|
||||
@@ -139,6 +142,10 @@ const setLayout = () => {
|
||||
background-color: #dfedff;
|
||||
}
|
||||
|
||||
.navbarContant {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
}
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
@@ -170,4 +177,17 @@ const setLayout = () => {
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
.bgColor {
|
||||
width: 850px;
|
||||
height: 850px;
|
||||
background: #fdf1ee;
|
||||
filter: blur(200px);
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
right: -10%;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
13
src/store/modules/bgColor.ts
Normal file
13
src/store/modules/bgColor.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useBgColor = defineStore('backgroundColor', () => {
|
||||
const isShow = ref(false);
|
||||
const toggleBgColor = (bol: boolean = false) => {
|
||||
isShow.value = bol;
|
||||
console.log(isShow.value);
|
||||
};
|
||||
return {
|
||||
toggleBgColor,
|
||||
isShow
|
||||
};
|
||||
});
|
||||
@@ -83,6 +83,14 @@ export function convertToChineseCapital(num: number | string): string {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化为Big实例,空/undefined/null转0
|
||||
* @param num 数字 | 数字字符串
|
||||
*/
|
||||
function toBig(num: string | number | undefined | null): Big {
|
||||
if (num === null || num === undefined || num === '') return new Big(0);
|
||||
return new Big(num);
|
||||
}
|
||||
/**
|
||||
* 金额加法
|
||||
* @param a 数值
|
||||
@@ -93,56 +101,46 @@ export function moneyAdd(a: number | string = 0, b: number | string = 0): string
|
||||
return new Big(a).plus(b).toFixed(2);
|
||||
}
|
||||
|
||||
// 金额减法
|
||||
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;
|
||||
/**
|
||||
* 减法 a - b
|
||||
*/
|
||||
export function sub(a: string | number, b: string | number): number {
|
||||
return Number(toBig(a).minus(toBig(b)));
|
||||
}
|
||||
|
||||
// 金额乘法
|
||||
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);
|
||||
/**
|
||||
* 乘法 a * b
|
||||
*/
|
||||
export function mul(a: string | number, b: string | number): number {
|
||||
return Number(toBig(a).times(toBig(b)));
|
||||
}
|
||||
|
||||
// 金额除法
|
||||
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);
|
||||
/**
|
||||
* 除法 a / b
|
||||
* @throws 除数为0抛异常,业务try catch捕获
|
||||
*/
|
||||
export function div(a: string | number, b: string | number): number {
|
||||
const bigB = toBig(b);
|
||||
if (bigB.eq(0)) throw new Error('除数不能为0');
|
||||
return Number(toBig(a).div(bigB));
|
||||
}
|
||||
|
||||
// 保留2位小数(金额专用)
|
||||
export function toFixed2(val) {
|
||||
return Number(val).toFixed(2);
|
||||
}
|
||||
// 判断 a 和 b 是否数值相等
|
||||
export function eq(a: string | number, b: string | number): boolean {
|
||||
return toBig(a).eq(toBig(b));
|
||||
}
|
||||
/**
|
||||
* 金额保留指定位小数(四舍五入,默认2位)
|
||||
* @param num 计算结果
|
||||
* @param digit 保留位数
|
||||
*/
|
||||
export function toFixedMoney(num: string | number, digit = 2): number {
|
||||
return Number(toBig(num).toFixed(digit, Big.roundHalfUp));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 智能金额格式化(带单位:元/万元/亿元)
|
||||
|
||||
@@ -216,7 +216,7 @@ function headerToken() {
|
||||
Authorization: 'Bearer ' + useStore.token
|
||||
};
|
||||
}
|
||||
|
||||
const allowImgSuffix = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'];
|
||||
/** 检测文件大小和格式 */
|
||||
function handleBeforeUpload(file: UploadFile): Promise<boolean | { file: UploadFile; type: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -226,7 +226,7 @@ function handleBeforeUpload(file: UploadFile): Promise<boolean | { file: UploadF
|
||||
type: '文件大小错误',
|
||||
file: file
|
||||
});
|
||||
} else if (file.raw.type !== 'image/jpeg' && file.raw.type !== 'image/png') {
|
||||
} else if (!allowImgSuffix.includes(file.raw.type)) {
|
||||
reject({
|
||||
type: '文件类型错误',
|
||||
file: file
|
||||
@@ -355,7 +355,7 @@ const cancelForm = () => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
background: linear-gradient(180deg, #deedff 0%, #f8f9fe 50%);
|
||||
background: #deedff;
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<script lang="ts" setup>
|
||||
import defaultVilageinfoImage from '@/assets/images/villageimage.png';
|
||||
import Navbar from '@/layout/components/Navbar.vue';
|
||||
import { deleteVillageByIdAPI, getCommunitylistAPI, switchVillageAPI } from '@/api/system/community/index';
|
||||
import { deleteVillageByIdAPI, getCommunitylistAPI, switchVillageAPI } from '@/api/system/community';
|
||||
import type { communitylist_rows_type } from '@/api/system/community/type';
|
||||
import { AddLocation, Picture } from '@element-plus/icons-vue';
|
||||
import { useHouseStore } from '@/store/modules/house';
|
||||
@@ -119,47 +119,35 @@ function handleclick(item: communitylist_rows_type) {
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
background: linear-gradient(180deg, #deedff 0%, #f8f9fe 50%);
|
||||
|
||||
position: relative;
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
& > div {
|
||||
flex: 1;
|
||||
}
|
||||
& > span {
|
||||
padding-left: 20px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
.bgcolor {
|
||||
width: 1085px;
|
||||
width: 571px;
|
||||
height: 571px;
|
||||
background: #fdf1ee;
|
||||
filter: blur(400px);
|
||||
filter: blur(200px);
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transform: translateY(-50%);
|
||||
z-index: 90;
|
||||
top: -210px;
|
||||
right: 0;
|
||||
pointer-events: none; /* 🔥 让它不拦截鼠标点击,穿透到下面 */
|
||||
@media (max-width: 1540px) {
|
||||
width: 800px;
|
||||
height: 400px;
|
||||
}
|
||||
@media (max-width: 1280px) {
|
||||
width: 600px;
|
||||
height: 300px;
|
||||
}
|
||||
@media (max-width: 1030px) {
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.image-slot {
|
||||
@@ -172,6 +160,8 @@ function handleclick(item: communitylist_rows_type) {
|
||||
background: #fff;
|
||||
}
|
||||
.containerbox {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
@@ -208,9 +198,7 @@ function handleclick(item: communitylist_rows_type) {
|
||||
.communityBody {
|
||||
padding: 20px;
|
||||
color: #000;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
@media (max-width: 2350px) {
|
||||
@@ -267,7 +255,6 @@ function handleclick(item: communitylist_rows_type) {
|
||||
border-right: 1px solid #ccc;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #4791ff;
|
||||
cursor: pointer;
|
||||
line-height: 60px;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-error="handleError"
|
||||
:limit="1"
|
||||
>
|
||||
@@ -310,7 +311,15 @@ const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
const handleError: UploadProps['onError'] = (error: Error) => {
|
||||
console.log(error);
|
||||
};
|
||||
|
||||
const allowImgSuffix = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'];
|
||||
/** 检测文件大小和格式 */
|
||||
const handleBeforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
if (!allowImgSuffix.includes(rawFile.name.split('.')[1])) {
|
||||
ElMessage.error('文件类型错误,请重新上传');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// ! 投诉 ====================================================================================================
|
||||
|
||||
// ! 签到 =======================================
|
||||
|
||||
@@ -62,9 +62,10 @@ function headerToken() {
|
||||
Authorization: 'Bearer ' + useStore.token
|
||||
};
|
||||
}
|
||||
const allowImgSuffix = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'];
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
const type = rawFile.type.split('/').pop();
|
||||
if (['png', 'jpg', 'jpeg'].includes(type)) {
|
||||
if (allowImgSuffix.includes(type)) {
|
||||
if (rawFile.size / 1024 / 1024 <= 10) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -14,35 +14,35 @@
|
||||
<div class="carInfoBox">
|
||||
<div class="carInfo_item">
|
||||
<div class="label">投诉类型</div>
|
||||
<div class="main">{{ form.type }}</div>
|
||||
<div class="main">{{ formInfo.type }}</div>
|
||||
</div>
|
||||
|
||||
<div class="carInfo_item">
|
||||
<div class="label">投诉人姓名</div>
|
||||
<div class="main">{{ form.complaintName }}</div>
|
||||
<div class="main">{{ formInfo.complaintName }}</div>
|
||||
</div>
|
||||
|
||||
<div class="carInfo_item">
|
||||
<div class="label">手机号码</div>
|
||||
<div class="main">{{ form.phone }}</div>
|
||||
<div class="main">{{ formInfo.phone }}</div>
|
||||
</div>
|
||||
|
||||
<div class="carInfo_item">
|
||||
<div class="label">投诉时间</div>
|
||||
<div class="main">{{ form.createTime }}</div>
|
||||
<div class="main">{{ formInfo.createTime }}</div>
|
||||
</div>
|
||||
|
||||
<div class="carInfo_item">
|
||||
<div class="label">处理状态</div>
|
||||
<div class="main">
|
||||
<DictTag :options="com_complaint_status" :value="form.status"></DictTag>
|
||||
<DictTag :options="com_complaint_status" :value="formInfo.status"></DictTag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carInfoBox signLe">
|
||||
<div class="carInfo_item">
|
||||
<div class="label">问题描述</div>
|
||||
<div class="main">{{ form.problemDes }}</div>
|
||||
<div class="main">{{ formInfo.problemDes }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carInfoBox signLe">
|
||||
@@ -75,14 +75,14 @@
|
||||
<el-form ref="formRef" :rules="rules" class="m-auto" :inline="false" label-width="100px" :model="form">
|
||||
<el-form-item label="处理状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio value="2">处理完成</el-radio>
|
||||
<el-radio value="1">处理完成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理人员" prop="handleId">
|
||||
<repairUser
|
||||
:is-multiple="false"
|
||||
:username="form.handleName"
|
||||
:userid="form.handleId ?? ''"
|
||||
:username="formInfo.handleName"
|
||||
:userid="formInfo.handleId"
|
||||
returnvalue="*"
|
||||
@change="handleChange"
|
||||
></repairUser>
|
||||
@@ -91,7 +91,7 @@
|
||||
<el-input type="textarea" :rows="5" v-model="form.handleContent"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-if="form.status === '0'" @click="submitForm">提交</el-button>
|
||||
<el-button type="primary" v-if="form.status !== '0'" @click="submitForm">提交</el-button>
|
||||
<el-button @click="handleBack">返回</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -115,7 +115,7 @@ const { com_complaint_status } = toRefs<any>(proxy?.useDict('com_complaint_statu
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const form = ref({
|
||||
const formInfo = ref({
|
||||
'id': null,
|
||||
'type': '',
|
||||
'typeId': null,
|
||||
@@ -129,24 +129,34 @@ const form = ref({
|
||||
'handleContent': '',
|
||||
'createTime': null
|
||||
});
|
||||
const form = ref({
|
||||
'id': null,
|
||||
'status': '1',
|
||||
'handleId': '',
|
||||
'handleName': '',
|
||||
'handleContent': ''
|
||||
});
|
||||
const rules = {
|
||||
status: [{ required: true, message: '选择投诉处理状态', trigger: 'blur' }],
|
||||
handleContent: [{ required: true, message: '投诉处理内容不能为空', trigger: 'blur' }]
|
||||
handleContent: [{ required: true, message: '投诉处理内容不能为空', trigger: 'blur' }],
|
||||
handleId: [{ required: true, message: '投诉处理人员不能为空', trigger: 'blur' }]
|
||||
};
|
||||
const userid = ref();
|
||||
const problemImageUrlList = ref([]);
|
||||
|
||||
// ! 投诉 ====================================================================================================
|
||||
async function init() {
|
||||
const res2 = await listComplaintType();
|
||||
getComplaint(userid.value).then((res) => {
|
||||
form.value = {
|
||||
...form.value,
|
||||
formInfo.value = {
|
||||
...formInfo.value,
|
||||
...res.data
|
||||
};
|
||||
console.log(formInfo.value);
|
||||
problemImageUrlList.value = res.data.problemImageUrl ? res.data.problemImageUrl.split(',') : [];
|
||||
const find = res2.rows.find((item) => item.id === form.value.typeId);
|
||||
const find = res2.rows.find((item) => item.id === formInfo.value.typeId);
|
||||
if (find) {
|
||||
form.value.type = find.name;
|
||||
formInfo.value.type = find.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -168,7 +178,12 @@ const submitForm = () => {
|
||||
formRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (userid.value) {
|
||||
updateComplaint(form.value).then(() => {
|
||||
form.value.id = userid.value;
|
||||
const obj = {
|
||||
...formInfo.value,
|
||||
...form.value
|
||||
};
|
||||
updateComplaint(obj).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleBack();
|
||||
});
|
||||
|
||||
@@ -63,7 +63,6 @@ import { ref } from 'vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { addDecoration, getDecoration, updateDecoration } from '@/api/system/Decoration';
|
||||
import { useHouseStore } from '@/store/modules/house';
|
||||
import { validator } from '@/utils/Reg';
|
||||
|
||||
const houseStore = useHouseStore();
|
||||
const treedata = ref([]);
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
:show-file-list="true"
|
||||
:on-remove="handleAvatarRemove"
|
||||
:on-change="handleProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
>
|
||||
<div class="uploadBtn flex flex-items-center">
|
||||
<el-icon><Upload /></el-icon>
|
||||
@@ -94,7 +95,7 @@ import editor from '@/components/Editor/index.vue';
|
||||
import { ref } from 'vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { addHandleLog, getHandleLog, updateHandleLog, uploadAttachments } from '@/api/system/HandleLog';
|
||||
import { UploadFiles, UploadProps, UploadUserFile } from 'element-plus';
|
||||
import { UploadFiles, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Upload } from '@element-plus/icons-vue'; // 确保引入图标
|
||||
@@ -143,6 +144,8 @@ const handleAvatarRemove: UploadProps['onRemove'] = (uploadFile: UploadUserFile,
|
||||
// 定义大小限制常量 (单位: MB)
|
||||
const MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024; // 10MB in bytes
|
||||
const MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024; // 20MB in bytes
|
||||
// 禁止的危险文件后缀
|
||||
const forbidSuffix = ['exe', 'msi', 'bat', 'cmd', 'sh', 'apk', 'dmg'];
|
||||
// 添加一个锁,防止 on-change 递归调用导致重复提示
|
||||
const isChecking = ref(false);
|
||||
const handleProgress: UploadProps['onChange'] = (uploadFile: UploadUserFile, uploadFiles: UploadFiles) => {
|
||||
@@ -225,6 +228,16 @@ const handleProgress: UploadProps['onChange'] = (uploadFile: UploadUserFile, upl
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
const ext = rawFile.name.toLowerCase().slice(rawFile.name.lastIndexOf('.'));
|
||||
if (blockedExts.includes(ext)) {
|
||||
ElMessage.warning(`禁止上传 ${ext} 文件`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// ! 初始 ====================================================================================================
|
||||
function init() {
|
||||
console.log('init');
|
||||
|
||||
@@ -15,20 +15,20 @@
|
||||
<el-input v-model.trim="form.noticeTitle" placeholder="请输入公告标题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作者" prop="author">
|
||||
<el-input v-model.trim="form.author" placeholder="请输入作者" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">-->
|
||||
<!-- <el-form-item label="作者" prop="author">-->
|
||||
<!-- <el-input v-model.trim="form.author" placeholder="请输入作者" />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="公告紧急程度" prop="urgencyLevel">
|
||||
<el-select v-model="form.urgencyLevel" clearable placeholder="请选择公告紧急程度">
|
||||
<el-option v-for="dict in com_noticepc_level" :key="dict.value" :label="dict.label" :value="Number(dict.value)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">-->
|
||||
<!-- <el-form-item label="公告紧急程度" prop="urgencyLevel">-->
|
||||
<!-- <el-select v-model="form.urgencyLevel" clearable placeholder="请选择公告紧急程度">-->
|
||||
<!-- <el-option v-for="dict in com_noticepc_level" :key="dict.value" :label="dict.label" :value="Number(dict.value)" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否发布" prop="publishStatus">
|
||||
<el-radio-group v-model="form.publishStatus">
|
||||
|
||||
@@ -36,19 +36,27 @@
|
||||
<el-table v-loading="loading" border :data="noticeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="公告标题" align="center" prop="noticeTitle" />
|
||||
<el-table-column label="作者" width="120" align="center" prop="author" />
|
||||
<el-table-column label="紧急程度" align="center" prop="urgencyLevel">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="com_noticepc_level" :value="scope.row.urgencyLevel"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="作者" width="120" align="center" prop="author" />-->
|
||||
<!-- <el-table-column label="紧急程度" align="center" prop="urgencyLevel">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <dict-tag :options="com_noticepc_level" :value="scope.row.urgencyLevel"></dict-tag>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column label="发布状态" align="center" prop="publishStatus">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="com_publish_status" :value="scope.row.publishStatus"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已读" width="120" align="center" prop="readNum" />
|
||||
<el-table-column label="未读" width="120" align="center" prop="unReadNum" />
|
||||
<el-table-column label="已读" width="120" align="center" prop="readNum">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.readNum ?? '--' }} 人</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="未读" width="120" align="center" prop="unReadNum">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.unReadNum ?? '--' }} 人</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发布人" align="center" prop="publishBy" />
|
||||
<el-table-column label="发布日期" align="center" prop="publishTime" width="100">
|
||||
<template #default="scope">
|
||||
@@ -57,6 +65,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="220" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleMain(scope.row)">详情</el-button>
|
||||
<el-button link type="primary" @click="handleUpdate(scope.row)" v-has-permi="['notice:notice:edit']">编辑</el-button>
|
||||
<el-button link type="primary" @click="handleDelete(scope.row)" v-has-permi="['notice:notice:remove']">删除</el-button>
|
||||
</template>
|
||||
@@ -65,6 +74,17 @@
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="MainForm.visible" title="公告详情">
|
||||
<div class="w-full h-full">
|
||||
<div v-html="MainForm.content"></div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="MainForm.visible = false">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -170,6 +190,15 @@ const handleUpdate = (row?: NoticeVO) => {
|
||||
}
|
||||
});
|
||||
};
|
||||
const MainForm = ref({
|
||||
visible: false,
|
||||
content: ''
|
||||
});
|
||||
/** 详情按钮操作 */
|
||||
const handleMain = (row: NoticeVO) => {
|
||||
MainForm.value.visible = true;
|
||||
MainForm.value.content = row.noticeContent;
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: NoticeVO) => {
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
list-type="picture-card"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="handleChangeFile"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-upload>
|
||||
@@ -108,7 +109,7 @@ import { ref } from 'vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { hasFormData } from '@/utils/house';
|
||||
import Holder from '@/components/Holder/index.vue';
|
||||
import { UploadProps, UploadUserFile } from 'element-plus';
|
||||
import { UploadFiles, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus';
|
||||
import { addRepair, getRepair, updateRepair, uploadRepairImages } from '@/api/system/Repair';
|
||||
import { gettreelistRepairProject } from '@/api/system/RepairProject';
|
||||
import { useHouseStore } from '@/store/modules/house';
|
||||
@@ -201,6 +202,15 @@ const dialogVisible = ref(false);
|
||||
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||
console.log(uploadFile, uploadFiles);
|
||||
};
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
const handleChangeFile: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
const ext = rawFile.name.toLowerCase().slice(rawFile.name.lastIndexOf('.'));
|
||||
if (blockedExts.includes(ext)) {
|
||||
ElMessage.warning(`禁止上传 ${ext} 文件`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
dialogImageUrl.value = uploadFile.url!;
|
||||
|
||||
@@ -49,9 +49,14 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="报修房屋" align="center" show-overflow-tooltip prop="houseName" />
|
||||
<el-table-column label="维修项目" align="center" prop="maintenanceItemName" />
|
||||
<el-table-column label="标题" align="center" prop="item" />
|
||||
<el-table-column label="问题描述" align="center" prop="problem" />
|
||||
<el-table-column label="报修人" width="100" align="center" prop="residentName" />
|
||||
<el-table-column label="联系电话" width="120" align="center" prop="phone" />
|
||||
<el-table-column label="维修人员" width="100" align="center" prop="repairName">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.repairName ?? '---' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预约日期" align="center" prop="orderDate" width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.orderDate, '{y}-{m}-{d}') }}</span>
|
||||
@@ -62,7 +67,6 @@
|
||||
<dict-tag :options="com_repair_status" :value="scope.row.problemStatus || ''"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleShare(scope.row)" v-has-permi="['repair:repair:query']">{{
|
||||
@@ -91,11 +95,11 @@ import { checkPermi } from '@/utils/permission';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { com_repair_status } = toRefs<any>(proxy?.useDict('com_repair_status'));
|
||||
|
||||
interface repairlistType extends RepairVO {
|
||||
interface repairListType extends RepairVO {
|
||||
maintenanceItemPath?: string;
|
||||
residentName: string;
|
||||
}
|
||||
const repairList = ref<repairlistType[]>([]);
|
||||
const repairList = ref<repairListType[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
@@ -147,7 +151,7 @@ const data = reactive<PageData<RepairForm, RepairQuery>>({
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
// != 维修项目u ===========================================================================
|
||||
|
||||
@@ -193,7 +197,7 @@ const handleAdd = () => {
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: RepairVO) => {
|
||||
const handleUpdate = (row?: RepairVO) => {
|
||||
const _id = row?.id || ids.value[0];
|
||||
router.push({
|
||||
path: '/repair/editRepair',
|
||||
@@ -203,7 +207,7 @@ const handleUpdate = async (row?: RepairVO) => {
|
||||
});
|
||||
};
|
||||
/** 分配人员 */
|
||||
const handleShare = (row) => {
|
||||
const handleShare = (row: { id: string }) => {
|
||||
const _id = row?.id || ids.value[0];
|
||||
router.push({
|
||||
path: '/repair/repairMain',
|
||||
|
||||
@@ -15,56 +15,64 @@
|
||||
</template>
|
||||
<div class="w-full h-full CarInfoBox">
|
||||
<el-row class="mb-20px">
|
||||
<el-col :span="10">
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">报修房屋</div>
|
||||
<div class="label">报修房屋:</div>
|
||||
<div class="main">{{ form.houseName }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4"></el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">维修项目</div>
|
||||
<div class="label">维修项目:</div>
|
||||
<div class="main">{{ form.maintenanceItemName }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">问题描述:</div>
|
||||
<div class="main">{{ form.problem }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="mb-20px">
|
||||
<el-col :span="10">
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">报修人</div>
|
||||
<div class="label">报修人:</div>
|
||||
<div class="main">{{ form.residentName }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4"></el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">手机号码</div>
|
||||
<div class="label">手机号码:</div>
|
||||
<div class="main">{{ form.phone }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="mb-20px">
|
||||
<el-col>
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">预约日期</div>
|
||||
<div class="label">预约日期:</div>
|
||||
<div class="main">{{ form.orderDate }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="mb-20px">
|
||||
<el-col>
|
||||
<!-- <el-col :span="8">-->
|
||||
<!-- <div class="carInfo_Item">-->
|
||||
<!-- <div class="label">提交人:</div>-->
|
||||
<!-- <div class="main">{{ form.problem }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="8">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">问题描述</div>
|
||||
<div class="main">{{ form.problem }}</div>
|
||||
<div class="label">提交时间:</div>
|
||||
<div class="main">{{ form.createTime }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="form.problemImageUrl.trim() === ''">
|
||||
<el-col :span="24">
|
||||
<div class="carInfo_Item">
|
||||
<div class="label">附件</div>
|
||||
<div class="label">附件:</div>
|
||||
<div class="main fileImagebox">
|
||||
<el-image
|
||||
:preview-teleported="true"
|
||||
@@ -115,31 +123,37 @@
|
||||
</div>
|
||||
</template>
|
||||
<div class="h-full w-full">
|
||||
<el-steps space="108px" direction="vertical" :active="activeStop">
|
||||
<el-step>
|
||||
<template #title>
|
||||
<span>已提交维护信息</span>
|
||||
</template>
|
||||
<template #description> {{ reviewInfo.submitTime ?? '' }} </template>
|
||||
</el-step>
|
||||
<el-step>
|
||||
<template #title>
|
||||
<span>{{ reviewInfo.allocateStatus === '0' ? '待分配' : '已分配' }} </span>
|
||||
</template>
|
||||
<template #description>{{ reviewInfo.allocateTime ?? '等待物业派单中' }} </template>
|
||||
</el-step>
|
||||
<el-step>
|
||||
<template #title>
|
||||
<span>{{ reviewInfo.completeStatus === '0' ? '待维修' : '已维修' }} </span>
|
||||
</template>
|
||||
<template #description> {{ reviewInfo.completeTime ?? '维修人员进行维修' }}</template>
|
||||
</el-step>
|
||||
<el-step>
|
||||
<template #title>
|
||||
<span>完成维修 </span>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
<!-- <el-steps space="108px" direction="vertical" :active="activeStop">-->
|
||||
<!-- <el-step>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <span>完成维修 </span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-step>-->
|
||||
<!-- <el-step>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <span>{{ reviewInfo.completeStatus === '0' ? '待维修' : '已维修' }} </span>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #description> {{ reviewInfo.completeTime ?? '维修人员进行维修' }}</template>-->
|
||||
<!-- </el-step>-->
|
||||
<!-- <el-step>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <span>{{ reviewInfo.allocateStatus === '0' ? '待分配' : '已分配' }} </span>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #description>{{ reviewInfo.allocateTime ?? '等待物业派单中' }} </template>-->
|
||||
<!-- </el-step>-->
|
||||
<!-- <el-step>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <span>已提交维护信息</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #description> {{ reviewInfo.submitTime ?? '' }} </template>-->
|
||||
<!-- </el-step>-->
|
||||
<!-- </el-steps>-->
|
||||
|
||||
<StepTimeline :steps="stepList">
|
||||
<template #title="{ item }">{{ item.title }}</template>
|
||||
<template #subtitle="{ item }">{{ item.subtitle }}</template>
|
||||
<template #time="{ item }">{{ item.time }}</template>
|
||||
</StepTimeline>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -149,6 +163,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import StepTimeline, { StepItem } from '@/components/StepTimeline/index.vue';
|
||||
import repairUser from '@/components/Holder/repairUser.vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { getRepair, updateRepair } from '@/api/system/Repair';
|
||||
@@ -165,7 +180,12 @@ const activeStop = ref(0);
|
||||
interface formType extends RepairVO {
|
||||
problemImageUrlList: string[];
|
||||
}
|
||||
|
||||
const stepList = ref<StepItem[]>([
|
||||
{ status: 'completed', title: '提交维修信息', subtitle: '等待提交', time: '', wrap: false },
|
||||
{ status: 'pending', title: '待分配', subtitle: '等待物业派单中', time: '', wrap: true },
|
||||
{ status: 'waiting', title: '维修', subtitle: '等待维修人员维修', time: '', wrap: false },
|
||||
{ status: 'waiting', title: '完成维修', subtitle: '等待填写维修记录', time: '', wrap: false }
|
||||
]);
|
||||
const form = ref<formType>({
|
||||
'id': '',
|
||||
'houseId': '',
|
||||
@@ -239,19 +259,32 @@ async function init() {
|
||||
function handleReview() {
|
||||
if (reviewInfo.value.submitStatus === '1') {
|
||||
// 提交完成
|
||||
active.value = 1;
|
||||
activeStop.value = 1;
|
||||
stepList.value[0].status = 'completed';
|
||||
stepList.value[0].subtitle = '提交成功';
|
||||
stepList.value[1].status = 'pending';
|
||||
stepList.value[1].subtitle = '等待物业派单中';
|
||||
stepList.value[0].time = reviewInfo.value.submitTime;
|
||||
|
||||
if (reviewInfo.value.allocateStatus === '1') {
|
||||
// 分配完成
|
||||
active.value = 2;
|
||||
activeStop.value = 2;
|
||||
stepList.value[1].status = 'completed';
|
||||
stepList.value[1].title = '已分配';
|
||||
stepList.value[1].subtitle = `${form.value.repairName ?? '---'} ${form.value.repairPhone ?? '---'}`;
|
||||
stepList.value[1].time = reviewInfo.value.allocateTime;
|
||||
|
||||
stepList.value[2].status = 'pending';
|
||||
stepList.value[2].subtitle = '等待维修人员维修';
|
||||
// 维修完成
|
||||
if (reviewInfo.value.completeStatus === '1') {
|
||||
active.value = 4;
|
||||
activeStop.value = 4;
|
||||
stepList.value[2].time = reviewInfo.value.completeTime;
|
||||
stepList.value[2].status = 'completed';
|
||||
stepList.value[2].subtitle = '维修完成';
|
||||
stepList.value[3].status = 'completed';
|
||||
stepList.value[3].subtitle = '填写维修记录';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stepList.value[0].status = 'waiting';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +293,7 @@ if (route.query.id) {
|
||||
init();
|
||||
}
|
||||
|
||||
/** 派单 ╬>*/
|
||||
/** 派单 */
|
||||
function handleSend() {
|
||||
// 已分配
|
||||
form.value.problemStatus = '1';
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<el-table-column label="账单名称" align="center" prop="billName" />
|
||||
<el-table-column label="收费范围" align="center" prop="chargeScope" width="100">
|
||||
<template #default="scope">
|
||||
<template v-if="ShowHouselist.includes(scope.row.chargeTypeId)">
|
||||
<template v-if="ShowHouseList.includes(scope.row.chargeTypeId)">
|
||||
<DictTag :options="com_bill_charge_scope_house" :value="scope.row.chargeScope"></DictTag>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -56,8 +56,9 @@
|
||||
<span v-else>---</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleChange(scope.row)">生成账单</el-button>
|
||||
<el-button link type="primary" @click="handleUpdate(scope.row)" v-has-permi="['bill:bill:edit']">编辑</el-button>
|
||||
<el-button link type="primary" @click="handleMain(scope.row)" v-has-permi="['bill:bill:query']">详情</el-button>
|
||||
</template>
|
||||
@@ -65,6 +66,36 @@
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<el-dialog v-model="BillVisible" :title="BillForm.title" width="500">
|
||||
<el-form :model="BillForm" label-width="auto" style="max-width: 600px">
|
||||
<el-form-item label="账单生成时间">
|
||||
<el-date-picker
|
||||
v-if="BillForm.chargePeriod === '0'"
|
||||
v-model="BillForm.year"
|
||||
type="years"
|
||||
format="YYYY"
|
||||
value-format="YYYY"
|
||||
placeholder="选择账单生成年份"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-date-picker
|
||||
format="YYYY-MM"
|
||||
value-format="YYYY-MM"
|
||||
v-else
|
||||
v-model="BillForm.yearMonths"
|
||||
type="months"
|
||||
placeholder="选择账单生成月份"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="BillVisible = false">关闭</el-button>
|
||||
<el-button type="primary" @click="handleChangeApi"> 生成 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -72,7 +103,7 @@
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import pagination from '@/components/Pagination/index.vue';
|
||||
import DictTag from '@/components/DictTag/index.vue';
|
||||
import { listBill } from '@/api/system/SdbBill';
|
||||
import { listBill, manualGenerateApi } from '@/api/system/SdbBill';
|
||||
import { BillVO, BillQuery, BillForm } from '@/api/system/SdbBill/type';
|
||||
import { listChargeItem } from '@/api/system/SdbChargeItem';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
@@ -92,7 +123,7 @@ const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const ShowHouselist = ['2049026484272791553', '2049026503017136129'];
|
||||
const ShowHouseList = ['2049026484272791553', '2049026503017136129'];
|
||||
|
||||
const initFormData: BillForm = {
|
||||
id: undefined,
|
||||
@@ -104,7 +135,7 @@ const initFormData: BillForm = {
|
||||
endDate: undefined,
|
||||
villageId: undefined,
|
||||
remark: undefined,
|
||||
cerateTime: undefined
|
||||
createTime: undefined
|
||||
};
|
||||
const data = reactive<PageData<BillForm, BillQuery>>({
|
||||
form: { ...initFormData },
|
||||
@@ -116,7 +147,7 @@ const data = reactive<PageData<BillForm, BillQuery>>({
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form } = toRefs(data);
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
const chargeItems = ref([]);
|
||||
function init() {
|
||||
@@ -176,7 +207,7 @@ const handleUpdate = (row?: BillVO) => {
|
||||
});
|
||||
};
|
||||
|
||||
function handleMain(row) {
|
||||
function handleMain(row: BillVO) {
|
||||
router.push({
|
||||
path: '/sdb/sdbbillMain',
|
||||
query: {
|
||||
@@ -184,6 +215,44 @@ function handleMain(row) {
|
||||
}
|
||||
});
|
||||
}
|
||||
const BillVisible = ref(false);
|
||||
const BillForm = ref<{
|
||||
title: string;
|
||||
billId: string;
|
||||
chargePeriod: string;
|
||||
yearMonths?: string[];
|
||||
year?: string[];
|
||||
}>({
|
||||
title: '',
|
||||
billId: '',
|
||||
chargePeriod: '1'
|
||||
});
|
||||
function handleChange(row: BillVO) {
|
||||
clearChangeBillForm();
|
||||
BillVisible.value = true;
|
||||
BillForm.value.title = row.billName;
|
||||
BillForm.value.chargePeriod = row.chargePeriod;
|
||||
BillForm.value.billId = row.id;
|
||||
if (BillForm.value.chargePeriod === '1') {
|
||||
BillForm.value['yearMonths'] = [];
|
||||
} else {
|
||||
BillForm.value['year'] = [];
|
||||
}
|
||||
}
|
||||
function handleChangeApi() {
|
||||
manualGenerateApi(BillForm.value).then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
clearChangeBillForm();
|
||||
BillVisible.value = false;
|
||||
});
|
||||
}
|
||||
function clearChangeBillForm() {
|
||||
BillForm.value = {
|
||||
title: '',
|
||||
billId: '',
|
||||
chargePeriod: '1'
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
</el-col>
|
||||
<right-toolbar :show-add="false" :show-edit="false" :show-delete="false">
|
||||
<template #dropdown>
|
||||
<el-dropdown-item @click="handleMarkqrcode" v-if="checkPermi(['equipment:addqrcode:electricitydevice'])">
|
||||
<el-dropdown-item @click="handleMarkQRCode" v-if="checkPermi(['equipment:addqrcode:electricitydevice'])">
|
||||
<span>批量生成条形码</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="handleMarkQrcodeZip" v-if="checkPermi(['equipment:addqrcode:electricitydevice'])">
|
||||
<span>批量下载条形码</span>
|
||||
</el-dropdown-item>
|
||||
<!-- <el-dropdown-item v-has-permi="['equipment:addqrcode:electricitydevice']">
|
||||
<div @click="handleMarkqrcode">批量更新固件</div>
|
||||
<div @click="handleMarkQRCode">批量更新固件</div>
|
||||
</el-dropdown-item> -->
|
||||
</template>
|
||||
</right-toolbar>
|
||||
@@ -171,7 +171,7 @@
|
||||
</el-card>
|
||||
<!-- 添加或修改电 设备对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form v-if="dialogType === 'usedWater'" :rules="rules" ref="UsedWaterformRef" :model="UsedWaterform" label-width="100px">
|
||||
<el-form v-if="dialogType === 'usedWater'" :rules="rules" ref="UsedWaterFormRef" :model="UsedWaterform" label-width="100px">
|
||||
<el-form-item label="设备编号" prop="deviceCode"> {{ UsedWaterform.deviceCode }} </el-form-item>
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker
|
||||
@@ -198,7 +198,7 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form v-else-if="dialogType === 'Upload'" ref="UploadFileformRef" :model="UploadFileform" :rules="UploadFileformRules" label-width="100px">
|
||||
<el-form v-else-if="dialogType === 'Upload'" ref="UploadFileFormRef" :model="UploadFileForm" :rules="UploadFileFormRules" label-width="100px">
|
||||
<el-form-item label="上传更新文件" prop="file">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
@@ -227,9 +227,9 @@
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">更新到设备</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form v-else-if="dialogType === 'UpdateHouse'" ref="EditHouseformRef" :model="EditHouseform" :rules="EditHouseformRules" label-width="100px">
|
||||
<el-form v-else-if="dialogType === 'UpdateHouse'" ref="EditHouseFormRef" :model="EditHouseForm" :rules="EditHouseFormRules" label-width="100px">
|
||||
<el-form-item label="更新户号" prop="houseId">
|
||||
<el-cascader v-model="userHousepath" :options="treedata" @change="handleChange" />
|
||||
<el-cascader v-model="userHousePath" :options="treeData" @change="handleChange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="unSubmit">取消</el-button>
|
||||
@@ -264,8 +264,6 @@ import { checkPermi } from '@/utils/permission';
|
||||
import { Upload } from '@element-plus/icons-vue';
|
||||
import { CascaderValue, UploadProps, UploadRawFile } from 'element-plus';
|
||||
import { exportImagesToZip } from '@/utils/exportZip';
|
||||
import { WaterDeviceVO } from '@/api/system/SdbWaterDevice/type';
|
||||
import { waterDeviceUnbind } from '@/api/system/SdbWaterDevice';
|
||||
|
||||
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/electricityDevice/upload';
|
||||
|
||||
@@ -311,7 +309,7 @@ const getList = async () => {
|
||||
};
|
||||
// ! 用电量 =============================================================================
|
||||
const usedWaterInfo = ref(true);
|
||||
const UsedWaterformRef = ref(null);
|
||||
const UsedWaterFormRef = ref(null);
|
||||
const UsedWaterform = ref({
|
||||
deviceCode: '',
|
||||
startTime: '',
|
||||
@@ -349,14 +347,14 @@ function handleEndTime(val: string) {
|
||||
// ! =======================================================================================
|
||||
|
||||
// ? 上传固件 ==============================================================================================
|
||||
const UploadFileformRef = ref(null);
|
||||
const UploadFileFormRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
const UploadFileform = ref({
|
||||
const UploadFileForm = ref({
|
||||
id: '',
|
||||
deviceCode: '',
|
||||
file: ''
|
||||
});
|
||||
const UploadFileformRules = {
|
||||
const UploadFileFormRules = {
|
||||
file: [{ required: true, message: '更新文件不能为空', trigger: 'blur' }]
|
||||
};
|
||||
// 携带token
|
||||
@@ -387,18 +385,18 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile)
|
||||
return true;
|
||||
};
|
||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (response: any) => {
|
||||
UploadFileform.value.file = response.data.url;
|
||||
UploadFileForm.value.file = response.data.url;
|
||||
};
|
||||
|
||||
// ? 上传固件 ==============================================================================================
|
||||
|
||||
// * 编辑房屋 ==============================================================================================
|
||||
// 编辑房屋
|
||||
const EditHouseformRef = ref(null);
|
||||
const EditHouseformRules = {
|
||||
const EditHouseFormRef = ref(null);
|
||||
const EditHouseFormRules = {
|
||||
file: [{ required: true, message: '更新文件不能为空', trigger: 'blur' }]
|
||||
};
|
||||
const EditHouseform = ref({
|
||||
const EditHouseForm = ref({
|
||||
id: '',
|
||||
deviceCode: '',
|
||||
houseId: ''
|
||||
@@ -406,7 +404,7 @@ const EditHouseform = ref({
|
||||
// * 编辑房屋 ==============================================================================================
|
||||
|
||||
/** 批量生成 条形码 */
|
||||
function handleMarkqrcode() {
|
||||
function handleMarkQRCode() {
|
||||
if (ids.value.length > 0) {
|
||||
ElectricityDeviceMakerQrcode(ids.value).then(() => {
|
||||
ElMessage.success('批量生成成功');
|
||||
@@ -423,12 +421,12 @@ function handleMarkQrcodeZip() {
|
||||
const matchedList = ElectricityDeviceList.value.filter((item) => {
|
||||
return selectedIds.has(item.id) && item.url;
|
||||
});
|
||||
produceQRzip(matchedList);
|
||||
produceQRZip(matchedList);
|
||||
} else {
|
||||
ElMessage.warning('请选择设备');
|
||||
}
|
||||
}
|
||||
function produceQRzip(vals: ElectricityDeviceVO[]) {
|
||||
function produceQRZip(vals: ElectricityDeviceVO[]) {
|
||||
const arr = vals.map((item) => {
|
||||
return {
|
||||
name: item.deviceCode,
|
||||
@@ -464,12 +462,12 @@ const handleQrCode = (row: ElectricityDeviceVO) => {
|
||||
});
|
||||
};
|
||||
// * house
|
||||
const treedata = ref([]);
|
||||
const treeData = ref([]);
|
||||
const houseStore = useHouseStore();
|
||||
const userHousepath = ref<CascaderValue>([]);
|
||||
const userHousePath = ref<CascaderValue>([]);
|
||||
function handleChange(val: CascaderValue) {
|
||||
userHousepath.value = val;
|
||||
EditHouseform.value.houseId = val[2];
|
||||
userHousePath.value = val;
|
||||
EditHouseForm.value.houseId = val[2];
|
||||
}
|
||||
// * house
|
||||
const dialogType = ref<'usedWater' | 'Upload' | 'UpdateHouse'>('usedWater');
|
||||
@@ -486,13 +484,13 @@ const handleOpenDialog = (type: 'usedWater' | 'Upload' | 'UpdateHouse', row: Ele
|
||||
UsedWaterform.value.endTime = '';
|
||||
usedWaterInfo.value = true;
|
||||
} else if (type === 'Upload') {
|
||||
UploadFileform.value.file = '';
|
||||
UploadFileform.value.deviceCode = row.deviceCode;
|
||||
UploadFileform.value.id = row.id;
|
||||
UploadFileForm.value.file = '';
|
||||
UploadFileForm.value.deviceCode = row.deviceCode;
|
||||
UploadFileForm.value.id = row.id;
|
||||
} else if (type === 'UpdateHouse') {
|
||||
EditHouseform.value.id = row.id;
|
||||
EditHouseform.value.deviceCode = row.deviceCode;
|
||||
EditHouseform.value.houseId = '';
|
||||
EditHouseForm.value.id = row.id;
|
||||
EditHouseForm.value.deviceCode = row.deviceCode;
|
||||
EditHouseForm.value.houseId = '';
|
||||
getTree();
|
||||
}
|
||||
};
|
||||
@@ -509,10 +507,10 @@ function handleUnbind(data: ElectricityDeviceVO) {
|
||||
}
|
||||
|
||||
function getTree() {
|
||||
treedata.value = [];
|
||||
treeData.value = [];
|
||||
houseStore.getCurrentVilageTreeHouse().then((res) => {
|
||||
treedata.value = res;
|
||||
userHousepath.value = [];
|
||||
treeData.value = res;
|
||||
userHousePath.value = [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -526,7 +524,7 @@ const submitForm = () => {
|
||||
ElMessage.warning('请选择时间');
|
||||
return;
|
||||
}
|
||||
UsedWaterformRef.value?.validate(async (valid: boolean) => {
|
||||
UsedWaterFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
await getElectricityDeviceTimeRangeUsedWater(UsedWaterform.value)
|
||||
@@ -541,12 +539,12 @@ const submitForm = () => {
|
||||
}
|
||||
});
|
||||
} else if (dialogType.value === 'UpdateHouse') {
|
||||
EditHouseformRef.value?.validate(async (valid: boolean) => {
|
||||
EditHouseFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
await updateElectricityDevice(EditHouseform.value).finally(() => (buttonLoading.value = false));
|
||||
await updateElectricityDevice(EditHouseForm.value).finally(() => (buttonLoading.value = false));
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
getList();
|
||||
await getList();
|
||||
unSubmit();
|
||||
}
|
||||
});
|
||||
@@ -571,18 +569,18 @@ const reset = () => {
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
};
|
||||
EditHouseform.value = {
|
||||
EditHouseForm.value = {
|
||||
houseId: '',
|
||||
deviceCode: '',
|
||||
id: ''
|
||||
};
|
||||
UploadFileform.value.file = '';
|
||||
UploadFileForm.value.file = '';
|
||||
// 上传 清空
|
||||
UploadFileformRef.value?.resetFields();
|
||||
UploadFileFormRef.value?.resetFields();
|
||||
// 使用电量 清空
|
||||
EditHouseformRef.value?.resetFields();
|
||||
EditHouseFormRef.value?.resetFields();
|
||||
// 使用电量 清空
|
||||
UsedWaterformRef.value?.resetFields();
|
||||
UsedWaterFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
|
||||
@@ -170,11 +170,10 @@ function headerToken() {
|
||||
};
|
||||
}
|
||||
const userid = ref('');
|
||||
const allowImgSuffix = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'];
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
const type = rawFile.type.split('/').pop();
|
||||
console.log('type', type);
|
||||
console.log('rawFile', rawFile);
|
||||
if (['png', 'jpg', 'jpeg'].includes(type)) {
|
||||
if (allowImgSuffix.includes(type)) {
|
||||
if (rawFile.size / 1024 / 1024 <= 10) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="维护人员" prop="maintainUserIds">
|
||||
<repairUser
|
||||
userType="EquipmentMaintenance"
|
||||
userType="repair"
|
||||
:userid="checkoutuseid"
|
||||
ref="repairUserRef"
|
||||
returnvalue="*"
|
||||
@@ -55,10 +55,12 @@
|
||||
<el-radio v-for="(item, index) in com_equipment_archive_status" :value="item.value" :label="item.label" :key="index"></el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model.trim="form.remark" placeholder="请输入" />
|
||||
<el-form-item label="设备保质期" prop="shelfLife">
|
||||
<el-input v-model.trim="form.shelfLife" placeholder="请输入" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" :row="5" v-model.trim="form.remark" placeholder="请输入" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="margin-top: 30px">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="cancelForm">返回</el-button>
|
||||
@@ -93,6 +95,7 @@ const form = ref({
|
||||
deviceModel: '', // 型号
|
||||
area: '', // 区域
|
||||
status: '0', // 区域
|
||||
shelfLife: '', // 设备保质期
|
||||
maintainUserIds: '', // 设备维护人员
|
||||
remark: '' // 备注
|
||||
});
|
||||
@@ -118,6 +121,7 @@ function init() {
|
||||
deviceCode: res.data.deviceCode,
|
||||
deviceModel: res.data.deviceModel,
|
||||
area: res.data.area,
|
||||
shelfLife: res.data.shelfLife,
|
||||
status: res.data.status,
|
||||
maintainUserIds: res.data.maintainUserIds,
|
||||
remark: res.data.remark
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</template>
|
||||
<el-table v-loading="loading" border :data="deviceList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="设备分类" align="center" prop="categoryName" />
|
||||
<el-table-column label="设备分类" width="100" align="center" prop="categoryName" />
|
||||
<el-table-column label="设备名称" align="center" prop="deviceName" />
|
||||
<el-table-column label="设备编号" align="center" prop="deviceCode" />
|
||||
<el-table-column label="设备型号" align="center" prop="deviceModel" />
|
||||
@@ -49,8 +49,9 @@
|
||||
<dict-tag :options="com_equipment_archive_status" :value="scope.row.status"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="保修期" align="center" prop="shelfLife" />
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<el-table-column label="操作" width="180" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleMain(scope.row)" v-has-permi="['system:device:query']">查看详情</el-button>
|
||||
<el-button link type="primary" @click="handleUpdate(scope.row)" v-has-permi="['system:device:edit']">编辑</el-button>
|
||||
|
||||
@@ -234,13 +234,13 @@ const cancelForm = () => {
|
||||
.info_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.label {
|
||||
font-size: 15px;
|
||||
.label {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
}
|
||||
.value {
|
||||
font-weight: 450;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
</div>
|
||||
<div class="addBuildingFormBody">
|
||||
<div class="infobox">
|
||||
<div class="info_item">
|
||||
<div class="label">设备分类:</div>
|
||||
<span class="value">{{ form.categoryName }}</span>
|
||||
</div>
|
||||
<!-- <div class="info_item">-->
|
||||
<!-- <div class="label">设备分类:</div>-->
|
||||
<!-- <span class="value">{{ form.categoryName }}</span>-->
|
||||
<!-- </div>-->
|
||||
<div class="info_item">
|
||||
<div class="label">设备名称:</div>
|
||||
<span class="value">{{ form.deviceName }}</span>
|
||||
@@ -48,7 +48,6 @@
|
||||
<div class="label">维修结果:</div>
|
||||
<DictTag :options="com_equipment_repair_status" :value="form.repairResult"></DictTag>
|
||||
</div>
|
||||
<!-- TODO 维修时间 -->
|
||||
<div class="info_item">
|
||||
<div class="label">维修时间:</div>
|
||||
<span class="value">{{ form.repairTime }}</span>
|
||||
@@ -169,16 +168,16 @@ const cancelForm = () => {
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
font-size: 0.8rem;
|
||||
.info_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 15px;
|
||||
.label {
|
||||
width: 120px;
|
||||
text-align: right;
|
||||
}
|
||||
.value {
|
||||
font-weight: 450;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="房屋" prop="houseId">
|
||||
<el-cascader @change="handleChange" v-model="userHousepath" :options="treedata" />
|
||||
<el-cascader @change="handleChange" v-model="userHousePath" :options="treeData" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2"></el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="业主姓名" prop="rentalName">
|
||||
<el-input disabled v-model="form.rentalName" placeholder="请输入业主姓名" />
|
||||
<el-input :disabled="HasName" v-model="form.rentalName" placeholder="请输入业主姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -58,7 +58,7 @@
|
||||
<el-col :span="11">
|
||||
<el-form-item label="房屋朝向" prop="type">
|
||||
<el-select v-model.number="form.houseFace" placeholder="请选择">
|
||||
<el-option v-for="(item, index) in houseformat" :key="index" :label="item" :value="item" />
|
||||
<el-option v-for="(item, index) in houseFormat" :key="index" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -94,14 +94,14 @@
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="房屋设施" prop="type">
|
||||
<div class="housedevicesbox" v-if="housefacilities.length > 0">
|
||||
<div class="houseDevicesBox" v-if="houseFacilities.length > 0">
|
||||
<div
|
||||
v-for="item in housefacilities"
|
||||
v-for="item in houseFacilities"
|
||||
:key="item.id"
|
||||
@click="handleClick(item.id)"
|
||||
class="housedevices_item"
|
||||
class="houseDevices_Item"
|
||||
:class="{
|
||||
active: housedeviceslist.includes(item.id)
|
||||
active: houseDevicesList.includes(item.id)
|
||||
}"
|
||||
>
|
||||
<span class="checked">√</span>
|
||||
@@ -128,6 +128,7 @@
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-change="handleChangeFile"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
<template #tip>
|
||||
@@ -178,9 +179,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { CascaderValue, UploadInstance, UploadProps, UploadUserFile } from 'element-plus';
|
||||
import { CascaderValue, UploadFiles, UploadInstance, UploadProps, UploadUserFile } from 'element-plus';
|
||||
|
||||
import { getHousePathById, hasFormData, splitStringUrl } from '@/utils/house';
|
||||
import { hasFormData, splitStringUrl } from '@/utils/house';
|
||||
import { addHouseRental, getHouseOwnUser, getHouseRental, updateHouseRental, uploadHouseImage } from '@/api/system/houseRental';
|
||||
import { validator } from '@/utils/Reg';
|
||||
import { useHouseStore } from '@/store/modules/house';
|
||||
@@ -192,9 +193,6 @@ const houseStore = useHouseStore();
|
||||
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/houseRental/uploadImages';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { com_rental_method } = toRefs<any>(proxy?.useDict('com_rental_method'));
|
||||
|
||||
const { com_house_rental_facilities } = toRefs<any>(proxy?.useDict('com_house_rental_facilities') || {});
|
||||
|
||||
const { com_rental_status } = toRefs<any>(proxy?.useDict('com_rental_status'));
|
||||
const { com_house_use } = toRefs<any>(proxy?.useDict('com_house_use'));
|
||||
|
||||
@@ -202,7 +200,7 @@ const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const formRef = ref();
|
||||
const houseformat = ['东', '西', '南', '北'];
|
||||
const houseFormat = ['东', '西', '南', '北'];
|
||||
const form = ref({
|
||||
id: null,
|
||||
houseId: null,
|
||||
@@ -224,14 +222,14 @@ const form = ref({
|
||||
unitNoId: null, //单元id
|
||||
email: '' //邮箱
|
||||
});
|
||||
const userHousepath = ref<CascaderValue>([]);
|
||||
const userHousePath = ref<CascaderValue>([]);
|
||||
const rules = ref({
|
||||
houseId: [{ required: true, message: '请选择房屋', trigger: 'blur' }],
|
||||
rentalName: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{
|
||||
validator: (_, val) => validator(val, 'phone'),
|
||||
validator: (_: any, val: string | number) => validator(val, 'phone'),
|
||||
message: '请输入正确的手机号码',
|
||||
trigger: 'blur'
|
||||
}
|
||||
@@ -239,19 +237,19 @@ const rules = ref({
|
||||
});
|
||||
// ! 编辑租赁-=================================================================================
|
||||
const userid = ref(null);
|
||||
const treedata = ref(null);
|
||||
const housefacilities = ref([]);
|
||||
// !== 楼栋房屋 =============================================================================
|
||||
async function gettreedata() {
|
||||
const reslist = await listHouseFacilities();
|
||||
housefacilities.value = reslist.rows
|
||||
const treeData = ref(null);
|
||||
const houseFacilities = ref([]);
|
||||
// !== 楼栋房屋 =============================================================================╬
|
||||
async function getTreeData() {
|
||||
const resList = await listHouseFacilities();
|
||||
houseFacilities.value = resList.rows
|
||||
.map((item) => {
|
||||
if (item.status !== '1') return item;
|
||||
return false;
|
||||
})
|
||||
.filter((item) => item !== false);
|
||||
|
||||
treedata.value = await houseStore.getCurrentVilageTreeHouse();
|
||||
treeData.value = await houseStore.getCurrentVilageTreeHouse();
|
||||
if (route.query.id) {
|
||||
userid.value = route.query.id;
|
||||
getHouseRental(userid.value).then((res) => {
|
||||
@@ -259,22 +257,30 @@ async function gettreedata() {
|
||||
...form.value,
|
||||
...res.data
|
||||
};
|
||||
if (form.value.facilities) housedeviceslist.value = form.value.facilities.split(',').filter((item) => item);
|
||||
if (form.value.facilities) houseDevicesList.value = form.value.facilities.split(',').filter((item) => item);
|
||||
if (form.value.houseImageUrl) fileList.value = splitStringUrl(form.value.houseImageUrl);
|
||||
handleChange([form.value.buildingId, form.value.unitNoId, form.value.houseId]);
|
||||
});
|
||||
}
|
||||
}
|
||||
gettreedata();
|
||||
getTreeData();
|
||||
|
||||
const HasName = ref(false);
|
||||
// 获取房屋
|
||||
function handleChange(val: CascaderValue) {
|
||||
userHousepath.value = val;
|
||||
userHousePath.value = val;
|
||||
form.value.houseId = val[2];
|
||||
|
||||
form.value.rentalName = '';
|
||||
if (val[2]) {
|
||||
getHouseOwnUser(val[2]).then((res) => {
|
||||
if (res.msg) {
|
||||
form.value.rentalName = res.msg;
|
||||
HasName.value = true;
|
||||
} else {
|
||||
HasName.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// !== 上传文件 =============================================================================
|
||||
const fileList = ref<UploadUserFile[]>([]);
|
||||
@@ -282,28 +288,39 @@ const dialogImageUrl = ref('');
|
||||
const dialogVisible = ref(false);
|
||||
// 上传文件成功
|
||||
const uploadRef = ref<UploadInstance>();
|
||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
|
||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (response) => {
|
||||
if (response.data && response.data.error.length > 0) {
|
||||
ElMessage.error('图片上传失败,请稍后再试');
|
||||
}
|
||||
};
|
||||
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
const handleChangeFile = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
const ext = uploadFile.name.toLowerCase().slice(uploadFile.name.lastIndexOf('.'));
|
||||
if (blockedExts.includes(ext)) {
|
||||
ElMessage.warning(`禁止上传 ${ext} 文件`);
|
||||
fileList.value = uploadFiles.filter((f) => f.uid !== uploadFile.uid);
|
||||
return;
|
||||
}
|
||||
fileList.value = uploadFiles;
|
||||
};
|
||||
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
dialogImageUrl.value = uploadFile.url!;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||
const handleRemove: UploadProps['onRemove'] = (_, uploadFiles) => {
|
||||
fileList.value = uploadFiles;
|
||||
};
|
||||
|
||||
// !== 家电 =============================================================================
|
||||
|
||||
// 家电
|
||||
const housedeviceslist = ref([]);
|
||||
const houseDevicesList = ref([]);
|
||||
function handleClick(index: number) {
|
||||
if (housedeviceslist.value.includes(index)) {
|
||||
housedeviceslist.value = housedeviceslist.value.filter((item) => item !== index);
|
||||
if (houseDevicesList.value.includes(index)) {
|
||||
houseDevicesList.value = houseDevicesList.value.filter((item) => item !== index);
|
||||
} else {
|
||||
housedeviceslist.value.push(index);
|
||||
houseDevicesList.value.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,28 +331,27 @@ const submitForm = () => {
|
||||
formRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
// 处理家电
|
||||
form.value.facilities = housedeviceslist.value.join(',');
|
||||
form.value.facilities = houseDevicesList.value.join(',');
|
||||
let str = '';
|
||||
// 判断有无图片
|
||||
if (fileList.value.length > 0) {
|
||||
const formdata = new FormData();
|
||||
const formData = new FormData();
|
||||
fileList.value.forEach((item) => {
|
||||
// 只处理 新增的图片
|
||||
if (item.raw && item.raw instanceof File) {
|
||||
formdata.append('files', item.raw);
|
||||
formData.append('files', item.raw);
|
||||
} else {
|
||||
str += item.url + ',';
|
||||
}
|
||||
});
|
||||
if (!hasFormData(formdata)) return sendForm(str);
|
||||
uploadHouseImage(formdata)
|
||||
if (!hasFormData(formData)) return sendForm(str);
|
||||
uploadHouseImage(formData)
|
||||
.then((res) => {
|
||||
if (res.data.success.length > 0) {
|
||||
const successlist = res.data.success;
|
||||
successlist.forEach((item) => {
|
||||
const successList = res.data.success;
|
||||
successList.forEach((item) => {
|
||||
str += item.url + ',';
|
||||
});
|
||||
//
|
||||
form.value.houseImageUrl = str;
|
||||
}
|
||||
if (res.data.error.length > 0) {
|
||||
@@ -350,7 +366,7 @@ const submitForm = () => {
|
||||
.catch((err) => {
|
||||
if (err && err.data && err.data.error.length > 0) {
|
||||
const str = err.data.error.join(',');
|
||||
err.data.error.forEach((item) => {
|
||||
err.data.error.forEach((item: string) => {
|
||||
fileList.value = fileList.value.filter((file) => file.name !== item);
|
||||
});
|
||||
ElMessage.error('图片:' + str + ' 上传失败!,请重新上传');
|
||||
@@ -380,7 +396,6 @@ const sendForm = (val: string) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 推出
|
||||
const cancelForm = () => {
|
||||
router.back();
|
||||
@@ -445,13 +460,13 @@ const cancelForm = () => {
|
||||
.formBody {
|
||||
width: 1050px;
|
||||
margin: 0 auto;
|
||||
.housedevicesbox {
|
||||
.houseDevicesBox {
|
||||
display: grid;
|
||||
margin-bottom: 20px;
|
||||
gap: 10px 20px;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
.housedevices_item {
|
||||
.houseDevices_Item {
|
||||
width: 95px;
|
||||
height: 35px;
|
||||
background-color: #ccc;
|
||||
|
||||
@@ -29,12 +29,16 @@
|
||||
<el-card class="flex-1" shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-col :span="5">
|
||||
<span style="font-size: 1.2rem">日报列表</span>
|
||||
</el-col>
|
||||
<el-col :span="14"></el-col>
|
||||
<el-col :span="5" style="text-align: right">
|
||||
<el-button type="warning" @click="exportCurrentPage">导出当前页</el-button>
|
||||
<el-button type="warning" @click="exportAll">导出所有</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="itemList">
|
||||
<el-table-column label="日期" width="100" align="center" prop="statDate" />
|
||||
<el-table-column label="计划巡检任务" width="120" align="center" prop="totalPlans" />
|
||||
@@ -50,7 +54,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Item" lang="ts">
|
||||
import { listItem, type Request } from '@/api/system/Inspection/index';
|
||||
import { listItem } from '@/api/system/Inspection';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -61,12 +65,12 @@ const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const data = reactive<{
|
||||
queryParams: Request;
|
||||
}>({
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
queryDateEnd: '',
|
||||
queryDateBegin: '',
|
||||
statDate: '',
|
||||
dataType: '1' // 1 日报
|
||||
}
|
||||
@@ -77,6 +81,8 @@ const { queryParams } = toRefs(data);
|
||||
/** 查询巡检项目列表 */
|
||||
const getList = async () => {
|
||||
queryParams.value.statDate = starDate.value.join('-');
|
||||
queryParams.value.queryDateBegin = starDate.value[0];
|
||||
queryParams.value.queryDateEnd = starDate.value[1];
|
||||
loading.value = true;
|
||||
listItem(queryParams.value)
|
||||
.then((res) => {
|
||||
@@ -101,6 +107,26 @@ const resetQuery = () => {
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 导出当前页数据 */
|
||||
const exportCurrentPage = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export/page',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检日报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
const exportAll = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检日报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@@ -29,9 +29,14 @@
|
||||
<el-card class="flex-1" shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-col :span="5">
|
||||
<span style="font-size: 1.2rem">月报列表</span>
|
||||
</el-col>
|
||||
<el-col :span="14"> </el-col>
|
||||
<el-col :span="5" style="text-align: right">
|
||||
<el-button type="warning" @click="exportCurrentPage">导出当前页</el-button>
|
||||
<el-button type="warning" @click="exportAll">导出所有</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
@@ -50,10 +55,8 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Item" lang="ts">
|
||||
import { listItem, type Request } from '@/api/system/Inspection/index';
|
||||
|
||||
import { listItem } from '@/api/system/Inspection';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const itemList = ref<any[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
@@ -62,12 +65,13 @@ const total = ref(0);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const starDate = ref([]);
|
||||
const data = reactive<{
|
||||
queryParams: Request;
|
||||
}>({
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
statDate: '',
|
||||
queryDateEnd: '',
|
||||
queryDateBegin: '',
|
||||
dataType: '3' // 1 日报 3 月报
|
||||
}
|
||||
});
|
||||
@@ -77,6 +81,8 @@ const { queryParams } = toRefs(data);
|
||||
/** 查询巡检项目列表 */
|
||||
const getList = async () => {
|
||||
queryParams.value.statDate = starDate.value.join('-');
|
||||
queryParams.value.queryDateBegin = starDate.value[0];
|
||||
queryParams.value.queryDateEnd = starDate.value[1];
|
||||
loading.value = true;
|
||||
listItem(queryParams.value)
|
||||
.then((res) => {
|
||||
@@ -100,7 +106,25 @@ const resetQuery = () => {
|
||||
starDate.value = [];
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 导出当前页数据 */
|
||||
const exportCurrentPage = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export/page',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检月报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
const exportAll = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检月报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@@ -86,6 +86,7 @@ import { Check } from '@element-plus/icons-vue';
|
||||
import MapWrapper from '@/components/Map/index.vue';
|
||||
import { PointVO } from '@/api/system/InspectionPoint/type';
|
||||
import { LngLat } from '@/components/Map/type';
|
||||
import { PlanVO } from '@/api/system/InspectionPlan/type';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { com_inspection_remind_tiime } = toRefs<any>(proxy?.useDict('com_inspection_remind_tiime'));
|
||||
@@ -167,7 +168,6 @@ async function init() {
|
||||
} else {
|
||||
taskTime.value = [['', '']];
|
||||
}
|
||||
|
||||
handleChangeMap(res.data.routeIds);
|
||||
});
|
||||
}
|
||||
@@ -181,20 +181,25 @@ function outback() {
|
||||
const MapWrapperRef = ref<InstanceType<typeof MapWrapper>>();
|
||||
|
||||
function handleChangeMap(val: string) {
|
||||
if (val) {
|
||||
if (!val) return;
|
||||
MapWrapperRef.value.clearMapMarker();
|
||||
const find = playlist.value.find((item) => item.id === val);
|
||||
if (!find) return;
|
||||
if (find.points && find.points.length > 0) {
|
||||
find.points.forEach((item: PointVO) => {
|
||||
const angular = item.location.split(',').map(Number).filter(Boolean) as LngLat;
|
||||
MapWrapperRef.value.addMarker_more(angular, item.pointName, item.id);
|
||||
const pointMap = new Map(find.points.map((p) => [p.id, p]));
|
||||
const totalPointsList = find.totalPoints.split(',').filter(Boolean);
|
||||
if (totalPointsList.length > 0) {
|
||||
totalPointsList.forEach((item) => {
|
||||
const findItem = pointMap.get(item);
|
||||
const angular = findItem.location.split(',').map(Number).filter(Boolean) as LngLat;
|
||||
MapWrapperRef.value.addMarker_more(angular, findItem.pointName, findItem.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
// 巡检路线
|
||||
if (find.pathPoints) {
|
||||
MapWrapperRef.value.renderSavedPath(find.pathPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -69,22 +69,20 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Plan" lang="ts">
|
||||
import { listPlan, delPlan, changePlanStatus } from '@/api/system/InspectionPlan/index';
|
||||
import { listPlan, delPlan, changePlanStatus } from '@/api/system/InspectionPlan';
|
||||
import { PlanVO, PlanQuery, PlanForm } from '@/api/system/InspectionPlan/type';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { numToWeek } from '@/utils/time';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { com_inspection_plan_setting } = toRefs<any>(proxy?.useDict('com_inspection_plan_setting'));
|
||||
|
||||
interface planlistType extends PlanVO {
|
||||
interface planListType extends PlanVO {
|
||||
routeNames?: string;
|
||||
inspectorNames?: string;
|
||||
executeDayNames?: number[];
|
||||
}
|
||||
|
||||
const planList = ref<planlistType[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const planList = ref<planListType[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
@@ -93,12 +91,6 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const planFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: PlanForm = {
|
||||
id: undefined,
|
||||
@@ -132,7 +124,7 @@ const data = reactive<PageData<PlanForm, PlanQuery>>({
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
/** 查询巡检计划列表 */
|
||||
const getList = async () => {
|
||||
@@ -154,18 +146,6 @@ const getList = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
planFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
@@ -220,17 +200,6 @@ const handleDelete = async (row?: PlanVO) => {
|
||||
await getList();
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'system/plan/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`plan_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" label-width="100px" @submit.prevent="handleQuery" :model="queryParams" :inline="true">
|
||||
<el-form-item label="执行状态" prop="statuss">
|
||||
<el-form-item label="执行状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择执行状态" clearable>
|
||||
<el-option v-for="(item, index) in com_inspection_task_status" :key="index" :value="item.value" :label="item.label"></el-option>
|
||||
</el-select>
|
||||
@@ -77,7 +77,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Task" lang="ts">
|
||||
import { listTask, delTask } from '@/api/system/InspectionTask/index';
|
||||
import { listTask, delTask } from '@/api/system/InspectionTask';
|
||||
import { TaskVO, TaskQuery, TaskForm } from '@/api/system/InspectionTask/type';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
|
||||
@@ -86,7 +86,6 @@ const { com_inspection_task_status } = toRefs<any>(proxy?.useDict('com_inspectio
|
||||
const { com_inspection_remind_tiime } = toRefs<any>(proxy?.useDict('com_inspection_remind_tiime'));
|
||||
const router = useRouter();
|
||||
const taskList = ref<TaskVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
@@ -95,12 +94,6 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const taskFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: TaskForm = {
|
||||
id: undefined,
|
||||
@@ -121,7 +114,7 @@ const data = reactive<PageData<TaskForm, TaskQuery>>({
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
/** 查询巡检任务列表 */
|
||||
const getList = async () => {
|
||||
@@ -136,12 +129,6 @@ const getList = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
taskFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
@@ -169,7 +156,7 @@ const handleAdd = () => {
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: TaskVO) => {
|
||||
const handleUpdate = (row?: TaskVO) => {
|
||||
const _ids = row?.id || ids.value[0];
|
||||
router.push({
|
||||
path: '/inspection/editTask',
|
||||
|
||||
@@ -29,9 +29,14 @@
|
||||
<el-card class="flex-1" shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-col :span="5">
|
||||
<span style="font-size: 1.2rem">周报列表</span>
|
||||
</el-col>
|
||||
<el-col :span="14"> </el-col>
|
||||
<el-col :span="5" style="text-align: right">
|
||||
<el-button type="warning" @click="exportCurrentPage">导出当前页</el-button>
|
||||
<el-button type="warning" @click="exportAll">导出所有</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
@@ -50,7 +55,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Item" lang="ts">
|
||||
import { listItem, type Request } from '@/api/system/Inspection/index';
|
||||
import { listItem } from '@/api/system/Inspection';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -61,12 +66,13 @@ const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const data = reactive<{
|
||||
queryParams: Request;
|
||||
}>({
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
statDate: '',
|
||||
queryDateBegin: '',
|
||||
queryDateEnd: '',
|
||||
dataType: '2' // 1 日报 2 周报 3 月报
|
||||
}
|
||||
});
|
||||
@@ -76,6 +82,8 @@ const { queryParams } = toRefs(data);
|
||||
/** 查询巡检项目列表 */
|
||||
const getList = async () => {
|
||||
queryParams.value.statDate = starDate.value.join('-');
|
||||
queryParams.value.queryDateBegin = starDate.value[0];
|
||||
queryParams.value.queryDateEnd = starDate.value[1];
|
||||
loading.value = true;
|
||||
listItem(queryParams.value)
|
||||
.then((res) => {
|
||||
@@ -99,7 +107,25 @@ const resetQuery = () => {
|
||||
starDate.value = [];
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 导出当前页数据 */
|
||||
const exportCurrentPage = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export/page',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检周报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
const exportAll = () => {
|
||||
proxy?.download(
|
||||
'/inspection/data/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`巡检周报_${new Date().toLocaleString()}.xlsx`
|
||||
);
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
<span>
|
||||
{{ parkingReviewInfo.parking.residentName }}
|
||||
</span>
|
||||
<el-button type="primary" link style="font-size: smaller">详情</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,7 +250,7 @@ getInfo();
|
||||
font-size: 14px;
|
||||
.label {
|
||||
font-weight: 600;
|
||||
width: 80px;
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</div> -->
|
||||
<!-- <div class="userinfo_item">
|
||||
<div class="title_item">注册时间:</div>
|
||||
<span> {{ userInfo.name }} </span>
|
||||
<span> {{ userInfo.name }} </span>╬6╬╬222╬▐
|
||||
</div> -->
|
||||
<div class="userinfo_item img">
|
||||
<div class="title_item">身份证正面:</div>
|
||||
@@ -154,9 +154,10 @@ const userInfo = ref<ResidentVO>({
|
||||
buildingId: '',
|
||||
userId: null,
|
||||
nickName: '',
|
||||
unitNoId: '',
|
||||
'id': null,
|
||||
'name': '',
|
||||
'type': null,
|
||||
'type': '0',
|
||||
'gender': null,
|
||||
'status': null,
|
||||
'idCard': '',
|
||||
@@ -192,7 +193,7 @@ if (route.query.id) {
|
||||
getresidentReviewlistAPI(userid.value).then((res) => {
|
||||
if (res.rows[0]) {
|
||||
reviewInfo.value = res.rows[0];
|
||||
handleActivestaus(reviewInfo.value);
|
||||
handleActiveStaus(reviewInfo.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -202,7 +203,7 @@ const getReviewStatusLabel = (status: string) => {
|
||||
const item = com_review.value?.find((i: any) => i.value === status);
|
||||
return item ? item.label : '未知状态';
|
||||
};
|
||||
function handleActivestaus(rews) {
|
||||
function handleActiveStaus(rews) {
|
||||
// 提交状态 0未提交 1已提交
|
||||
if (rews.submitStatus === '0') {
|
||||
active.value = 0;
|
||||
@@ -262,7 +263,7 @@ function updatePass(val: '0' | '1' | '2') {
|
||||
}
|
||||
|
||||
function update() {
|
||||
UpdateResidentReviewAPI(reviewInfo.value).then((res) => {
|
||||
UpdateResidentReviewAPI(reviewInfo.value).then(() => {
|
||||
backRoute();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-exceed="handleExceed"
|
||||
:on-error="handleError"
|
||||
:before-upload="handleBeforUpload"
|
||||
:limit="1"
|
||||
>
|
||||
<img alt="身份证正面照" v-if="form.cardImageFront" :src="form.cardImageFront" class="avatar" />
|
||||
@@ -81,6 +82,7 @@
|
||||
:on-exceed="handleExceed2"
|
||||
:on-success="handleAvatar2Success"
|
||||
:on-error="handleError2"
|
||||
:before-upload="handleBeforUpload"
|
||||
>
|
||||
<img alt="身份证背面照" v-if="form.cardImageBack" :src="form.cardImageBack" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
|
||||
@@ -228,6 +230,15 @@ const handleError: UploadProps['onError'] = (error: Error, uploadFile: UploadFil
|
||||
const handleError2: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
console.log(error);
|
||||
};
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
const handleBeforUpload = (uploadFile: UploadRawFile) => {
|
||||
const ext = uploadFile.name.toLowerCase().slice(uploadFile.name.lastIndexOf('.'));
|
||||
if (blockedExts.includes(ext)) {
|
||||
ElMessage.warning(`禁止上传 ${ext} 文件`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// !== 提交 =============================================================================
|
||||
|
||||
// 提交
|
||||
|
||||
@@ -92,9 +92,6 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<i v-if="open" class="bgColor"></i>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -116,9 +113,10 @@ import {
|
||||
PayMentMethod
|
||||
} from '@/api/system/Payment';
|
||||
import RingProgress from './compontents/RingProgress.vue';
|
||||
import { useBgColor } from '@/store/modules/bgColor';
|
||||
|
||||
const BgStore = useBgColor();
|
||||
const defaultDay = 30; // 默认查询近30天数据
|
||||
const open = ref(false);
|
||||
const last10Day = getPastDayDate(defaultDay);
|
||||
const dataTime = ref(last10Day);
|
||||
|
||||
@@ -631,12 +629,11 @@ function reset() {
|
||||
}
|
||||
getList();
|
||||
onMounted(() => {
|
||||
open.value = true;
|
||||
BgStore.toggleBgColor(true);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
open.value = false;
|
||||
BgStore.toggleBgColor(false);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -60,10 +60,6 @@
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<Teleport to="body">
|
||||
<i v-if="open" class="bgColor"></i>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -73,15 +69,16 @@ import Echarts from '@/components/Echarts/index.vue';
|
||||
import { EChartsOption } from 'echarts';
|
||||
import { getLastNDays } from '@/utils/time';
|
||||
import { get_movein_moveout_list, get_movein_user_sex, get_movein_user_type, get_person_age, user_movein_list } from '@/api/system/Personnel';
|
||||
import { useBgColor } from '@/store/modules/bgColor';
|
||||
|
||||
const BgStore = useBgColor();
|
||||
const date = ref('');
|
||||
const open = ref(true);
|
||||
|
||||
onMounted(() => {
|
||||
open.value = true;
|
||||
BgStore.toggleBgColor(true);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
open.value = false;
|
||||
BgStore.toggleBgColor(false);
|
||||
});
|
||||
|
||||
function reset() {
|
||||
@@ -650,7 +647,7 @@ function MoveInPersonAge() {
|
||||
<style scoped lang="scss">
|
||||
.personnel {
|
||||
position: relative;
|
||||
background: linear-gradient(180deg, #deedff 0%, #f8f9fe 50%);
|
||||
background: #deedff;
|
||||
.el-button {
|
||||
width: 80px;
|
||||
height: 32px;
|
||||
|
||||
@@ -94,7 +94,7 @@ const rules = ref({
|
||||
// 登录账号:必填,长度限制,通常建议增加唯一性校验(需后端配合或异步校验)
|
||||
userName: [
|
||||
{ required: true, message: '请输入登录账号', trigger: 'blur' },
|
||||
{ min: 6, max: 16, message: '长度在 6 到 16 个字符', trigger: 'blur' }
|
||||
{ min: 1, max: 16, message: '长度在 1 到 16 个字符', trigger: 'blur' }
|
||||
],
|
||||
// 登录密码:必填,新增时必填,编辑时可选(通常逻辑),这里暂按必填处理,建议长度限制
|
||||
password: [
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
:on-progress="handleFileUploadProgress"
|
||||
:on-success="handleFileSuccess"
|
||||
:auto-upload="false"
|
||||
:on-change="handleChangeFile"
|
||||
drag
|
||||
>
|
||||
<el-icon class="el-icon--upload">
|
||||
@@ -214,6 +215,7 @@ import { checkPermi } from '@/utils/permission';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getCommunitylistAPI } from '@/api/system/community';
|
||||
import { communitylist_rows_type } from '@/api/system/community/type';
|
||||
import { UploadRawFile } from 'element-plus';
|
||||
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@@ -464,6 +466,14 @@ const handleFileSuccess = (response: any, file: UploadFile) => {
|
||||
});
|
||||
getList();
|
||||
};
|
||||
const forbidSuffix = ['exe', 'msi', 'bat', 'cmd', 'sh', 'apk', 'dmg', 'zip', 'rar', '7z', 'tar', 'gz'];
|
||||
const handleChangeFile = (uploadFile: UploadFile) => {
|
||||
const type = uploadFile.raw.name.split('.')[1];
|
||||
if (forbidSuffix.includes(type)) {
|
||||
ElMessage.warning('不允许上传exe、安装包等文件');
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交上传文件 */
|
||||
function submitFileForm() {
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-has-permi="['system:version:add']">新增</el-button>
|
||||
</el-col>
|
||||
<!-- <right-toolbar v-model:showSearch="showSearch"╬╬╘╬ @queryTable="getList"></right-toolbar> -->
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
@@ -109,13 +108,17 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="渠道" prop="channel">
|
||||
<el-radio-group v-model="form.channel">
|
||||
<el-radio value="huawei">华为</el-radio>
|
||||
<el-radio value="xiaomi">小米</el-radio>
|
||||
<el-radio value="oppo">oppo</el-radio>
|
||||
<el-radio value="vivo">vivo</el-radio>
|
||||
<el-radio-group @change="handleChangeChannel" v-model="form.channel">
|
||||
<el-radio v-if="form.platform !== appType.ios" value="huawei">华为</el-radio>
|
||||
<el-radio v-if="form.platform !== appType.ios" value="xiaomi">小米</el-radio>
|
||||
<el-radio v-if="form.platform !== appType.ios" value="oppo">oppo</el-radio>
|
||||
<el-radio v-if="form.platform !== appType.ios" value="vivo">vivo</el-radio>
|
||||
<el-radio v-if="form.platform !== appType.ios" value="yyb">应用宝</el-radio>
|
||||
<el-radio v-if="form.platform !== appType.ios" value="honor">荣耀</el-radio>
|
||||
<el-radio value="ios">ios</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="更新日志" prop="releaseNotes">
|
||||
<el-input v-model="form.releaseNotes" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
@@ -225,13 +228,13 @@ enum appType {
|
||||
/** 更新包类型 */
|
||||
enum updatePackageType {
|
||||
/** 整包更新 */
|
||||
apk = 'apk',
|
||||
apk = 'apk'
|
||||
/** 热更新 */
|
||||
wgt = 'wgt'
|
||||
// wgt = 'wgt'
|
||||
}
|
||||
enum updateType {
|
||||
/** 强制更新 */
|
||||
force = '0',
|
||||
// force = '0',
|
||||
/** 可选更新 */
|
||||
optional = '1'
|
||||
}
|
||||
@@ -245,21 +248,21 @@ const getlastVersionlist = ref([]);
|
||||
* @param {string} latest - 最新版本号字符串,格式为点分十进制(如 "1.2.4")
|
||||
* @returns {boolean} 如果当前版本小于或等于最新版本,返回 true;否则返回 false
|
||||
*/
|
||||
function needUpdate(current: string, latest: string) {
|
||||
// 将版本号字符串分割并转换为数字数组
|
||||
const c = current.split('.').map(Number);
|
||||
const l = latest.split('.').map(Number);
|
||||
const max = Math.max(c.length, l.length);
|
||||
|
||||
// 逐段比较版本号,若当前段小于最新段则需更新,大于则无需更新
|
||||
for (let i = 0; i < max; i++) {
|
||||
const cv = c[i] || 0;
|
||||
const lv = l[i] || 0;
|
||||
if (cv <= lv) return true;
|
||||
if (cv > lv) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// function needUpdate(current: string, latest: string) {
|
||||
// // 将版本号字符串分割并转换为数字数组
|
||||
// const c = current.split('.').map(Number);
|
||||
// const l = latest.split('.').map(Number);
|
||||
// const max = Math.max(c.length, l.length);
|
||||
//
|
||||
// // 逐段比较版本号,若当前段小于最新段则需更新,大于则无需更新
|
||||
// for (let i = 0; i < max; i++) {
|
||||
// const cv = c[i] || 0;
|
||||
// const lv = l[i] || 0;
|
||||
// if (cv <= lv) return true;
|
||||
// if (cv > lv) return false;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/** 查询【请填写功能名称】列表 */
|
||||
const getList = async () => {
|
||||
@@ -314,6 +317,11 @@ function handleChangePlatform() {
|
||||
form.value.updateType = updateType.optional;
|
||||
form.value.method = updatePackageType.apk;
|
||||
form.value.downloadUrl = '';
|
||||
|
||||
if (form.value.platform === 'ios') {
|
||||
form.value.channel = 'ios';
|
||||
handleChangeChannel(form.value.channel);
|
||||
}
|
||||
handleGetVersionlast();
|
||||
}
|
||||
|
||||
@@ -326,6 +334,19 @@ function handleGetVersionlast() {
|
||||
});
|
||||
}
|
||||
|
||||
const channelUrl = {
|
||||
'huawei': 'tappmarket://details?id=',
|
||||
'xiaomi': 'mimarket://details?id=',
|
||||
'oppo': 'oppomarket://details?packagename=',
|
||||
'vivo': 'vivomarket://details?id=',
|
||||
'honor': 'market://details?id=',
|
||||
'yyb': 'tmast://appdetails?pname=',
|
||||
'ios': 'itms-apps://apps.apple.com/cn/app/id'
|
||||
};
|
||||
function handleChangeChannel(val: string) {
|
||||
console.log(val);
|
||||
form.value.downloadUrl = channelUrl[val];
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
if (!form.value.minVersionCode) {
|
||||
|
||||
@@ -208,9 +208,9 @@ function changeActive_index(val: number) {
|
||||
changeChartConfig(0);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
// echarts
|
||||
.echartsbox {
|
||||
height: inherit;
|
||||
flex: 1;
|
||||
.echarts {
|
||||
margin-right: 20px;
|
||||
flex: 1;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitQuick">确 定</el-button>
|
||||
<el-button>取 消</el-button>
|
||||
<el-button @click="close">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -171,6 +171,9 @@ function submitQuick() {
|
||||
getquicklist();
|
||||
});
|
||||
}
|
||||
function close() {
|
||||
dialog.visible = false;
|
||||
}
|
||||
function delteRoute(e: MouseEvent, id: string) {
|
||||
e.stopPropagation();
|
||||
delQuicklyshortcut(id).then(() => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span class="ecarts_title">近一周报修量趋势</span>
|
||||
<span class="echarts_units">单位(个)</span>
|
||||
</div>
|
||||
<div class="flex flex-items-center justify-center">
|
||||
<div class="flex flex-items-center justify-center" @click="handleRoute">
|
||||
<span class="echarts_all_baoxiu">全部报修</span>
|
||||
<i class="echarts_all_arrow"></i>
|
||||
</div>
|
||||
@@ -18,6 +18,13 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import repairEcharts from './repairEcharts.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
const handleRoute = () => {
|
||||
router.push({
|
||||
path: '/repair/repairlist'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -57,6 +64,7 @@ import repairEcharts from './repairEcharts.vue';
|
||||
color: #98a4b2;
|
||||
line-height: 18px;
|
||||
margin-right: 7px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.echarts_all_arrow {
|
||||
display: block;
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { addHandleLog, uploadAttachments } from '@/api/system/HandleLog';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { UploadFiles, UploadProps, UploadUserFile } from 'element-plus';
|
||||
import { UploadFiles, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus';
|
||||
import { Upload } from '@element-plus/icons-vue';
|
||||
|
||||
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/handleLog/uploadAttachments';
|
||||
@@ -70,13 +70,20 @@ function headerToken() {
|
||||
Authorization: 'Bearer ' + useStore.token
|
||||
};
|
||||
}
|
||||
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
const handleAvatarRemove: UploadProps['onRemove'] = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
fileList.value = uploadFiles;
|
||||
};
|
||||
const handleProgress: UploadProps['onChange'] = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
const ext = uploadFile.name.toLowerCase().slice(uploadFile.name.lastIndexOf('.'));
|
||||
if (blockedExts.includes(ext)) {
|
||||
ElMessage.warning(`禁止上传 ${ext} 文件`);
|
||||
fileList.value = uploadFiles.filter((f) => f.uid !== uploadFile.uid);
|
||||
return;
|
||||
}
|
||||
fileList.value = uploadFiles;
|
||||
};
|
||||
|
||||
const btnloading = ref(false);
|
||||
function submitTodo() {
|
||||
btnloading.value = true;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<el-col :span="18">
|
||||
<VillageAllInfo :list="list"></VillageAllInfo>
|
||||
<div class="echartsbox flex flex-items-center">
|
||||
<repairechartsAll></repairechartsAll>
|
||||
<repairechartsAll></repairechartsAll>
|
||||
<inandoutEcharts></inandoutEcharts>
|
||||
</div>
|
||||
@@ -92,8 +93,8 @@ const list = ref([
|
||||
{ name: '房屋总数量', value: 458, icon: icon2 },
|
||||
{ name: '车位总数量', value: 2539, icon: icon3 },
|
||||
{ name: '设备总数量', value: 22, icon: icon4 },
|
||||
{ name: '物料总数量', value: 458, icon: icon5 },
|
||||
{ name: '投诉总数量', value: 458, icon: icon6 }
|
||||
// { name: '物料总数量', value: 458, icon: icon5 }
|
||||
]);
|
||||
|
||||
function getVillageinfo() {
|
||||
|
||||
@@ -542,7 +542,7 @@ const reset = () => {
|
||||
const handleAdd = async () => {
|
||||
reset();
|
||||
if (queryParams.value.category != '') {
|
||||
form.value.category = queryParams.value.category;
|
||||
form.value.category = queryParams.value.category as string;
|
||||
}
|
||||
form.value.modelValue = 'CLASSICS';
|
||||
form.value.formCustom = 'N';
|
||||
|
||||
Reference in New Issue
Block a user