新增:每月1日自动生成保养计划

This commit is contained in:
gxwebsoft
2024-02-23 13:57:48 +08:00
parent 25864fb449
commit e6caabbba8
12 changed files with 2017 additions and 386 deletions

View File

@@ -1,3 +1,3 @@
VITE_APP_NAME=后台管理系统 VITE_APP_NAME=后台管理系统
#VITE_API_URL=http://127.0.0.1:10041/api VITE_API_URL=http://127.0.0.1:10041/api
VITE_API_URL=http://1.14.159.185:10041/api #VITE_API_URL=http://1.14.159.185:10041/api

View File

@@ -0,0 +1,108 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type {
SecurityRecord,
SecurityRecordParam
} from '@/api/tower/security-record/model';
/**
* 分页查询仓库
*/
export async function pageSecurityRecord(params: SecurityRecordParam) {
const res = await request.get<ApiResult<PageResult<SecurityRecord>>>(
'/tower/tower-security-record/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询仓库列表
*/
export async function listSecurityRecord(params?: SecurityRecordParam) {
const res = await request.get<ApiResult<SecurityRecord[]>>(
'/tower/tower-security-record',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加仓库
*/
export async function addSecurityRecord(data: SecurityRecord) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-security-record',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改仓库
*/
export async function updateSecurityRecord(data: SecurityRecord) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security-record',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 绑定仓库
*/
export async function bindSecurityRecord(data: SecurityRecord) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security-record/bind',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除仓库
*/
export async function removeSecurityRecord(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security-record/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除仓库
*/
export async function removeBatchSecurityRecord(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security-record/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,31 @@
import type { PageParam } from '@/api';
export interface SecurityRecord {
securityRecordId?: number;
projectName?: string;
projectId?: number;
securityCode?: string;
regionName?: string;
longitude?: string;
latitude?: string;
country?: string;
province?: string;
city?: string;
region?: string;
address?: string;
status?: number;
userId?: number;
comments?: string;
sortNumber?: number;
}
/**
* 搜索条件
*/
export interface SecurityRecordParam extends PageParam {
securityId?: number;
projectId?: number;
projectName?: string;
status?: number;
keywords?: string;
}

View File

@@ -0,0 +1,105 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { Security, SecurityParam } from '@/api/tower/security/model';
/**
* 分页查询仓库
*/
export async function pageSecurity(params: SecurityParam) {
const res = await request.get<ApiResult<PageResult<Security>>>(
'/tower/tower-security/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询仓库列表
*/
export async function listSecurity(params?: SecurityParam) {
const res = await request.get<ApiResult<Security[]>>(
'/tower/tower-security',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加仓库
*/
export async function addSecurity(data: Security) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-security',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改仓库
*/
export async function updateSecurity(data: Security) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 绑定仓库
*/
export async function bindSecurity(data: Security) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security/bind',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除仓库
*/
export async function removeSecurity(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除仓库
*/
export async function removeBatchSecurity(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,31 @@
import type { PageParam } from '@/api';
export interface Security {
securityId?: number;
projectName?: string;
projectId?: number;
securityCode?: string;
regionName?: string;
longitude?: string;
latitude?: string;
country?: string;
province?: string;
city?: string;
region?: string;
address?: string;
status?: number;
userId?: number;
comments?: string;
sortNumber?: number;
}
/**
* 搜索条件
*/
export interface SecurityParam extends PageParam {
securityId?: number;
projectId?: number;
projectName?: string;
status?: number;
keywords?: string;
}

View File

@@ -54,12 +54,8 @@
/> />
</a-form-item> </a-form-item>
<a-form-item label="其他说明备注"> <a-form-item label="其他说明备注">
<a-input <a-input allow-clear v-model:value="form.remark" />
allow-clear
v-model:value="form.remark"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :md="8" :sm="24" :xs="24"> <a-col :md="8" :sm="24" :xs="24">
<a-form-item label="出租单位" v-bind="validateInfos.companyId"> <a-form-item label="出租单位" v-bind="validateInfos.companyId">
@@ -88,8 +84,14 @@
/> />
</a-form-item> </a-form-item>
<a-form-item label="合同存档"> <a-form-item label="合同存档">
<a-switch :checked="form.isInStock" :checked-value="1" :un-checked-value="0" checked-children="已归档" <a-switch
un-checked-children="未归档" @change="changeInStock" /> :checked="form.isInStock"
:checked-value="1"
:un-checked-value="0"
checked-children="已归档"
un-checked-children="未归档"
@change="changeInStock"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :md="8" :sm="24" :xs="24"> <a-col :md="8" :sm="24" :xs="24">
@@ -121,8 +123,14 @@
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item label="是否自动结算"> <a-form-item label="是否自动结算">
<a-switch :checked="form.autoSettle" :checked-value="1" :un-checked-value="0" checked-children="" <a-switch
un-checked-children="" @change="changeAutoSettle" /> :checked="form.autoSettle"
:checked-value="1"
:un-checked-value="0"
checked-children=""
un-checked-children=""
@change="changeAutoSettle"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@@ -139,13 +147,21 @@
</a-col> </a-col>
<a-col :span="8"> <a-col :span="8">
<a-form-item label="欠收金额汇总"> <a-form-item label="欠收金额汇总">
<p style="margin-bottom: 0">{{ form.totalSettleAmount - form.totalIncomeAmount }}</p> <p style="margin-bottom: 0">{{
form.totalSettleAmount - form.totalIncomeAmount
}}</p>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
<div class="flex flex-col justify-start justify-start" <div
style="padding: 1rem 0;border-top: 1px solid #dcdfe6; border-bottom: 1px solid #dcdfe6"> class="flex flex-col justify-start justify-start"
style="
padding: 1rem 0;
border-top: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
"
>
<div> <div>
<p>合同电子存档</p> <p>合同电子存档</p>
<div class="flex justify-start"> <div class="flex justify-start">
@@ -164,8 +180,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="flex justify-start items-center" <div
style="padding: 1rem 0;border-top: 1px solid #dcdfe6;"> class="flex justify-start items-center"
style="padding: 1rem 0; border-top: 1px solid #dcdfe6"
>
<div class="flex justify-start items-center"> <div class="flex justify-start items-center">
<unordered-list-outlined /> <unordered-list-outlined />
<span>合同签订设备清单</span> <span>合同签订设备清单</span>
@@ -211,62 +229,119 @@
</a-col> </a-col>
</a-row> </a-row>
<div style="min-height: 10rem"> <div style="min-height: 10rem">
<div class=" p-05 flex justify-center items-center" v-if="contractEquipmentList.length === 0"> <div
class="p-05 flex justify-center items-center"
v-if="contractEquipmentList.length === 0"
>
<span class="text-grey">暂无数据</span> <span class="text-grey">暂无数据</span>
</div> </div>
<template v-else> <template v-else>
<a-row class="text-center" v-for="(item, index) in contractEquipmentList" <a-row
:key="index"> class="text-center"
v-for="(item, index) in contractEquipmentList"
:key="index"
>
<a-col :span="3" class="p-05 border-r-white"> <a-col :span="3" class="p-05 border-r-white">
<a-select placeholder="必选项" style="width: 100%" size="small" @change="changeEquipment($event, index)" <a-select
v-model:value="contractEquipmentList[index].equipmentId"> placeholder="必选项"
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.equipmentId"> style="width: 100%"
size="small"
@change="changeEquipment($event, index)"
v-model:value="contractEquipmentList[index].equipmentId"
>
<a-select-option
v-for="(item, index) in equipmentList"
:key="index"
:value="item.equipmentId"
>
{{ item.name }}({{ item.model }}) {{ item.name }}({{ item.model }})
</a-select-option> </a-select-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].equipmentModel" size="small" readonly/> <a-input
v-model:value="contractEquipmentList[index].equipmentModel"
size="small"
readonly
/>
</a-col> </a-col>
<a-col :span="3" class="p-05 border-r-white"> <a-col :span="3" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].filingNo" size="small" readonly/> <a-input
v-model:value="contractEquipmentList[index].filingNo"
size="small"
readonly
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].num" size="small" placeholder="必填项" type="number"> <a-input
v-model:value="contractEquipmentList[index].num"
size="small"
placeholder="必填项"
type="number"
>
<template #suffix></template> <template #suffix></template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].planRentMonth" size="small" placeholder="必填项" <a-input
type="number" /> v-model:value="contractEquipmentList[index].planRentMonth"
size="small"
placeholder="必填项"
type="number"
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].rentAmount" size="small" placeholder="必填项" <a-input
type="number" /> v-model:value="contractEquipmentList[index].rentAmount"
size="small"
placeholder="必填项"
type="number"
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].inOutAmount" size="small" placeholder="必填项" <a-input
type="number" /> v-model:value="contractEquipmentList[index].inOutAmount"
size="small"
placeholder="必填项"
type="number"
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].workerAmount" size="small" placeholder="必填项" <a-input
type="number" /> v-model:value="contractEquipmentList[index].workerAmount"
size="small"
placeholder="必填项"
type="number"
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].otherAmount" size="small" placeholder="必填项" <a-input
type="number" /> v-model:value="contractEquipmentList[index].otherAmount"
size="small"
placeholder="必填项"
type="number"
/>
</a-col> </a-col>
<a-col :span="2" class="p-05 border-r-white"> <a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].preBuryAmount" size="small" <a-input
type="number" /> v-model:value="contractEquipmentList[index].preBuryAmount"
size="small"
type="number"
/>
</a-col> </a-col>
<a-col :span="1" class="p-05 border-r-white"> <a-col :span="1" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].remark" size="small" placeholder="可选项" /> <a-input
v-model:value="contractEquipmentList[index].remark"
size="small"
placeholder="可选项"
/>
</a-col> </a-col>
<a-col :span="1" class="p-05"> <a-col :span="1" class="p-05">
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer" <close-circle-outlined
@click.native="delEquipment(index)" /> style="font-size: 1.5rem; color: pink; cursor: pointer"
@click.native="delEquipment(index)"
/>
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
@@ -285,39 +360,46 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue"; import { ref, reactive, watch, computed } from 'vue';
import { Form, message, UploadFile } from "ant-design-vue"; import { Form, message, UploadFile } from 'ant-design-vue';
import { assignObject } from "ele-admin-pro"; import { assignObject } from 'ele-admin-pro';
import { updateContract, addContract } from "@/api/tower/contract"; import { updateContract, addContract } from '@/api/tower/contract';
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from '@/store/modules/user';
import { Contract } from "@/api/tower/contract/model"; import { Contract } from '@/api/tower/contract/model';
import dayjs from "dayjs"; import dayjs from 'dayjs';
import { ContractFile } from "@/api/tower/contractFile/model"; import { ContractFile } from '@/api/tower/contractFile/model';
import { import {
PlusOutlined, PlusOutlined,
UnorderedListOutlined, UnorderedListOutlined,
CloseCircleOutlined, UploadOutlined CloseCircleOutlined,
} from "@ant-design/icons-vue"; UploadOutlined
import { ContractEquipment } from "@/api/tower/contractEquipment/model"; } from '@ant-design/icons-vue';
import { TowerModel } from "@/api/tower/model/model"; import { ContractEquipment } from '@/api/tower/contractEquipment/model';
import { listTowerModel } from "@/api/tower/model"; import { TowerModel } from '@/api/tower/model/model';
import { addBatchContractFile, listContractFile } from "@/api/tower/contractFile"; import { listTowerModel } from '@/api/tower/model';
import { addBatchContractEquipment, listContractEquipment } from "@/api/tower/contractEquipment"; import {
import { Company } from "@/api/system/company/model"; addBatchContractFile,
import { Customer } from "@/api/oa/customer/model"; listContractFile
import { listTowerEquipment } from "@/api/tower/equipment"; } from '@/api/tower/contractFile';
import { TowerEquipment } from "@/api/tower/equipment/model"; import {
import { TOKEN_STORE_NAME } from "@/config/setting"; addBatchContractEquipment,
import { FileItem } from "ele-admin-pro/es/ele-file-list/types"; listContractEquipment
import { Equipment } from "@/api/apps/equipment/model"; } from '@/api/tower/contractEquipment';
import { Company } from '@/api/system/company/model';
import { Customer } from '@/api/oa/customer/model';
import { listTowerEquipment } from '@/api/tower/equipment';
import { TowerEquipment } from '@/api/tower/equipment/model';
import { TOKEN_STORE_NAME } from '@/config/setting';
import { FileItem } from 'ele-admin-pro/es/ele-file-list/types';
import { Equipment } from '@/api/apps/equipment/model';
const userStore = useUserStore(); const userStore = useUserStore();
// 当前用户信息 // 当前用户信息
const loginUser = computed(() => userStore.info ?? {}); const loginUser = computed(() => userStore.info ?? {});
const token = localStorage.getItem(TOKEN_STORE_NAME); const token = localStorage.getItem(TOKEN_STORE_NAME);
const now = dayjs().format("YYYY-MM-DD HH:mm:ss"); const now = dayjs().format('YYYY-MM-DD HH:mm:ss');
// 是否是修改 // 是否是修改
const isUpdate = ref(false); const isUpdate = ref(false);
@@ -330,8 +412,8 @@ const props = defineProps<{
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: "done"): void; (e: 'done'): void;
(e: "update:visible", visible: boolean): void; (e: 'update:visible', visible: boolean): void;
}>(); }>();
// 提交状态 // 提交状态
@@ -345,11 +427,11 @@ const form = reactive<Contract>({
projectId: undefined, projectId: undefined,
companyId: undefined, companyId: undefined,
customerId: undefined, customerId: undefined,
customerContact: "", customerContact: '',
contactNumber: "", contactNumber: '',
signDate: "", signDate: '',
startDate: "", startDate: '',
endDate: "", endDate: '',
contractAmount: undefined, contractAmount: undefined,
contactAgreeAmount: undefined, contactAgreeAmount: undefined,
totalSettleAmount: 0, totalSettleAmount: 0,
@@ -357,13 +439,13 @@ const form = reactive<Contract>({
isInStock: 0, isInStock: 0,
autoSettle: 0, autoSettle: 0,
payRate: undefined, payRate: undefined,
remark: "", remark: '',
fileList: "[]" fileList: '[]'
}); });
/* 更新visible */ /* 更新visible */
const updateVisible = (value: boolean) => { const updateVisible = (value: boolean) => {
emit("update:visible", value); emit('update:visible', value);
}; };
// 表单验证规则 // 表单验证规则
@@ -371,8 +453,8 @@ const rules = reactive({
projectId: [ projectId: [
{ {
required: true, required: true,
message: "请选择项目", message: '请选择项目',
trigger: "blur" trigger: 'blur'
} }
], ],
// contactNumber: [ // contactNumber: [
@@ -385,20 +467,20 @@ const rules = reactive({
companyId: [ companyId: [
{ {
required: true, required: true,
message: "请选择出租单位", message: '请选择出租单位',
trigger: "blur" trigger: 'blur'
} }
], ],
customerId: [ customerId: [
{ {
required: true, required: true,
message: "请选择承租单位", message: '请选择承租单位',
trigger: "blur" trigger: 'blur'
} }
] ]
}); });
const projectName = ref<string>(""); const projectName = ref<string>('');
const chooseProject = (res) => { const chooseProject = (res) => {
// console.log(res) // console.log(res)
projectName.value = res.projectName; projectName.value = res.projectName;
@@ -417,7 +499,7 @@ const chooseCompany = (res: Company) => {
form.companyId = res.companyId; form.companyId = res.companyId;
}; };
const customerName = ref<string>(""); const customerName = ref<string>('');
const chooseCustomer = (res: Customer) => { const chooseCustomer = (res: Customer) => {
customerName.value = res.name; customerName.value = res.name;
form.customerId = res.customerId; form.customerId = res.customerId;
@@ -432,7 +514,6 @@ const changeAutoSettle = (checked) => {
form.autoSettle = checked; form.autoSettle = checked;
}; };
const fileList = ref<FileItem[]>([]); const fileList = ref<FileItem[]>([]);
interface FileInfo { interface FileInfo {
@@ -453,16 +534,22 @@ const onFileUpload = (info: FileInfo) => {
}; };
const contractFileList = ref<ContractFile[]>([]); const contractFileList = ref<ContractFile[]>([]);
const uploadFile = path => { const uploadFile = (path) => {
contractFileList.value.push({ path, contractId: 0, userId: loginUser.value.userId }); contractFileList.value.push({
path,
contractId: 0,
userId: loginUser.value.userId
});
}; };
const delFile = index => { const delFile = (index) => {
contractFileList.value.splice(index, 1); contractFileList.value.splice(index, 1);
}; };
const getContractFileList = async () => { const getContractFileList = async () => {
contractFileList.value = await listContractFile({ contractId: props.data?.contractId }); contractFileList.value = await listContractFile({
contractId: props.data?.contractId
});
}; };
const equipmentList = ref<TowerEquipment[]>([]); const equipmentList = ref<TowerEquipment[]>([]);
@@ -477,14 +564,16 @@ const getEquipmentModelList = async () => {
const contractEquipmentList = ref<ContractEquipment[]>([]); const contractEquipmentList = ref<ContractEquipment[]>([]);
const getContractEquipmentList = async () => { const getContractEquipmentList = async () => {
contractEquipmentList.value = await listContractEquipment({ contractId: props.data?.contractId }); contractEquipmentList.value = await listContractEquipment({
contractId: props.data?.contractId
});
}; };
const chooseEquipmentName = (res, index) => { const chooseEquipmentName = (res, index) => {
contractEquipmentList.value[index].equipmentName = res.name; contractEquipmentList.value[index].equipmentName = res.name;
}; };
const delEquipment = index => { const delEquipment = (index) => {
contractEquipmentList.value.splice(index, 1); contractEquipmentList.value.splice(index, 1);
}; };
@@ -493,8 +582,8 @@ const addEquipment = () => {
contractEquipmentId: null, contractEquipmentId: null,
contractId: null, contractId: null,
equipmentId: undefined, equipmentId: undefined,
equipmentName: "", equipmentName: '',
equipmentModel: "", equipmentModel: '',
num: null, num: null,
planRentMonth: null, planRentMonth: null,
rentAmount: null, rentAmount: null,
@@ -514,7 +603,7 @@ const save = () => {
.then(async () => { .then(async () => {
loading.value = true; loading.value = true;
// 去除空格 // 去除空格
form.contactNumber = form.contactNumber?.replace(/\s*/g, ""); form.contactNumber = form.contactNumber?.replace(/\s*/g, '');
// 判断权限 // 判断权限
// if (loginUser.value.roles?.[0].roleCode != 'admin'){ // if (loginUser.value.roles?.[0].roleCode != 'admin'){
// form.status = '1'; // form.status = '1';
@@ -525,42 +614,42 @@ const save = () => {
for (let i = 0; i < contractEquipmentList.value.length; i++) { for (let i = 0; i < contractEquipmentList.value.length; i++) {
if (!contractEquipmentList.value[i].equipmentId) { if (!contractEquipmentList.value[i].equipmentId) {
loading.value = false; loading.value = false;
message.error("请选择设备"); message.error('请选择设备');
return; return;
} }
if (!contractEquipmentList.value[i].equipmentModel) { if (!contractEquipmentList.value[i].equipmentModel) {
loading.value = false; loading.value = false;
message.error("请选择设备型号"); message.error('请选择设备型号');
return; return;
} }
if (!contractEquipmentList.value[i].num) { if (!contractEquipmentList.value[i].num) {
loading.value = false; loading.value = false;
message.error("请输入签订数量"); message.error('请输入签订数量');
return; return;
} }
if (contractEquipmentList.value[i].planRentMonth === null) { if (contractEquipmentList.value[i].planRentMonth === null) {
loading.value = false; loading.value = false;
message.error("请输入计划租期"); message.error('请输入计划租期');
return; return;
} }
if (contractEquipmentList.value[i].rentAmount === null) { if (contractEquipmentList.value[i].rentAmount === null) {
loading.value = false; loading.value = false;
message.error("请输入租金"); message.error('请输入租金');
return; return;
} }
if (contractEquipmentList.value[i].inOutAmount === null) { if (contractEquipmentList.value[i].inOutAmount === null) {
loading.value = false; loading.value = false;
message.error("请输入进退场费"); message.error('请输入进退场费');
return; return;
} }
if (contractEquipmentList.value[i].workerAmount === null) { if (contractEquipmentList.value[i].workerAmount === null) {
loading.value = false; loading.value = false;
message.error("请输入劳务费用"); message.error('请输入劳务费用');
return; return;
} }
if (contractEquipmentList.value[i].otherAmount === null) { if (contractEquipmentList.value[i].otherAmount === null) {
loading.value = false; loading.value = false;
message.error("请输入其他费用"); message.error('请输入其他费用');
return; return;
} }
} }
@@ -572,15 +661,14 @@ const save = () => {
}); });
const contractId = res?.data; const contractId = res?.data;
// if (contractFileList.value.length > 0) await saveFileList(contractId); // if (contractFileList.value.length > 0) await saveFileList(contractId);
if (contractEquipmentList.value.length > 0) await saveEquipmentList(contractId); if (contractEquipmentList.value.length > 0)
await saveEquipmentList(contractId);
loading.value = false; loading.value = false;
message.success(res?.message); message.success(res?.message);
updateVisible(false); updateVisible(false);
emit("done"); emit('done');
}) })
.catch(() => { .catch(() => {});
});
}; };
const saveFileList = async (contractId) => { const saveFileList = async (contractId) => {
@@ -598,11 +686,13 @@ const saveEquipmentList = async (contractId) => {
}; };
const changeEquipment = (equipmentId, index) => { const changeEquipment = (equipmentId, index) => {
const equip = equipmentList.value.filter(item => item.equipmentId === equipmentId)[0] const equip = equipmentList.value.filter(
console.log(equip) (item) => item.equipmentId === equipmentId
contractEquipmentList.value[index].equipmentModel = equip.model )[0];
contractEquipmentList.value[index].filingNo = equip.filingNo console.log(equip);
} contractEquipmentList.value[index].equipmentModel = equip.model;
contractEquipmentList.value[index].filingNo = equip.filingNo;
};
watch( watch(
() => props.visible, () => props.visible,
@@ -626,7 +716,7 @@ watch(
isUpdate.value = false; isUpdate.value = false;
} }
} else { } else {
projectName.value = customerName.value = companyName.value = ""; projectName.value = customerName.value = companyName.value = '';
contractFileList.value = []; contractFileList.value = [];
fileList.value = []; fileList.value = [];
resetFields(); resetFields();

View File

@@ -0,0 +1,192 @@
<!-- 编辑弹窗 -->
<template xmlns="">
<ele-modal
:width="500"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改保养计划' : '新建保养计划'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 6, sm: 6, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 18, sm: 20, xs: 24 } : { flex: '1' }
"
>
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 22, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="项目名称" name="name">
<ProjectSelectModel
:placeholder="`请选择项目`"
v-model:value="form.projectName"
@done="chooseProject"
/>
</a-form-item>
<a-form-item label="所在地" name="address">
<a-input
allow-clear
placeholder="请输入项目地址"
v-model:value="form.address"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue/es';
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
import { storeToRefs } from 'pinia';
import { useThemeStore } from '@/store/modules/theme';
import useFormData from '@/utils/use-form-data';
import type { Security } from '@/api/tower/security/model';
import { addSecurity, updateSecurity } from '@/api/tower/security';
import { Project } from '@/api/tower/project/model';
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Security | null;
}>();
const formRef = ref<FormInstance | null>(null);
// 是否是修改
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<Security>({
securityId: undefined,
projectId: undefined,
projectName: undefined,
securityCode: undefined,
address: '',
status: 0,
sortNumber: 100
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
name: [
{
required: true,
message: '请输入设备名称',
type: 'string',
trigger: 'blur'
}
],
model: [
{
required: true,
message: '请输入设备型号',
type: 'string',
trigger: 'blur'
}
],
yearLife: [
{
required: true,
message: '请输入设备使用年限',
type: 'number',
trigger: 'blur'
}
],
sortNumber: [
{
required: true,
message: '请输入排序号',
type: 'number',
trigger: 'blur'
}
]
});
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const categoryForm = {
...form
};
const saveOrUpdate = isUpdate.value ? updateSecurity : addSecurity;
saveOrUpdate(categoryForm)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const chooseProject = (row: Project) => {
console.log(row);
form.projectId = row.projectId;
form.projectName = row.projectName;
form.address = row.projectAddress;
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignFields({
...props.data
});
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
formRef.value?.clearValidate();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 300px;
}
.ml-10 {
margin-left: 5px;
}
</style>

View File

@@ -0,0 +1,222 @@
<template>
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="securityRecordId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
:expand-icon-column-index="1"
:scroll="{ x: 1200 }"
cache-key="towerModel"
>
<template #toolbar>
<a-space>
<ProjectSelectModel
:placeholder="`请选择项目`"
v-model:value="projectName"
@done="chooseProject"
/>
<a-radio-group v-model:value="searchStatus" @change="onStatus">
<a-radio-button value="0">正常</a-radio-button>
<a-radio-button value="1">待修</a-radio-button>
<a-radio-button value="2">异常已修</a-radio-button>
<a-radio-button value="3">异常未修</a-radio-button>
</a-radio-group>
<a-range-picker
v-model:value="dateRange"
@change="onRange"
value-format="YYYY-MM-DD"
class="ele-fluid"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'userId'">
{{ `${record.nickname}` }}
</template>
<template v-if="column.key === 'images'">
<a-image :src="record.images" :width="120" />
</template>
<template v-if="column.key === 'longitude'">
{{ `${record.longitude}, ${record.latitude}` }}
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status == 0">正常</a-tag>
<a-tag v-if="record.status == 1" color="red">待修</a-tag>
<a-tag v-if="record.status == 2" color="green">异常已修</a-tag>
<a-tag v-if="record.status == 3" color="orange">异常未修</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
placement="topRight"
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<SecurityRecordEdit
v-model:visible="showEdit"
:data="current"
@done="reload"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { message } from 'ant-design-vue/es';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { messageLoading, toDateString } from 'ele-admin-pro/es';
import type { EleProTable } from 'ele-admin-pro/es';
import type {
SecurityRecord,
SecurityRecordParam
} from '@/api/tower/security-record/model';
import {
pageSecurityRecord,
removeSecurityRecord
} from '@/api/tower/security-record';
import SecurityRecordEdit from './components/security-record-edit.vue';
import { Project } from '@/api/tower/project/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '操作人',
dataIndex: 'userId',
key: 'userId'
},
{
title: '现场图片',
dataIndex: 'images',
key: 'images'
},
{
title: '定位',
dataIndex: 'longitude',
key: 'longitude'
},
{
title: '备注说明',
dataIndex: 'comments',
key: 'comments'
},
{
title: '完成状态',
dataIndex: 'status',
key: 'status',
width: 180
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
customRender: ({ text }) => toDateString(text)
}
]);
// 当前编辑数据
const current = ref<SecurityRecord | null>(null);
const searchText = ref('');
const searchStatus = ref('');
// 是否显示编辑弹窗
const showEdit = ref(false);
const projectName = ref('');
// 日期范围选择
const dateRange = ref<[string, string]>(['', '']);
/* 搜索 */
const onRange = () => {
const [d1, d2] = dateRange.value ?? [];
reload({
createTimeStart: d1 ? d1 + ' 00:00:00' : '',
createTimeEnd: d2 ? d2 + ' 23:59:59' : ''
});
};
// 表格数据源
const datasource: DatasourceFunction = ({ where }) => {
if (searchText.value && searchText.value != '') {
where.keywords = searchText.value;
}
return pageSecurityRecord({ ...where });
};
/* 刷新表格 */
const reload = (where?: SecurityRecordParam) => {
tableRef?.value?.reload({ where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: SecurityRecord | null, id?: number) => {
current.value = row ?? null;
showEdit.value = true;
};
const search = (searchText) => {
reload({ keywords: searchText });
};
const chooseProject = (row: Project) => {
reload({ projectId: row.projectId });
};
const onStatus = (e: any) => {
console.log(e.target.value);
const status = e.target.value;
reload({ status });
};
/* 删除单个 */
const remove = (row: SecurityRecord) => {
const hide = messageLoading('请求中..', 0);
removeSecurityRecord(row.securityRecordId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 自定义行属性 */
const customRow = (record: SecurityRecord) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
</script>
<script lang="ts">
export default {
name: 'TowerSecurityRecord'
};
</script>

View File

@@ -0,0 +1,249 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="740"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改分类' : '新建分类'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 6, sm: 4, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 18, sm: 20, xs: 24 } : { flex: '1' }
"
>
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 12, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="上级分类" name="parentId">
<a-tree-select
allow-clear
:tree-data="categoryList"
tree-default-expand-all
placeholder="请选择上级分类"
:value="form.parentId || undefined"
:dropdown-style="{ maxHeight: '360px', overflow: 'auto' }"
@update:value="(value?: number) => (form.parentId = value)"
/>
</a-form-item>
<a-form-item label="设备型号" name="title">
<a-input
allow-clear
placeholder="请输入分类名称"
v-model:value="form.title"
@pressEnter="save"
/>
</a-form-item>
<a-form-item label="使用年限" name="yearLife">
<a-input
allow-clear
placeholder="请输入分类名称"
v-model:value="form.yearLife"
@pressEnter="save"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue/es';
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
import { storeToRefs } from 'pinia';
import { useThemeStore } from '@/store/modules/theme';
import useFormData from '@/utils/use-form-data';
import type { Security } from '@/api/tower/security/model';
import { addSecurity, updateSecurity } from '@/api/tower/security';
import { FILE_SERVER } from "@/config/setting";
import { ItemType } from "ele-admin-pro/es/ele-image-upload/types";
import { uploadFile } from "@/api/system/file";
import { LoginRecordParam } from "@/api/system/login-record/model";
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Security | null;
// 上级分类id
parentId?: number;
// 全部分类数据
categoryList: Security[];
}>();
// 表单数据
const { form, resetFields, assignFields } = useFormData<Security>({
securityId: undefined,
projectName: undefined,
securityCode: undefined,
regionName: '',
status: 0,
address: undefined,
sortNumber: 100
});
//
const formRef = ref<FormInstance | null>(null);
// 是否是修改
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 已上传数据, 可赋初始值用于回显
const images = ref([]);
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
title: [
{
required: true,
message: '请输入分类名称',
type: 'string',
trigger: 'blur'
}
],
sortNumber: [
{
required: true,
message: '请输入排序号',
type: 'number',
trigger: 'blur'
}
],
meta: [
{
type: 'string',
validator: async (_rule: Rule, value: string) => {
if (value) {
const msg = '请输入正确的JSON格式';
try {
const obj = JSON.parse(value);
if (typeof obj !== 'object' || obj === null) {
return Promise.reject(msg);
}
} catch (_e) {
return Promise.reject(msg);
}
}
return Promise.resolve();
},
trigger: 'blur'
}
]
});
// 上传文件
const onUpload = (d: ItemType) => {
uploadFile(<File>d.file)
.then((result) => {
form.image = result.path;
message.success('上传成功');
})
.catch((e) => {
message.error(e.message);
});
};
const onClose = () => {
form.image = ''
}
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const categoryForm = {
...form,
parentId: form.parentId || 0
};
const saveOrUpdate = isUpdate.value ? updateSecurity : addSecurity;
saveOrUpdate(categoryForm)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const updateHideValue = (value: boolean) => {
form.status = value ? 0 : 1;
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
// 头像赋值
images.value = [];
if(props.data.image){
images.value.push({ uid:1, url: props.data.image, status: '' });
}
assignFields({
...props.data,
parentId:
props.data.parentId === 0 ? undefined : props.data.parentId
});
isUpdate.value = true;
} else {
form.parentId = props.parentId;
isUpdate.value = false;
}
} else {
resetFields();
formRef.value?.clearValidate();
}
}
);
</script>
<script lang="ts">
import * as icons from '@/layout/menu-icons';
export default {
components: icons,
data() {
return {
iconData: [
{
title: '已引入的图标',
icons: Object.keys(icons)
}
]
};
}
};
</script>

