设备管理-设备清单-批次的设备清单-新增区域维度功能调整:展示机构+批次下所有护理单元的护理单元信息、已配置基础服务、设备信息数量
This commit is contained in:
parent
5d2efa1512
commit
a44a8a0331
|
|
@ -0,0 +1,234 @@
|
|||
<template>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<JFormContainer :disabled="disabled">
|
||||
<template #detail>
|
||||
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="选择区域" v-bind="validateInfos.nuId" id="nuPreviewForm-nuId" name="nuId">
|
||||
<a-select ref="select" :disabled="isUpdate"
|
||||
placeholder="请选择区域"
|
||||
v-model:value="formData.nuId">
|
||||
<a-select-option :value="item.nuId" v-for="item in nuInfos" :key="item.nuId">{{item.nuName}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="选择设备" v-bind="validateInfos.deviceName" id="nuPreviewForm-deviceName" name="deviceName">
|
||||
<a-select ref="select" :disabled="isUpdate"
|
||||
placeholder="请选择设备"
|
||||
v-model:value="formData.deviceName" @change="handleChange">
|
||||
<a-select-option :value="item.deviceName" v-for="item in deviceConfigs" :key="item.id">{{item.deviceName}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="设备类型" v-bind="validateInfos.deviceType" id="nuPreviewForm-deviceType" name="deviceType">
|
||||
<j-dict-select-tag v-model:value="formData.deviceType" dictCode="tplink_device_type" disabled allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="规格型号" v-bind="validateInfos.deviceModel" id="departPreviewForm-deviceModel" name="deviceModel">
|
||||
<a-input v-model:value="formData.deviceModel" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="生产厂家" v-bind="validateInfos.factory" id="nuPreviewForm-factory" name="factory">
|
||||
<a-input v-model:value="formData.factory" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="设备维度" v-bind="validateInfos.dimension" id="nuPreviewForm-dimension" name="dimension">
|
||||
<a-input v-model:value="formData.dimension" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="采购数量" v-bind="validateInfos.purchaseQuantity" id="nuPreviewForm-purchaseQuantity" name="purchaseQuantity">
|
||||
<a-input-number v-model:value="formData.purchaseQuantity" style="width: 100%"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</template>
|
||||
</JFormContainer>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted, unref} from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getValueType } from '/@/utils';
|
||||
import { nuList,configList,savePreview } from './preview.api';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
const isUpdate = ref<boolean>(false);
|
||||
const orgCode = ref<any>('');
|
||||
const batchNo = ref<any>('');
|
||||
const deviceConfigs = ref([]);
|
||||
const nuInfos = ref([]);
|
||||
const props = defineProps({
|
||||
formDisabled: { type: Boolean, default: false },
|
||||
formData: { type: Object, default: ()=>{} },
|
||||
formBpm: { type: Boolean, default: true }
|
||||
});
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const emit = defineEmits(['register', 'ok']);
|
||||
const formData = reactive<Record<string, any>>({
|
||||
id: undefined,
|
||||
orgCode: undefined,
|
||||
nuId: undefined,
|
||||
batchNo: undefined,
|
||||
deviceName: undefined,
|
||||
deviceType: undefined,
|
||||
deviceModel: undefined,
|
||||
factory: undefined,
|
||||
dimension: "区域维度",
|
||||
purchaseQuantity: undefined
|
||||
});
|
||||
const { createMessage } = useMessage();
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
//表单验证
|
||||
const validatorRules = {
|
||||
nuId: [{ required: true, message: '请选择区域!'},],
|
||||
deviceName: [{ required: true, message: '请选择设备!'},],
|
||||
purchaseQuantity: [{ required: true, message: '请输入采购数量!'},],
|
||||
};
|
||||
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
|
||||
|
||||
// 表单禁用
|
||||
const disabled = computed(()=>{
|
||||
if(props.formBpm === true){
|
||||
if(props.formData.disabled === false){
|
||||
return false;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return props.formDisabled;
|
||||
});
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
async function add(record) {
|
||||
getNuInfos(record);
|
||||
getDeviceConfig();
|
||||
orgCode.value = record.orgCode;
|
||||
batchNo.value = record.batchNo;
|
||||
formData.orgCode = record.orgCode;
|
||||
formData.batchNo = record.batchNo;
|
||||
isUpdate.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
async function edit(record) {
|
||||
getNuInfos(record);
|
||||
getDeviceConfig();
|
||||
orgCode.value = record.orgCode;
|
||||
batchNo.value = record.batchNo;
|
||||
isUpdate.value = true;
|
||||
nextTick(() => {
|
||||
resetFields();
|
||||
//赋值
|
||||
const tmpData = {};
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if(record.hasOwnProperty(key)){
|
||||
tmpData[key] = record[key]
|
||||
}
|
||||
})
|
||||
//赋值
|
||||
Object.assign(formData, tmpData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交数据
|
||||
*/
|
||||
async function submitForm() {
|
||||
try {
|
||||
// 触发表单验证
|
||||
await validate();
|
||||
} catch ({ errorFields }) {
|
||||
if (errorFields) {
|
||||
const firstField = errorFields[0];
|
||||
if (firstField) {
|
||||
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
return Promise.reject(errorFields);
|
||||
}
|
||||
confirmLoading.value = true;
|
||||
//时间格式化
|
||||
let model = formData;
|
||||
|
||||
//循环数据
|
||||
for (let data in model) {
|
||||
//如果该数据是数组并且是字符串类型
|
||||
if (model[data] instanceof Array) {
|
||||
let valueType = getValueType(formRef.value.getProps, data);
|
||||
//如果是字符串类型的需要变成以逗号分割的字符串
|
||||
if (valueType === 'string') {
|
||||
model[data] = model[data].join(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
let isUpdateVal = unref(isUpdate);
|
||||
await savePreview(model,isUpdateVal)
|
||||
.then((res) => {
|
||||
emit('ok');
|
||||
})
|
||||
.finally(() => {
|
||||
confirmLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceConfig(){
|
||||
let params = {'dimension': '区域维度'};
|
||||
configList(params)
|
||||
.then((res) => {
|
||||
deviceConfigs.value = res;
|
||||
}).catch(() =>{})
|
||||
.finally(() => {
|
||||
});
|
||||
}
|
||||
|
||||
function handleChange(key,record) {
|
||||
let vo = deviceConfigs.value.filter(item => item.id == record.key);
|
||||
formData.deviceType = vo[0]["deviceType"];
|
||||
formData.deviceModel = vo[0]["deviceModel"];
|
||||
formData.factory = vo[0]["factory"];
|
||||
}
|
||||
|
||||
async function getNuInfos(record){
|
||||
let params = {'orgCode': record.orgCode };
|
||||
nuInfos.value = await nuList(params);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
add,
|
||||
edit,
|
||||
submitForm,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
|
|
@ -1,93 +1,134 @@
|
|||
<template>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<JFormContainer :disabled="disabled">
|
||||
<template #detail>
|
||||
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="选择区域" v-bind="validateInfos.nuId" id="nuPreviewForm-nuId" name="nuId">
|
||||
<a-select ref="select" :disabled="isUpdate"
|
||||
placeholder="请选择区域"
|
||||
v-model:value="formData.nuId">
|
||||
<a-select-option :value="item.nuId" v-for="item in nuInfos" :key="item.nuId">{{item.nuName}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="选择设备" v-bind="validateInfos.deviceName" id="nuPreviewForm-deviceName" name="deviceName">
|
||||
<a-select ref="select" :disabled="isUpdate"
|
||||
placeholder="请选择设备"
|
||||
v-model:value="formData.deviceName" @change="handleChange">
|
||||
<a-select-option :value="item.deviceName" v-for="item in deviceConfigs" :key="item.id">{{item.deviceName}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="设备类型" v-bind="validateInfos.deviceType" id="nuPreviewForm-deviceType" name="deviceType">
|
||||
<j-dict-select-tag v-model:value="formData.deviceType" dictCode="tplink_device_type" disabled allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="规格型号" v-bind="validateInfos.deviceModel" id="departPreviewForm-deviceModel" name="deviceModel">
|
||||
<a-input v-model:value="formData.deviceModel" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="生产厂家" v-bind="validateInfos.factory" id="nuPreviewForm-factory" name="factory">
|
||||
<a-input v-model:value="formData.factory" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="设备维度" v-bind="validateInfos.dimension" id="nuPreviewForm-dimension" name="dimension">
|
||||
<a-input v-model:value="formData.dimension" :disabled="true"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="采购数量" v-bind="validateInfos.purchaseQuantity" id="nuPreviewForm-purchaseQuantity" name="purchaseQuantity">
|
||||
<a-input-number v-model:value="formData.purchaseQuantity" style="width: 100%"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</template>
|
||||
</JFormContainer>
|
||||
<a-row style="margin-top: -4px;">
|
||||
<a-col v-for="(item, index) in nuInfos" style="padding:7px 7px;" :key="index" :span="24">
|
||||
<a-card :class="['card-3d', { 'card-collapsed': expandedCard !== item.nuId }]"
|
||||
style="height: auto; min-height: 320px;">
|
||||
<!-- 卡片头部:可点击展开 -->
|
||||
<div class="card-header" @click="expandCard(item.nuId)">
|
||||
<div class="left-area">
|
||||
<div class="left-area">
|
||||
<div class="region-name">名称:{{ item.nuName }}</div>
|
||||
<div class="region-code">NUID:{{ item.nuId }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 展开时显示收起按钮,收起时显示展开图标 -->
|
||||
<div class="expand-icon" v-if="expandedCard === item.nuId">
|
||||
<span>▲ 收起</span>
|
||||
</div>
|
||||
<div class="expand-icon" v-else>
|
||||
<span>▼ 展开</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 卡片内容:只有展开的卡片才显示 -->
|
||||
<div class="card-content" v-if="expandedCard === item.nuId">
|
||||
<!-- 上半部分:左右布局 -->
|
||||
<div class="top-section">
|
||||
<!-- 右侧:其他内容区域 -->
|
||||
<div class="right-area">
|
||||
<div>基础功能:</div>
|
||||
<span v-for="(item2, index) in areaFuncInfo[item.nuId].children" :key="index">
|
||||
<a-checkbox style="margin-top:10px;" checked readonly disabled>{{ item2.nuName }}</a-checkbox>
|
||||
</span>
|
||||
<span v-for="(item2, index) in areaFuncInfo[item.nuId].children" :key="index">
|
||||
<div v-if="item2.children.length > 0">
|
||||
<div style="margin-top: 20px;">{{ item2.nuName }}:</div>
|
||||
<span v-for="(item3, index) in item2.children" :key="index">
|
||||
<a-checkbox style="margin-top:10px;" checked readonly disabled>{{ item3.nuName }}</a-checkbox>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<span v-if="areaFuncInfo[item.nuId].children.length == 0">暂无基础功能</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下半部分:设备列表(无内部滚动) -->
|
||||
<div class="bottom-section">
|
||||
<div class="section-title">设备配置</div>
|
||||
<div class="device-list">
|
||||
<div v-for="(device, dIndex) in deviceConfigs" :key="dIndex" class="device-item">
|
||||
<div class="device-info">
|
||||
<div class="device-name">{{ device.deviceName }}</div>
|
||||
<div class="device-detail">
|
||||
{{ device.factory }}<span v-if="device.factory && device.deviceModel"> | </span>{{
|
||||
device.deviceModel }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="device-quantity">
|
||||
<a-input-number :value="getQuantity(item.nuId, device.id)"
|
||||
@update:value="(val) => setQuantity(item.nuId, device.id, val)" :min="0" :precision="0" :step="1"
|
||||
:disabled="disabled" :placeholder="'请输入数量'" class="quantity-input" />
|
||||
</div>
|
||||
</div>
|
||||
<a-empty v-if="!deviceConfigs.length" description="暂无设备配置" :image-style="{ height: '60px' }" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="24" v-if="nuInfos.length == 0" style="margin-top:50px;">
|
||||
<a-empty description="暂无数据" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted, unref} from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { ref, reactive, defineExpose, nextTick, computed } from 'vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getValueType } from '/@/utils';
|
||||
import { nuList,configList,savePreview } from './preview.api';
|
||||
import { nuList, configList, batchSave, queryQuantityByOrgCode, getNuListByOrgCode } from './preview.api';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
|
||||
// 定义数据类型
|
||||
interface DeviceConfig {
|
||||
id: string;
|
||||
deviceName: string;
|
||||
deviceType: string;
|
||||
deviceModel: string;
|
||||
factory: string;
|
||||
dimension: string;
|
||||
}
|
||||
|
||||
interface NuInfo {
|
||||
nuId: string;
|
||||
nuName: string;
|
||||
}
|
||||
|
||||
interface SavedData {
|
||||
id: string;
|
||||
nuId: string;
|
||||
deviceType: string;
|
||||
purchaseQuantity: number;
|
||||
}
|
||||
|
||||
interface QuantityData {
|
||||
quantity: number;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const isUpdate = ref<boolean>(false);
|
||||
const orgCode = ref<any>('');
|
||||
const batchNo = ref<any>('');
|
||||
const deviceConfigs = ref([]);
|
||||
const nuInfos = ref([]);
|
||||
const orgCode = ref<string>('');
|
||||
const batchNo = ref<string>('');
|
||||
const deviceConfigs = ref<DeviceConfig[]>([]);
|
||||
const nuInfos = ref<NuInfo[]>([]);
|
||||
|
||||
// 当前展开的卡片ID,默认第一个
|
||||
const expandedCard = ref<string>('');
|
||||
|
||||
// 存储每个卡片的采购数量: Map<nuId, Map<deviceId, QuantityData>>
|
||||
const cardQuantities = ref<Map<string, Map<string, QuantityData>>>(new Map());
|
||||
|
||||
const props = defineProps({
|
||||
formDisabled: { type: Boolean, default: false },
|
||||
formData: { type: Object, default: ()=>{} },
|
||||
formData: { type: Object, default: () => ({}) },
|
||||
formBpm: { type: Boolean, default: true }
|
||||
});
|
||||
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const emit = defineEmits(['register', 'ok']);
|
||||
|
||||
const formData = reactive<Record<string, any>>({
|
||||
id: undefined,
|
||||
orgCode: undefined,
|
||||
|
|
@ -100,63 +141,170 @@ const formData = reactive<Record<string, any>>({
|
|||
dimension: "区域维度",
|
||||
purchaseQuantity: undefined
|
||||
});
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
//表单验证
|
||||
const configData = ref<SavedData[]>([]);
|
||||
const areaFuncInfo = ref()
|
||||
|
||||
// 表单验证
|
||||
const validatorRules = {
|
||||
nuId: [{ required: true, message: '请选择区域!'},],
|
||||
deviceName: [{ required: true, message: '请选择设备!'},],
|
||||
purchaseQuantity: [{ required: true, message: '请输入采购数量!'},],
|
||||
nuId: [{ required: true, message: '请选择区域!' }],
|
||||
deviceName: [{ required: true, message: '请选择设备!' }],
|
||||
purchaseQuantity: [{ required: true, message: '请输入采购数量!' }],
|
||||
};
|
||||
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
|
||||
|
||||
const { resetFields, validate } = useForm(formData, validatorRules, { immediate: false });
|
||||
|
||||
// 表单禁用
|
||||
const disabled = computed(()=>{
|
||||
if(props.formBpm === true){
|
||||
if(props.formData.disabled === false){
|
||||
const disabled = computed(() => {
|
||||
if (props.formBpm === true) {
|
||||
if (props.formData.disabled === false) {
|
||||
return false;
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return props.formDisabled;
|
||||
});
|
||||
|
||||
// 展开/收起卡片
|
||||
function expandCard(nuId: string) {
|
||||
// 如果点击的是已经展开的卡片,则收起
|
||||
if (expandedCard.value === nuId) {
|
||||
expandedCard.value = '';
|
||||
return;
|
||||
}
|
||||
// 否则展开当前卡片
|
||||
expandedCard.value = nuId;
|
||||
}
|
||||
|
||||
// 获取指定卡片、指定设备的数量
|
||||
function getQuantity(nuId: string, deviceId: string): number {
|
||||
const nuMap = cardQuantities.value.get(nuId);
|
||||
if (!nuMap) return 0;
|
||||
const data = nuMap.get(deviceId);
|
||||
return data?.quantity ?? 0;
|
||||
}
|
||||
|
||||
// 设置指定卡片、指定设备的数量
|
||||
function setQuantity(nuId: string, deviceId: string, value: number | undefined) {
|
||||
const intValue = Math.max(0, Math.floor(value || 0));
|
||||
|
||||
let nuMap = cardQuantities.value.get(nuId);
|
||||
if (!nuMap) {
|
||||
nuMap = new Map();
|
||||
cardQuantities.value.set(nuId, nuMap);
|
||||
}
|
||||
|
||||
const existing = nuMap.get(deviceId);
|
||||
if (existing) {
|
||||
existing.quantity = intValue;
|
||||
} else {
|
||||
nuMap.set(deviceId, {
|
||||
quantity: intValue,
|
||||
id: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 从已保存配置中填充数量到卡片
|
||||
function fillQuantitiesFromConfig() {
|
||||
if (!configData.value || configData.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先清空现有数据
|
||||
cardQuantities.value.clear();
|
||||
|
||||
// 遍历已保存的数据
|
||||
for (const savedItem of configData.value) {
|
||||
const { nuId, deviceType, purchaseQuantity, id } = savedItem;
|
||||
|
||||
// 通过 deviceType 找到对应的设备
|
||||
const matchedDevice = deviceConfigs.value.find(device => device.deviceType === deviceType);
|
||||
|
||||
if (matchedDevice && nuId) {
|
||||
let nuMap = cardQuantities.value.get(nuId);
|
||||
if (!nuMap) {
|
||||
nuMap = new Map();
|
||||
cardQuantities.value.set(nuId, nuMap);
|
||||
}
|
||||
|
||||
nuMap.set(matchedDevice.id, {
|
||||
quantity: purchaseQuantity || 0,
|
||||
id: id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log("填充后的 cardQuantities:", cardQuantities.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
async function add(record) {
|
||||
getNuInfos(record);
|
||||
getDeviceConfig();
|
||||
async function add(record: any) {
|
||||
await getNuInfos(record);
|
||||
await getDeviceConfig();
|
||||
orgCode.value = record.orgCode;
|
||||
batchNo.value = record.batchNo;
|
||||
formData.orgCode = record.orgCode;
|
||||
formData.batchNo = record.batchNo;
|
||||
isUpdate.value = false;
|
||||
|
||||
// 重置所有卡片的采购数量
|
||||
cardQuantities.value.clear();
|
||||
|
||||
configData.value = await queryQuantityByOrgCodeFunc();
|
||||
console.log("新增 - 已保存数据:", configData.value);
|
||||
|
||||
areaFuncInfo.value = await getNuListByOrgCodeFunc();
|
||||
console.log("🌊 ~ add ~ areaFuncInfo.value:", areaFuncInfo.value);
|
||||
|
||||
// 默认展开第一个卡片
|
||||
if (nuInfos.value.length > 0) {
|
||||
expandedCard.value = nuInfos.value[0].nuId;
|
||||
}
|
||||
|
||||
// 填充已保存的数据到卡片
|
||||
fillQuantitiesFromConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
async function edit(record) {
|
||||
getNuInfos(record);
|
||||
getDeviceConfig();
|
||||
async function edit(record: any) {
|
||||
await getNuInfos(record);
|
||||
await getDeviceConfig();
|
||||
orgCode.value = record.orgCode;
|
||||
batchNo.value = record.batchNo;
|
||||
isUpdate.value = true;
|
||||
nextTick(() => {
|
||||
|
||||
nextTick(async () => {
|
||||
resetFields();
|
||||
//赋值
|
||||
const tmpData = {};
|
||||
// 赋值
|
||||
const tmpData: Record<string, any> = {};
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if(record.hasOwnProperty(key)){
|
||||
tmpData[key] = record[key]
|
||||
if (record.hasOwnProperty(key)) {
|
||||
tmpData[key] = record[key];
|
||||
}
|
||||
})
|
||||
//赋值
|
||||
});
|
||||
Object.assign(formData, tmpData);
|
||||
|
||||
configData.value = await queryQuantityByOrgCodeFunc();
|
||||
console.log("编辑 - 已保存数据:", configData.value);
|
||||
|
||||
areaFuncInfo.value = await getNuListByOrgCodeFunc();
|
||||
console.log("🌊 ~ edit ~ areaFuncInfo.value:", areaFuncInfo.value);
|
||||
|
||||
// 默认展开第一个卡片
|
||||
if (nuInfos.value.length > 0) {
|
||||
expandedCard.value = nuInfos.value[0].nuId;
|
||||
}
|
||||
|
||||
// 填充已保存的数据到卡片
|
||||
fillQuantitiesFromConfig();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -164,63 +312,88 @@ async function edit(record) {
|
|||
* 提交数据
|
||||
*/
|
||||
async function submitForm() {
|
||||
try {
|
||||
// 触发表单验证
|
||||
await validate();
|
||||
} catch ({ errorFields }) {
|
||||
if (errorFields) {
|
||||
const firstField = errorFields[0];
|
||||
if (firstField) {
|
||||
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
return Promise.reject(errorFields);
|
||||
if (!deviceConfigs.value.length) {
|
||||
createMessage.warning('请先加载设备配置');
|
||||
return Promise.reject('无设备配置');
|
||||
}
|
||||
|
||||
confirmLoading.value = true;
|
||||
//时间格式化
|
||||
let model = formData;
|
||||
|
||||
//循环数据
|
||||
for (let data in model) {
|
||||
//如果该数据是数组并且是字符串类型
|
||||
if (model[data] instanceof Array) {
|
||||
let valueType = getValueType(formRef.value.getProps, data);
|
||||
//如果是字符串类型的需要变成以逗号分割的字符串
|
||||
if (valueType === 'string') {
|
||||
model[data] = model[data].join(',');
|
||||
try {
|
||||
// 构建提交数据: nu数量 * device数量 = 所有组合
|
||||
const submitRecords: any[] = [];
|
||||
|
||||
for (const nu of nuInfos.value) {
|
||||
for (const device of deviceConfigs.value) {
|
||||
const nuMap = cardQuantities.value.get(nu.nuId);
|
||||
const quantityData = nuMap?.get(device.id);
|
||||
const quantity = quantityData?.quantity ?? 0;
|
||||
const savedId = quantityData?.id;
|
||||
|
||||
submitRecords.push({
|
||||
id: savedId, // 如果有 id 说明是更新,没有则是新增
|
||||
orgCode: formData.orgCode,
|
||||
batchNo: formData.batchNo,
|
||||
nuId: nu.nuId,
|
||||
deviceName: device.deviceName,
|
||||
deviceType: device.deviceType,
|
||||
deviceModel: device.deviceModel,
|
||||
factory: device.factory,
|
||||
dimension: formData.dimension,
|
||||
purchaseQuantity: quantity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log("提交数据:", submitRecords);
|
||||
console.log("共提交条数:", submitRecords.length);
|
||||
|
||||
await batchSave(submitRecords);
|
||||
|
||||
createMessage.success('提交成功');
|
||||
emit('ok');
|
||||
} catch (error) {
|
||||
createMessage.error('提交失败');
|
||||
console.error(error);
|
||||
return Promise.reject(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
let isUpdateVal = unref(isUpdate);
|
||||
await savePreview(model,isUpdateVal)
|
||||
}
|
||||
|
||||
function getDeviceConfig() {
|
||||
const params = { dimension: '区域维度' };
|
||||
return configList(params)
|
||||
.then((res) => {
|
||||
emit('ok');
|
||||
deviceConfigs.value = res || [];
|
||||
console.log("设备配置:", deviceConfigs.value);
|
||||
})
|
||||
.finally(() => {
|
||||
confirmLoading.value = false;
|
||||
.catch(() => {
|
||||
deviceConfigs.value = [];
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceConfig(){
|
||||
let params = {'dimension': '区域维度'};
|
||||
configList(params)
|
||||
.then((res) => {
|
||||
deviceConfigs.value = res;
|
||||
}).catch(() =>{})
|
||||
.finally(() => {
|
||||
});
|
||||
function handleChange(key: string, record: any) {
|
||||
const vo = deviceConfigs.value.filter(item => item.id === record.key);
|
||||
if (vo.length) {
|
||||
formData.deviceType = vo[0].deviceType;
|
||||
formData.deviceModel = vo[0].deviceModel;
|
||||
formData.factory = vo[0].factory;
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(key,record) {
|
||||
let vo = deviceConfigs.value.filter(item => item.id == record.key);
|
||||
formData.deviceType = vo[0]["deviceType"];
|
||||
formData.deviceModel = vo[0]["deviceModel"];
|
||||
formData.factory = vo[0]["factory"];
|
||||
}
|
||||
|
||||
async function getNuInfos(record){
|
||||
let params = {'orgCode': record.orgCode };
|
||||
async function getNuInfos(record: any) {
|
||||
const params = { orgCode: record.orgCode };
|
||||
nuInfos.value = await nuList(params);
|
||||
console.log("区域信息:", nuInfos.value);
|
||||
}
|
||||
|
||||
async function queryQuantityByOrgCodeFunc() {
|
||||
return await queryQuantityByOrgCode({ batchNo: formData.batchNo, orgCode: formData.orgCode });
|
||||
}
|
||||
|
||||
async function getNuListByOrgCodeFunc() {
|
||||
return await getNuListByOrgCode({ orgCode: formData.orgCode });
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
|
@ -231,4 +404,202 @@ defineExpose({
|
|||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
/* 基础卡片样式 */
|
||||
.card-3d {
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e8eef4;
|
||||
background: white;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 鼠标悬停效果 */
|
||||
.card-3d:hover {
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* 收起状态样式 */
|
||||
.card-collapsed {
|
||||
min-height: auto !important;
|
||||
height: auto !important;
|
||||
|
||||
:deep(.ant-card-body) {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片内容区域 */
|
||||
:deep(.ant-card-body) {
|
||||
padding: 16px 20px;
|
||||
transition: padding 0.3s ease;
|
||||
}
|
||||
|
||||
/* 卡片头部 */
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.card-header .left-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.region-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.region-code {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header:hover .expand-icon {
|
||||
background-color: rgba(24, 144, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 卡片内容容器 */
|
||||
.card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
/* 上半部分 - 左右布局 */
|
||||
.top-section {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.right-area {
|
||||
flex: 3;
|
||||
background: #ffffff;
|
||||
padding: 12px;
|
||||
border-radius: 10px;
|
||||
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
/* 下半部分 - 设备配置(无内部滚动) */
|
||||
.bottom-section {
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1f2f3d;
|
||||
margin-bottom: 12px;
|
||||
padding-left: 4px;
|
||||
border-left: 3px solid #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.device-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.device-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
background: #fafbfc;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f5f8ff;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
}
|
||||
|
||||
.device-info {
|
||||
flex: 1;
|
||||
|
||||
.device-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1f2f3d;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.device-detail {
|
||||
font-size: 12px;
|
||||
color: #8a9aa8;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.device-quantity {
|
||||
margin-left: 16px;
|
||||
|
||||
.quantity-input {
|
||||
width: 130px;
|
||||
|
||||
:deep(.ant-input-number-input) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 768px) {
|
||||
.top-section {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.device-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.device-quantity {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
|
||||
.quantity-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 强制 checkbox 文字显示为黑色 */
|
||||
.right-area {
|
||||
:deep(.ant-checkbox-wrapper),
|
||||
:deep(.ant-checkbox-wrapper-disabled),
|
||||
:deep(.ant-checkbox + span),
|
||||
:deep(.ant-checkbox-disabled + span) {
|
||||
color: rgba(0, 0, 0, 0.88) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -8,6 +8,9 @@ enum Api {
|
|||
savePreview = '/iot/device/manager/savePreview',
|
||||
updatePreview = '/iot/device/manager/updatePreview',
|
||||
deletePreview = '/iot/device/manager/deletePreview',
|
||||
batchSave = '/iot/device/manager/batchSave',
|
||||
queryQuantityByOrgCode = '/iot/device/manager/queryQuantityByOrgCode',
|
||||
getNuListByOrgCode = '/iot/device/manager/getNuListByOrgCode',
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -24,8 +27,17 @@ export const nuList = (params) => defHttp.get({ url: Api.nuList, params });
|
|||
*/
|
||||
export const savePreview = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.updatePreview : Api.savePreview;
|
||||
return defHttp.post({url: url, params});
|
||||
}
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量保存
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export const batchSave = (params) => {
|
||||
return defHttp.post({ url: Api.batchSave, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除
|
||||
|
|
@ -33,4 +45,10 @@ export const savePreview = (params, isUpdate) => {
|
|||
*/
|
||||
export const deletePreview = (params) => defHttp.post({ url: Api.deletePreview, params });
|
||||
|
||||
export const queryQuantityByOrgCode = (params) => {
|
||||
return defHttp.get({ url: Api.queryQuantityByOrgCode, params });
|
||||
};
|
||||
|
||||
export const getNuListByOrgCode = (params) => {
|
||||
return defHttp.get({ url: Api.getNuListByOrgCode, params });
|
||||
};
|
||||
Loading…
Reference in New Issue