设备管理-设备清单-批次的设备清单-新增区域维度功能调整:展示机构+批次下所有护理单元的护理单元信息、已配置基础服务、设备信息数量

This commit is contained in:
1378012178@qq.com 2026-04-24 10:12:25 +08:00
parent 5d2efa1512
commit a44a8a0331
3 changed files with 767 additions and 144 deletions

View File

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

View File

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

View File

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