View File

@@ -0,0 +1,192 @@
<!-- 编辑弹窗 -->
<template xmlns="">
<ele-modal
:width="500"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改保养计划' : '新建保养计划'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 6, sm: 6, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 18, sm: 20, xs: 24 } : { flex: '1' }
"
>
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 22, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="项目名称" name="name">
<ProjectSelectModel
:placeholder="`请选择项目`"
v-model:value="form.projectName"
@done="chooseProject"
/>
</a-form-item>
<a-form-item label="所在地" name="address">
<a-input
allow-clear
placeholder="请输入项目地址"
v-model:value="form.address"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue/es';
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
import { storeToRefs } from 'pinia';
import { useThemeStore } from '@/store/modules/theme';
import useFormData from '@/utils/use-form-data';
import type { Security } from '@/api/tower/security/model';
import { addSecurity, updateSecurity } from '@/api/tower/security';
import { Project } from '@/api/tower/project/model';
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Security | null;
}>();
const formRef = ref<FormInstance | null>(null);
// 是否是修改
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<Security>({
securityId: undefined,
projectId: undefined,
projectName: undefined,
securityCode: undefined,
address: '',
status: 0,
sortNumber: 100
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
name: [
{
required: true,
message: '请输入设备名称',
type: 'string',
trigger: 'blur'
}
],
model: [
{
required: true,
message: '请输入设备型号',
type: 'string',
trigger: 'blur'
}
],
yearLife: [
{
required: true,
message: '请输入设备使用年限',
type: 'number',
trigger: 'blur'
}
],
sortNumber: [
{
required: true,
message: '请输入排序号',
type: 'number',
trigger: 'blur'
}
]
});
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const categoryForm = {
...form
};
const saveOrUpdate = isUpdate.value ? updateSecurity : addSecurity;
saveOrUpdate(categoryForm)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const chooseProject = (row: Project) => {
console.log(row);
form.projectId = row.projectId;
form.projectName = row.projectName;
form.address = row.projectAddress;
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignFields({
...props.data
});
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
formRef.value?.clearValidate();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 300px;
}
.ml-10 {
margin-left: 5px;
}
</style>

