修复小区背景颜色,巡检点顺序一致,投诉处理按钮

This commit is contained in:
Zy
2026-07-16 11:06:26 +08:00
parent 4efb535730
commit 725bdfa3fe
56 changed files with 1034 additions and 468 deletions

View File

@@ -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'

View File

@@ -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
});
};

View File

@@ -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;

View File

@@ -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
});
};

View File

@@ -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 {

View File

@@ -19,6 +19,7 @@ export interface DeviceVO {
* 设备编号
*/
deviceCode: string;
shelfLife:string;
/**
* 设备型号

View File

@@ -80,7 +80,7 @@ export interface ResidentForm extends BaseEntity {
* 主键 住户管理id
*/
userId?: string;
unitNoId: string;
unitNoId?: string;
/**
* 住户编号

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
};
/** 下载按钮操作 */

View 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>
&nbsp;&nbsp;
<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>

View File

@@ -161,7 +161,7 @@ watch(
position: relative;
background: #dfedff;
background: transparent;
border-bottom: 1px solid #dfedff;
//border-bottom: 1px solid #dfedff;
color: #c0c4cc;

View File

@@ -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>

View 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
};
});

View File

@@ -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));
}
/**
* 智能金额格式化(带单位:元/万元/亿元)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
};
// ! 投诉 ====================================================================================================
// ! 签到 =======================================

View File

@@ -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 {

View File

@@ -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();
});

View File

@@ -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([]);

View File

@@ -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');

View File

@@ -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">

View File

@@ -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) => {

View File

@@ -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!;

View File

@@ -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',

View File

@@ -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';

View File

@@ -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();

View File

@@ -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();
};
/** 搜索按钮操作 */

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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();
});

View File

@@ -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();
});

View File

@@ -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(() => {

View File

@@ -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();
});

View File

@@ -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',

View File

@@ -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();
});

View File

@@ -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;
}

View File

@@ -36,7 +36,7 @@
</div> -->
<!-- <div class="userinfo_item">
<div class="title_item">注册时间</div>
<span> {{ userInfo.name }} </span>
<span> {{ userInfo.name }} </span>6222
</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();
});
}

View File

@@ -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;
};
// !== 提交 =============================================================================
// 提交

View File

@@ -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">

View File

@@ -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;

View File

@@ -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: [

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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(() => {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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';