完成:保养记录和厂内维修模块

This commit is contained in:
gxwebsoft
2024-02-25 19:33:03 +08:00
parent 08f83ed015
commit aa56030cbd
16 changed files with 1442 additions and 400 deletions

View File

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

View File

@@ -1,5 +1,5 @@
import type { PageParam } from "@/api";
import { Dayjs } from "dayjs";
import type { PageParam } from '@/api';
import { Dayjs } from 'dayjs';
export interface Accessory {
accessoryId?: undefined;

View File

@@ -0,0 +1,109 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type {
SecurityPlant,
SecurityPlantParam
} from '@/api/tower/security-plant/model';
/**
* 分页查询仓库
*/
export async function pageSecurityPlant(params: SecurityPlantParam) {
const res = await request.get<ApiResult<PageResult<SecurityPlant>>>(
'/tower/tower-security-plant/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询仓库列表
*/
export async function listSecurityPlant(params?: SecurityPlantParam) {
const res = await request.get<ApiResult<SecurityPlant[]>>(
'/tower/tower-security-plant',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加仓库
*/
export async function addSecurityPlant(data: SecurityPlant) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-security-plant',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改仓库
*/
export async function updateSecurityPlant(data: SecurityPlant) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security-plant',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 绑定仓库
*/
export async function bindSecurityPlant(data: SecurityPlant) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-security-plant/bind',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除仓库
*/
export async function removeSecurityPlant(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security-plant/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除仓库
*/
export async function removeBatchSecurityPlant(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-security-plant/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,39 @@
import type { PageParam } from '@/api';
export interface SecurityPlant {
securityPlantId?: number;
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;
confirmStatus?: number;
userId?: number;
confirmId?: number;
comments?: string;
sortNumber?: number;
accessoryName?: string;
accessoryCategory?: object;
accessoryNo?: string;
accessorySpecs?: string;
accessoryModel?: string;
}
/**
* 搜索条件
*/
export interface SecurityPlantParam extends PageParam {
securityId?: number;
projectId?: number;
projectName?: string;
status?: number;
keywords?: string;
}

View File

@@ -2,6 +2,7 @@ import type { PageParam } from '@/api';
export interface SecurityRecord {
securityRecordId?: number;
securityId?: number;
projectName?: string;
projectId?: number;
securityCode?: string;
@@ -17,6 +18,11 @@ export interface SecurityRecord {
userId?: number;
comments?: string;
sortNumber?: number;
accessoryName?: string;
accessoryCategory?: object;
accessoryNo?: string;
accessorySpecs?: string;
accessoryModel?: string;
}
/**

View File

@@ -1,7 +1,7 @@
import type { PageParam } from '@/api';
export interface Security {
type: number;
type?: number;
securityId?: number;
projectName?: string;
projectId?: number;
@@ -22,6 +22,10 @@ export interface Security {
userId?: number;
comments?: string;
sortNumber?: number;
accessoryNo?: string;
accessoryCategory?: object;
accessoryModel?: string;
accessorySpecs?: string;
}
/**

View File

@@ -0,0 +1,157 @@
<template>
<ele-modal
:width="750"
:visible="visible"
:maskClosable="false"
:title="title"
:footer="null"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
>
<ele-pro-table
ref="tableRef"
row-key="customerId"
:datasource="datasource"
:columns="columns"
:customRow="customRow"
:pagination="false"
>
<template #toolbar>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入搜索关键词"
style="width: 200px"
@search="reload"
@pressEnter="reload"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'customerLogo'">
<a-image
v-if="record.customerAvatar"
:src="FILE_THUMBNAIL + record.customerAvatar"
:preview="false"
:width="45"
/>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-button type="link">选择</a-button>
</a-space>
</template>
</template>
</ele-pro-table>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import {
ColumnItem,
DatasourceFunction
} from 'ele-admin-pro/es/ele-pro-table/types';
import { pageCustomer } from '@/api/oa/customer';
import { FILE_THUMBNAIL } from '@/config/setting';
import { EleProTable } from 'ele-admin-pro';
import { Customer, CustomerParam } from '@/api/oa/customer/model';
import { pageAccessory } from '@/api/tower/accessory';
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 标题
title?: string;
// 企业类型
customerType?: string;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done', data: Customer): void;
(e: 'update:visible', visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 搜索内容
const searchText = ref(null);
// 表格实例
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: '配件编号',
dataIndex: 'accessoryNo'
},
{
title: '配件分类',
dataIndex: 'accessoryCategory'
},
{
title: '适用设备型号',
dataIndex: 'accessoryModel'
},
{
title: '配件规格',
dataIndex: 'accessorySpecs'
},
{
title: '操作',
key: 'action',
align: 'center'
}
]);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
// where = {};
// 搜索条件
// if (searchText.value) {
// where.keywords = searchText.value;
// }
// if (props.customerType == 'empty') {
// where.emptyType = true;
// } else {
// where.customerType = props.customerType;
// }
// where.isStaff = true;
return pageAccessory({
...where,
...orders,
page,
limit
});
};
/* 搜索 */
const reload = (where?: CustomerParam) => {
tableRef?.value?.reload({ page: 1, where });
};
/* 自定义行属性 */
const customRow = (record: Customer) => {
return {
// 行点击事件
onClick: () => {
updateVisible(false);
emit('done', record);
}
};
};
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,61 @@
<template>
<div>
<a-input-group compact>
<a-input
disabled
style="width: calc(100% - 32px)"
v-model:value="value"
:placeholder="placeholder"
/>
<a-button @click="openEdit">
<template #icon><BulbOutlined class="ele-text-warning" /></template>
</a-button>
</a-input-group>
<!-- 选择弹窗 -->
<SelectData
v-model:visible="showEdit"
:data="current"
:title="placeholder"
:customer-type="customerType"
@done="onChange"
/>
</div>
</template>
<script lang="ts" setup>
import { BulbOutlined } from '@ant-design/icons-vue';
import { ref } from 'vue';
import SelectData from './components/select-data.vue';
import { Customer } from '@/api/oa/customer/model';
withDefaults(
defineProps<{
value?: any;
customerType?: string;
placeholder?: string;
}>(),
{
placeholder: '请选择数据'
}
);
const emit = defineEmits<{
(e: 'done', Customer): void;
(e: 'clear'): void;
}>();
// 是否显示编辑弹窗
const showEdit = ref(false);
// 当前编辑数据
const current = ref<Customer | null>(null);
/* 打开编辑弹窗 */
const openEdit = (row?: Customer) => {
current.value = row ?? null;
showEdit.value = true;
};
const onChange = (row) => {
emit('done', row);
};
</script>

View File

@@ -101,65 +101,65 @@
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
import { computed, createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
ExclamationCircleOutlined,
UserOutlined
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString, toTreeData } from "ele-admin-pro";
import Search from "./components/search.vue";
import AccessoryEdit from "./components/accessory-edit.vue";
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString, toTreeData } from 'ele-admin-pro';
import Search from './components/search.vue';
import AccessoryEdit from './components/accessory-edit.vue';
import {
pageAccessory,
removeAccessory,
removeBatchAccessory
} from "@/api/tower/accessory";
import { timeAgo } from "ele-admin-pro";
import type { Accessory, AccessoryParam } from "@/api/tower/accessory/model";
import { useUserStore } from "@/store/modules/user";
import { Category } from "@/api/goods/category/model";
import { listCategory } from "@/api/goods/category";
import { listTowerModel } from "@/api/tower/model";
import { TowerModel } from "@/api/tower/model/model";
} from '@/api/tower/accessory';
import { timeAgo } from 'ele-admin-pro';
import type { Accessory, AccessoryParam } from '@/api/tower/accessory/model';
import { useUserStore } from '@/store/modules/user';
import { Category } from '@/api/goods/category/model';
import { listCategory } from '@/api/goods/category';
import { listTowerModel } from '@/api/tower/model';
import { TowerModel } from '@/api/tower/model/model';
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const accessoryType = localStorage.getItem("accessoryType");
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const accessoryType = localStorage.getItem('accessoryType');
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Accessory[]>([]);
// 当前编辑数据
const current = ref<Accessory | null>(null);
// 树形数据
const data = ref<Category[]>([]);
const data2 = ref<TowerModel[]>([]);
const data2List = ref<TowerModel[]>([]);
// 表格选中数据
const selection = ref<Accessory[]>([]);
// 当前编辑数据
const current = ref<Accessory | null>(null);
// 树形数据
const data = ref<Category[]>([]);
const data2 = ref<TowerModel[]>([]);
const data2List = ref<TowerModel[]>([]);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 树展开的key
const expandedRowKeys = ref<number[]>([]);
// 树选中的key
const selectedRowKeys = ref<number[]>([]);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 树展开的key
const expandedRowKeys = ref<number[]>([]);
// 树选中的key
const selectedRowKeys = ref<number[]>([]);
// 表格数据源
const datasource: DatasourceFunction = ({
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
@@ -178,113 +178,113 @@ const datasource: DatasourceFunction = ({
page,
limit
});
};
};
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
key: 'index',
width: 48,
align: "center",
fixed: "left",
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "配件编号",
dataIndex: "accessoryNo"
title: '配件编号',
dataIndex: 'accessoryNo'
},
{
title: "生成厂家",
dataIndex: "accessoryName"
title: '生产厂家',
dataIndex: 'accessoryName'
},
{
title: "配件分类",
dataIndex: "accessoryCategory"
title: '配件分类',
dataIndex: 'accessoryCategory'
},
{
title: "适用设备型号",
dataIndex: "accessoryModel"
title: '适用设备型号',
dataIndex: 'accessoryModel'
},
{
title: "配件规格",
dataIndex: "accessorySpecs"
title: '配件规格',
dataIndex: 'accessorySpecs'
},
{
title: "单价",
dataIndex: "accessoryPrice"
title: '单价',
dataIndex: 'accessoryPrice'
},
{
title: "购买数量",
dataIndex: "accessoryNum"
title: '购买数量',
dataIndex: 'accessoryNum'
},
{
title: "配件单位",
dataIndex: "accessoryUnit"
title: '配件单位',
dataIndex: 'accessoryUnit'
},
{
title: "产权单位名称",
dataIndex: "companyName"
title: '产权单位名称',
dataIndex: 'companyName'
},
{
title: "制造厂商",
dataIndex: "manufactor"
title: '制造厂商',
dataIndex: 'manufactor'
},
{
title: "制造厂商编号",
dataIndex: "manufactorNo"
title: '制造厂商编号',
dataIndex: 'manufactorNo'
},
{
title: "使用年限",
dataIndex: "lifeYear"
title: '使用年限',
dataIndex: 'lifeYear'
},
{
title: "出厂日期",
dataIndex: "factoryDate",
customRender: ({ text }) => toDateString(text, "yyyy-MM-dd")
title: '出厂日期',
dataIndex: 'factoryDate',
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: "报废日期",
dataIndex: "scrapDate",
customRender: ({ text }) => toDateString(text, "yyyy-MM-dd")
title: '报废日期',
dataIndex: 'scrapDate',
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: "操作",
key: "action",
title: '操作',
key: 'action',
width: 200,
fixed: "right",
align: "center",
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
]);
/* 搜索 */
const reload = (where?: AccessoryParam) => {
/* 搜索 */
const reload = (where?: AccessoryParam) => {
console.log(where);
selection.value = [];
tableRef?.value?.reload({ where: where });
};
};
/* 打开编辑弹窗 */
const openEdit = (row?: Accessory) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Accessory) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开批量移动弹窗 */
const openMove = () => {
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Accessory) => {
/* 打开用户详情弹窗 */
const openInfo = (row?: Accessory) => {
current.value = row ?? null;
showInfo.value = true;
};
};
/* 删除单个 */
const remove = (row: Accessory) => {
const hide = message.loading("请求中..", 0);
/* 删除单个 */
const remove = (row: Accessory) => {
const hide = message.loading('请求中..', 0);
removeAccessory(row.accessoryId)
.then((msg) => {
hide();
@@ -295,27 +295,27 @@ const remove = (row: Accessory) => {
hide();
message.error(e.message);
});
};
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, '批量转移0000');
console.log(selection.value);
};
};
/* 批量删除 */
const removeBatch = () => {
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
const hide = message.loading('请求中..', 0);
removeBatchAccessory(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
@@ -334,10 +334,10 @@ const removeBatch = () => {
});
}
});
};
};
/* 查询 */
const query = () => {
/* 查询 */
const query = () => {
loading.value = true;
listCategory()
.then((list) => {
@@ -346,18 +346,18 @@ const query = () => {
list.forEach((d) => {
d.key = d.categoryId;
d.value = d.categoryId;
if (typeof d.categoryId === "number") {
if (typeof d.categoryId === 'number') {
eks.push(d.categoryId);
}
});
expandedRowKeys.value = eks;
data.value = toTreeData({
data: list,
idField: "categoryId",
parentIdField: "parentId"
idField: 'categoryId',
parentIdField: 'parentId'
});
if (list.length) {
if (typeof list[0].categoryId === "number") {
if (typeof list[0].categoryId === 'number') {
selectedRowKeys.value = [list[0].categoryId];
}
} else {
@@ -368,10 +368,10 @@ const query = () => {
loading.value = false;
message.error(e.message);
});
};
};
/* 自定义行属性 */
const customRow = (record: Accessory) => {
/* 自定义行属性 */
const customRow = (record: Accessory) => {
return {
// 行点击事件
onClick: () => {
@@ -382,25 +382,25 @@ const customRow = (record: Accessory) => {
openEdit(record);
}
};
};
};
query();
query();
</script>
<script lang="ts">
export default {
name: "Accessory"
};
export default {
name: 'Accessory'
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
}
</style>

View File

@@ -0,0 +1,237 @@
<!-- 编辑弹窗 -->
<template>
<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="projectName">
<TowerAccessory
:placeholder="`请选择构件`"
v-model:value="form.projectName"
@done="chooseProject"
/>
</a-form-item>
<a-form-item label="配件编号" name="accessoryNo">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryNo"
/>
</a-form-item>
<a-form-item label="配件分类" name="accessoryCategory">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryCategory"
/>
</a-form-item>
<a-form-item label="适用设备型号" name="accessoryModel">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryModel"
/>
</a-form-item>
<a-form-item label="配件规格" name="accessorySpecs">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessorySpecs"
/>
</a-form-item>
<a-form-item label="保养内容" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入保养内容"
v-model:value="form.comments"
/>
</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 { Accessory } from '@/api/tower/accessory/model';
import {
addSecurityPlant,
updateSecurityPlant
} from '@/api/tower/security-plant';
import { SecurityPlant } from '@/api/tower/security-plant/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<SecurityPlant>({
securityPlantId: undefined,
securityId: undefined,
projectId: undefined,
projectName: undefined,
securityCode: undefined,
accessoryCategory: undefined,
address: '',
status: 0,
sortNumber: 100
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
projectName: [
{
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
? updateSecurityPlant
: addSecurityPlant;
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: Accessory) => {
form.projectId = row.accessoryId;
form.projectName = row.accessoryName;
form.securityId = row.accessoryId;
form.accessoryNo = row.accessoryNo;
form.accessorySpecs = row.accessorySpecs;
form.accessoryModel = row.accessoryModel;
form.accessoryCategory = row.accessoryCategory;
};
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,251 @@
<template>
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="securityPlantId"
: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>
<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 === 'confirmId'">
{{ `${record.confirmId > 0 ? record.confirmNickname : '-'}` }}
</template>
<template v-if="column.key === 'confirmStatus'">
<a-tag v-if="record.confirmStatus == 0" color="red">待确认</a-tag>
<a-tag v-if="record.confirmStatus == 1" color="green">已确认</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>
<!-- 编辑弹窗 -->
<SecurityPlantEdit
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 {
SecurityPlant,
SecurityPlantParam
} from '@/api/tower/security-plant/model';
import {
pageSecurityPlant,
removeSecurityPlant
} from '@/api/tower/security-plant';
import SecurityPlantEdit from './components/security-plant-edit.vue';
import { Project } from '@/api/tower/project/model';
import { PlusOutlined } from '@ant-design/icons-vue';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '配件编号',
dataIndex: 'accessoryNo',
key: 'accessoryNo'
},
{
title: '生产厂家',
dataIndex: 'accessoryName',
key: 'accessoryName'
},
{
title: '配件分类',
dataIndex: 'accessoryCategory',
key: 'accessoryCategory'
},
{
title: '适用设备型号',
dataIndex: 'accessoryModel',
key: 'accessoryModel'
},
{
title: '配件规格',
dataIndex: 'accessorySpecs',
key: 'accessorySpecs'
},
{
title: '保养内容',
dataIndex: 'comments',
key: 'comments'
},
{
title: '操作人员',
dataIndex: 'userId',
key: 'userId',
width: 180
},
{
title: '确认人员',
dataIndex: 'confirmId',
key: 'confirmId',
width: 180
},
{
title: '确认状态',
dataIndex: 'confirmStatus',
key: 'confirmStatus',
width: 180
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
customRender: ({ text }) => toDateString(text)
}
]);
// 当前编辑数据
const current = ref<SecurityPlant | null>(null);
const searchText = 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 pageSecurityPlant({ ...where });
};
/* 刷新表格 */
const reload = (where?: SecurityPlantParam) => {
tableRef?.value?.reload({ where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: SecurityPlant | 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: SecurityPlant) => {
const hide = messageLoading('请求中..', 0);
removeSecurityPlant(row.securityPlantId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 自定义行属性 */
const customRow = (plant: SecurityPlant) => {
return {
// 行点击事件
onClick: () => {
// console.log(plant);
},
// 行双击事件
onDblclick: () => {
openEdit(plant);
}
};
};
</script>
<script lang="ts">
export default {
name: 'TowerSecurityPlant'
};
</script>

View File

@@ -1,10 +1,10 @@
<!-- 编辑弹窗 -->
<template xmlns="">
<template>
<ele-modal
:width="500"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改保养计划' : '新建保养计划'"
:title="isUpdate ? '修改保养记录' : '新建保养记录'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
@@ -22,18 +22,52 @@
<a-col
v-bind="styleResponsive ? { md: 22, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="项目名称" name="name">
<ProjectSelectModel
:placeholder="`请选择项目`"
<a-form-item label="选择构件" name="projectName">
<TowerAccessory
:placeholder="`请选择构件`"
v-model:value="form.projectName"
@done="chooseProject"
/>
</a-form-item>
<a-form-item label="所在地" name="address">
<a-form-item label="配件编号" name="accessoryNo">
<a-input
allow-clear
placeholder="请输入项目地址"
v-model:value="form.address"
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryNo"
/>
</a-form-item>
<a-form-item label="配件分类" name="accessoryCategory">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryCategory"
/>
</a-form-item>
<a-form-item label="适用设备型号" name="accessoryModel">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessoryModel"
/>
</a-form-item>
<a-form-item label="配件规格" name="accessorySpecs">
<a-input
allow-clear
placeholder="请选择构件"
:disabled="true"
v-model:value="form.accessorySpecs"
/>
</a-form-item>
<a-form-item label="保养内容" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入保养内容"
v-model:value="form.comments"
/>
</a-form-item>
</a-col>
@@ -50,8 +84,12 @@
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';
import { Accessory } from '@/api/tower/accessory/model';
import {
addSecurityRecord,
updateSecurityRecord
} from '@/api/tower/security-record';
import { SecurityRecord } from '@/api/tower/security-record/model';
// 是否开启响应式布局
const themeStore = useThemeStore();
@@ -76,11 +114,13 @@
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<Security>({
const { form, resetFields, assignFields } = useFormData<SecurityRecord>({
securityRecordId: undefined,
securityId: undefined,
projectId: undefined,
projectName: undefined,
securityCode: undefined,
accessoryCategory: undefined,
address: '',
status: 0,
sortNumber: 100
@@ -88,10 +128,10 @@
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
name: [
projectName: [
{
required: true,
message: '请输入设备名称',
message: '请选择构件',
type: 'string',
trigger: 'blur'
}
@@ -134,7 +174,9 @@
const categoryForm = {
...form
};
const saveOrUpdate = isUpdate.value ? updateSecurity : addSecurity;
const saveOrUpdate = isUpdate.value
? updateSecurityRecord
: addSecurityRecord;
saveOrUpdate(categoryForm)
.then((msg) => {
loading.value = false;
@@ -155,11 +197,14 @@
emit('update:visible', value);
};
const chooseProject = (row: Project) => {
console.log(row);
form.projectId = row.projectId;
form.projectName = row.projectName;
form.address = row.projectAddress;
const chooseProject = (row: Accessory) => {
form.projectId = row.accessoryId;
form.projectName = row.accessoryName;
form.securityId = row.accessoryId;
form.accessoryNo = row.accessoryNo;
form.accessorySpecs = row.accessorySpecs;
form.accessoryModel = row.accessoryModel;
form.accessoryCategory = row.accessoryCategory;
};
watch(

View File

@@ -14,17 +14,23 @@
>
<template #toolbar>
<a-space>
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
<template #icon>
<plus-outlined />
</template>
<span>新建</span>
</a-button>
<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-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"
@@ -44,7 +50,7 @@
{{ `${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 == 0" color="green">已保养</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>
@@ -93,6 +99,7 @@
} from '@/api/tower/security-record';
import SecurityRecordEdit from './components/security-record-edit.vue';
import { Project } from '@/api/tower/project/model';
import { PlusOutlined } from '@ant-design/icons-vue';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
@@ -100,31 +107,48 @@
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '操作人',
dataIndex: 'userId',
key: 'userId'
title: '配件编号',
dataIndex: 'accessoryNo',
key: 'accessoryNo'
},
{
title: '现场图片',
dataIndex: 'images',
key: 'images'
title: '生产厂家',
dataIndex: 'accessoryName',
key: 'accessoryName'
},
{
title: '定位',
dataIndex: 'longitude',
key: 'longitude'
title: '配件分类',
dataIndex: 'accessoryCategory',
key: 'accessoryCategory'
},
{
title: '备注说明',
title: '适用设备型号',
dataIndex: 'accessoryModel',
key: 'accessoryModel'
},
{
title: '配件规格',
dataIndex: 'accessorySpecs',
key: 'accessorySpecs'
},
{
title: '保养内容',
dataIndex: 'comments',
key: 'comments'
},
{
title: '完成状态',
title: '状态',
dataIndex: 'status',
key: 'status',
width: 180
},
{
title: '保养人',
dataIndex: 'userId',
key: 'userId',
width: 180
},
{
title: '创建时间',
dataIndex: 'createTime',

View File

@@ -1,7 +1,7 @@
<!-- 编辑弹窗 -->
<template xmlns="">
<ele-modal
:width="500"
:width="1000"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改保养计划' : '新建保养计划'"
@@ -22,7 +22,7 @@
<a-col
v-bind="styleResponsive ? { md: 22, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="项目名称" name="name">
<a-form-item label="项目名称" name="projectName">
<ProjectSelectModel
:placeholder="`请选择项目`"
v-model:value="form.projectName"
@@ -36,6 +36,31 @@
v-model:value="form.address"
/>
</a-form-item>
<a-form-item label="现场图片" name="files">
<ele-image-upload
v-model:value="files"
:item-style="{ width: '90px', height: '90px' }"
:limit="20"
:upload-handler="uploadHandler"
@upload="onUpload"
/>
</a-form-item>
<a-form-item label="备注说明" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入备注说明"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">正常</a-radio>
<a-radio :value="1">待修</a-radio>
<a-radio :value="2">异常已修</a-radio>
<a-radio :value="3">异常未修</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
</a-row>
</a-form>
@@ -52,6 +77,8 @@
import type { Security } from '@/api/tower/security/model';
import { addSecurity, updateSecurity } from '@/api/tower/security';
import { Project } from '@/api/tower/project/model';
import type { ItemType } from "ele-admin-pro/es/ele-image-upload/types";
import { uploadFile } from "@/api/system/file";
// 是否开启响应式布局
const themeStore = useThemeStore();
@@ -74,6 +101,8 @@
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 已上传数据, 可赋初始值用于回显
const files = ref<ItemType[]>([]);
// 表单数据
const { form, resetFields, assignFields } = useFormData<Security>({
@@ -83,12 +112,14 @@
securityCode: undefined,
address: '',
status: 0,
sortNumber: 100
files: '',
sortNumber: 100,
comments: ''
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
name: [
projectName: [
{
required: true,
message: '请输入设备名称',
@@ -122,6 +153,41 @@
]
});
/* 上传事件 */
const uploadHandler = (file: File) => {
const item: ItemType = {
file,
uid: (file as any).uid,
name: file.name
};
if (!file.type.startsWith('image')) {
message.error('只能选择图片');
return;
}
if (file.size / 1024 / 1024 > 2) {
message.error('大小不能超过 2MB');
return;
}
onUpload(item);
};
// 上传文件
const onUpload = (d: ItemType) => {
uploadFile(<File>d.file)
.then((result) => {
files.value.push({
uid: result.id,
url: result.url,
status: "done"
})
message.success('上传成功');
})
.catch((e) => {
message.error(e.message);
});
};
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
@@ -132,7 +198,8 @@
.then(() => {
loading.value = true;
const categoryForm = {
...form
...form,
files: JSON.stringify(files.value)
};
const saveOrUpdate = isUpdate.value ? updateSecurity : addSecurity;
saveOrUpdate(categoryForm)
@@ -170,6 +237,18 @@
assignFields({
...props.data
});
files.value = [];
if (props.data.files) {
const arr = JSON.parse(props.data.files);
arr.map((d, i) => {
files.value.push({
uid: d.uid,
url: d.url,
status: 'done'
});
});
}
isUpdate.value = true;
} else {
isUpdate.value = false;

View File

@@ -43,6 +43,19 @@
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'userId'">
{{ `${record.nickname ? record.nickname : ''}` }}
</template>
<template v-if="column.key === 'files'">
<a-image-preview-group v-if="record.files">
<a-image
:width="70"
v-for="(item, index) in JSON.parse(record.files)"
:key="index"
:src="item.url"
/>
</a-image-preview-group>
</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>
@@ -117,7 +130,7 @@
key: 'projectName'
},
{
title: '保养编号',
title: '检查编号',
dataIndex: 'securityCode',
key: 'securityCode'
},
@@ -128,11 +141,28 @@
showSorterTooltip: false,
ellipsis: true
},
{
title: '现场图片',
dataIndex: 'files',
width: 300,
key: 'files'
},
{
title: '操作人',
dataIndex: 'userId',
key: 'userId',
width: 120,
align: 'center',
showSorterTooltip: false,
ellipsis: true
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 180
width: 120,
align: 'center'
},
{
title: '生成时间',

View File

@@ -129,7 +129,7 @@
key: 'projectName'
},
{
title: '保养编号',
title: '应急编号',
dataIndex: 'securityCode',
key: 'securityCode'
},