View File

@@ -0,0 +1,169 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="1000"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '保养记录' : '保养记录'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 6, sm: 6, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 18, sm: 20, xs: 24 } : { flex: '1' }
"
>
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 22, sm: 24, xs: 24 } : { span: 12 }"
/>
</a-row>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue/es';
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
import { storeToRefs } from 'pinia';
import { useThemeStore } from '@/store/modules/theme';
import useFormData from '@/utils/use-form-data';
import type { TowerModel } from '@/api/tower/model/model';
import { addTowerModel, updateTowerModel } from '@/api/tower/model';
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: TowerModel | null;
}>();
const formRef = ref<FormInstance | null>(null);
// 是否是修改
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<TowerModel>({
name: '',
modelId: undefined,
model: undefined,
image: '',
status: 0,
yearLife: undefined,
sortNumber: 100
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
name: [
{
required: true,
message: '请输入设备名称',
type: 'string',
trigger: 'blur'
}
],
model: [
{
required: true,
message: '请输入设备型号',
type: 'string',
trigger: 'blur'
}
],
yearLife: [
{
required: true,
message: '请输入设备使用年限',
type: 'number',
trigger: 'blur'
}
],
sortNumber: [
{
required: true,
message: '请输入排序号',
type: 'number',
trigger: 'blur'
}
]
});
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const categoryForm = {
...form
};
const saveOrUpdate = isUpdate.value ? updateTowerModel : addTowerModel;
saveOrUpdate(categoryForm)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignFields({
...props.data
});
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
formRef.value?.clearValidate();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 300px;
}
.ml-10 {
margin-left: 5px;
}
</style>

View File

@@ -0,0 +1,242 @@
<template>
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="securityId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
:expand-icon-column-index="1"
:scroll="{ x: 1200 }"
cache-key="towerModel"
>
<template #toolbar>
<a-space>
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
<template #icon>
<plus-outlined />
</template>
<span>新建</span>
</a-button>
<!-- 搜索表单 -->
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入搜索关键词"
@search="search"
@pressEnter="search"
/>
<a-radio-group v-model:value="searchStatus" @change="onStatus">
<a-radio-button value="0">正常</a-radio-button>
<a-radio-button value="1">待修</a-radio-button>
<a-radio-button value="2">异常已修</a-radio-button>
<a-radio-button value="3">异常未修</a-radio-button>
</a-radio-group>
<a-range-picker
v-model:value="dateRange"
@change="onRange"
value-format="YYYY-MM-DD"
class="ele-fluid"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<a-tag v-if="record.status == 0">正常</a-tag>
<a-tag v-if="record.status == 1" color="red">待修</a-tag>
<a-tag v-if="record.status == 2" color="green">异常已修</a-tag>
<a-tag v-if="record.status == 3" color="orange">异常未修</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openRecord(record)">保养记录</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
placement="topRight"
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<SecurityEdit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 保养记录 -->
<SecurityRecord
v-model:visible="showRecord"
:data="current"
@done="reload"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { message } from 'ant-design-vue/es';
import { PlusOutlined } from '@ant-design/icons-vue';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { messageLoading, toDateString } from 'ele-admin-pro/es';
import type { EleProTable } from 'ele-admin-pro/es';
import type { Security, SecurityParam } from '@/api/tower/security/model';
import {
pageSecurity,
listSecurity,
removeSecurity
} from '@/api/tower/security';
import SecurityEdit from './components/security-edit.vue';
import SecurityRecord from './components/security-record.vue';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
// {
// key: 'index',
// width: 48,
// align: 'center',
// fixed: 'left',
// hideInSetting: true,
// customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
// },
// {
// title: 'ID',
// dataIndex: 'securityId',
// key: 'securityId'
// },
{
title: '保养编号',
dataIndex: 'securityCode',
key: 'securityCode'
},
{
title: '项目名称',
dataIndex: 'projectName',
key: 'projectName'
},
{
title: '所在地',
dataIndex: 'address',
key: 'address',
showSorterTooltip: false,
ellipsis: true
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 180
},
{
title: '生成时间',
dataIndex: 'createTime',
width: 180,
customRender: ({ text }) => toDateString(text)
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center'
}
]);
// 当前编辑数据
const current = ref<Security | null>(null);
const searchText = ref('');
const searchStatus = ref('');
// 是否显示编辑弹窗
const showEdit = ref(false);
const showRecord = ref(false);
// 日期范围选择
const dateRange = ref<[string, string]>(['', '']);
/* 搜索 */
const onRange = () => {
const [d1, d2] = dateRange.value ?? [];
reload({
createTimeStart: d1 ? d1 + ' 00:00:00' : '',
createTimeEnd: d2 ? d2 + ' 23:59:59' : ''
});
};
// 表格数据源
const datasource: DatasourceFunction = ({ where }) => {
if (searchText.value && searchText.value != '') {
where.keywords = searchText.value;
}
return pageSecurity({ ...where });
};
/* 刷新表格 */
const reload = (where?: SecurityParam) => {
tableRef?.value?.reload({ where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Security | null, id?: number) => {
current.value = row ?? null;
showEdit.value = true;
};
const openRecord = (row?: Security, id?: number) => {
current.value = row ?? null;
showRecord.value = true;
};
const search = (searchText) => {
reload({ keywords: searchText });
};
const onStatus = (e: any) => {
console.log(e.target.value);
const status = e.target.value;
reload({ status });
};
/* 删除单个 */
const remove = (row: Security) => {
const hide = messageLoading('请求中..', 0);
removeSecurity(row.securityId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 自定义行属性 */
const customRow = (record: Security) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
</script>
<script lang="ts">
export default {
name: 'TowerSecurity'
};
</script>