fix(iot): 修复 IoT 复评后续对齐问题
- 补齐设备详情子设备、Modbus 操作权限 - 修复属性搜索清空、模拟器空参数、告警处理备注校验 - 修复 HTTP 数据目的 URL 回显、Redis Stream 密码必填 - 优化固件上传读取时机,补充 isEmptyVal 并复用 JSON 参数校验 - 修正场景产品状态字典和 antd ValueInput 图标导入pull/348/head
parent
ab697925cf
commit
d2763dc044
|
|
@ -32,6 +32,7 @@ const props = withDefaults(defineProps<FileUploadProps>(), {
|
|||
multiple: false,
|
||||
api: undefined,
|
||||
resultField: '',
|
||||
returnText: false,
|
||||
showDescription: false,
|
||||
});
|
||||
const emit = defineEmits([
|
||||
|
|
@ -147,9 +148,6 @@ function handleUploadError(error: any) {
|
|||
* @returns 是否允许上传
|
||||
*/
|
||||
async function beforeUpload(file: File) {
|
||||
const fileContent = await file.text();
|
||||
emit('returnText', fileContent);
|
||||
|
||||
// 检查文件数量限制
|
||||
if (fileList.value!.length >= props.maxNumber) {
|
||||
message.error($t('ui.upload.maxNumber', [props.maxNumber]));
|
||||
|
|
@ -176,6 +174,10 @@ async function beforeUpload(file: File) {
|
|||
|
||||
// 只有在验证通过后才增加计数器
|
||||
uploadNumber.value++;
|
||||
if (props.returnText) {
|
||||
const fileContent = await file.text();
|
||||
emit('returnText', fileContent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ const textareaProps = computed(() => {
|
|||
const fileUploadProps = computed(() => {
|
||||
return {
|
||||
...props.fileUploadProps,
|
||||
returnText: true,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export interface FileUploadProps {
|
|||
maxSize?: number; // 文件最大多少MB
|
||||
multiple?: boolean; // 是否支持多选
|
||||
resultField?: string; // support xxx.xxx.xx
|
||||
returnText?: boolean; // 是否返回文件文本内容
|
||||
showDescription?: boolean; // 是否显示下面的描述
|
||||
value?: string | string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,6 @@ function handleProcess(row: AlertRecordApi.AlertRecord) {
|
|||
}),
|
||||
]),
|
||||
async onOk() {
|
||||
if (!processRemark.value) {
|
||||
message.warning('请输入处理原因');
|
||||
throw new Error('请输入处理原因');
|
||||
}
|
||||
const hideLoading = message.loading({
|
||||
content: '正在处理...',
|
||||
duration: 0,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { computed, h, onMounted, ref } from 'vue';
|
|||
import { confirm, useVbenModal } from '@vben/common-ui';
|
||||
import { DICT_TYPE, ModbusFunctionCodeOptions } from '@vben/constants';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getModbusConfig } from '#/api/iot/device/modbus/config';
|
||||
|
|
@ -307,7 +307,16 @@ onMounted(async () => {
|
|||
<!-- 连接配置区域 -->
|
||||
<ConfigDescriptions :data="modbusConfig" class="mb-4">
|
||||
<template #extra>
|
||||
<Button type="primary" @click="handleEditConfig">编辑</Button>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '编辑',
|
||||
type: 'primary',
|
||||
auth: ['iot:device:create'],
|
||||
onClick: handleEditConfig,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</ConfigDescriptions>
|
||||
|
||||
|
|
@ -320,6 +329,7 @@ onMounted(async () => {
|
|||
label: '新增点位',
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['iot:device:create'],
|
||||
onClick: handleAddPoint,
|
||||
},
|
||||
]"
|
||||
|
|
@ -331,12 +341,14 @@ onMounted(async () => {
|
|||
{
|
||||
label: '编辑',
|
||||
type: 'link',
|
||||
auth: ['iot:device:update'],
|
||||
onClick: () => handleEditPoint(row),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
type: 'link',
|
||||
danger: true,
|
||||
auth: ['iot:device:delete'],
|
||||
popConfirm: {
|
||||
title: `确定要删除点位【${row.name}】吗?`,
|
||||
confirm: () => handleDeletePoint(row),
|
||||
|
|
|
|||
|
|
@ -312,13 +312,15 @@ async function handleEventPost(row: ThingModelApi.ThingModel) {
|
|||
const valueStr = formData.value[row.identifier!];
|
||||
let eventValue: any;
|
||||
|
||||
if (valueStr) {
|
||||
try {
|
||||
eventValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
message.error('事件参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (valueStr === undefined || valueStr === null || valueStr === '') {
|
||||
message.warning('请输入事件参数');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
eventValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
message.error('事件参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
|
||||
// 与后端 IotDeviceEventPostReqDTO 对齐 :{ identifier, value, time }
|
||||
|
|
@ -399,21 +401,23 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
|||
const valueStr = formData.value[row.identifier!];
|
||||
let inputParams: any = {};
|
||||
|
||||
if (valueStr) {
|
||||
try {
|
||||
inputParams = JSON.parse(valueStr);
|
||||
} catch {
|
||||
message.error('服务参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof inputParams !== 'object' ||
|
||||
inputParams === null ||
|
||||
Array.isArray(inputParams)
|
||||
) {
|
||||
message.error('服务参数必须是 JSON 对象');
|
||||
return;
|
||||
}
|
||||
if (valueStr === undefined || valueStr === null || valueStr === '') {
|
||||
message.warning('请输入服务参数');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
inputParams = JSON.parse(valueStr);
|
||||
} catch {
|
||||
message.error('服务参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof inputParams !== 'object' ||
|
||||
inputParams === null ||
|
||||
Array.isArray(inputParams)
|
||||
) {
|
||||
message.error('服务参数必须是 JSON 对象');
|
||||
return;
|
||||
}
|
||||
|
||||
// 与后端 IotDeviceServiceInvokeReqDTO 对齐 :{ identifier, inputParams }
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ watch(
|
|||
label: '添加子设备',
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['iot:device:update'],
|
||||
onClick: openAddModal,
|
||||
},
|
||||
{
|
||||
|
|
@ -324,6 +325,7 @@ watch(
|
|||
type: 'primary',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['iot:device:update'],
|
||||
disabled: isEmpty(checkedIds),
|
||||
onClick: handleUnbindBatch,
|
||||
},
|
||||
|
|
@ -342,6 +344,7 @@ watch(
|
|||
label: '解绑',
|
||||
type: 'link',
|
||||
danger: true,
|
||||
auth: ['iot:device:update'],
|
||||
onClick: () => handleUnbind(row),
|
||||
},
|
||||
]"
|
||||
|
|
|
|||
|
|
@ -207,6 +207,13 @@ function handleQuery() {
|
|||
}
|
||||
}
|
||||
|
||||
/** 搜索关键词变化 */
|
||||
function handleKeywordChange(event: Event) {
|
||||
if (!(event.target as HTMLInputElement).value) {
|
||||
handleQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/** 视图切换 */
|
||||
async function handleViewModeChange(mode: 'card' | 'list') {
|
||||
if (viewMode.value === mode) {
|
||||
|
|
@ -281,6 +288,7 @@ onBeforeUnmount(() => {
|
|||
allow-clear
|
||||
placeholder="请输入属性名称、标识符"
|
||||
style="width: 240px"
|
||||
@change="handleKeywordChange"
|
||||
@press-enter="handleQuery"
|
||||
/>
|
||||
<Switch
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
|||
import { deleteOtaFirmware, getOtaFirmwarePage } from '#/api/iot/ota/firmware';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { getProductName, useGridColumns, useGridFormSchema } from './data';
|
||||
import {
|
||||
getProductName,
|
||||
useGridColumns,
|
||||
useGridFormSchema,
|
||||
} from './data';
|
||||
import OtaFirmwareForm from './modules/form.vue';
|
||||
|
||||
const { push } = useRouter();
|
||||
|
|
@ -116,7 +120,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
<!-- 所属产品列:点击跳产品详情 -->
|
||||
<template #productName="{ row }">
|
||||
<a
|
||||
v-if="row.productId"
|
||||
v-if="row.productId && getProductName(row.productId) !== '-'"
|
||||
class="cursor-pointer text-primary hover:underline"
|
||||
@click="handleOpenProductDetail(row.productId)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -21,21 +21,31 @@ const fullUrl = computed(() =>
|
|||
urlPath.value ? urlPrefix.value + urlPath.value : '',
|
||||
);
|
||||
|
||||
function syncUrlFields(url?: string) {
|
||||
if (url?.startsWith('https://')) {
|
||||
urlPrefix.value = 'https://';
|
||||
urlPath.value = url.slice(8);
|
||||
} else if (url?.startsWith('http://')) {
|
||||
urlPrefix.value = 'http://';
|
||||
urlPath.value = url.slice(7);
|
||||
} else {
|
||||
urlPath.value = url ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
watch([urlPrefix, urlPath], () => {
|
||||
config.value.url = fullUrl.value;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => config.value?.url,
|
||||
(url) => syncUrlFields(url),
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (!isEmpty(config.value)) {
|
||||
if (config.value.url?.startsWith('https://')) {
|
||||
urlPrefix.value = 'https://';
|
||||
urlPath.value = config.value.url.slice(8);
|
||||
} else if (config.value.url?.startsWith('http://')) {
|
||||
urlPrefix.value = 'http://';
|
||||
urlPath.value = config.value.url.slice(7);
|
||||
} else {
|
||||
urlPath.value = config.value.url ?? '';
|
||||
}
|
||||
syncUrlFields(config.value.url);
|
||||
return;
|
||||
}
|
||||
config.value = {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,11 @@ onMounted(() => {
|
|||
class="w-full"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item :name="['config', 'password']" label="密码">
|
||||
<Form.Item
|
||||
:name="['config', 'password']"
|
||||
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
|
||||
label="密码"
|
||||
>
|
||||
<Input.Password v-model:value="config.password" placeholder="请输入密码" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
JsonParamsInputTypeEnum,
|
||||
} from '@vben/constants';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { isEmptyVal } from '@vben/utils';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { Button, Input, Popover, Tag } from 'ant-design-vue';
|
||||
|
|
@ -242,10 +243,8 @@ function handleParamsChange() {
|
|||
|
||||
// 必填参数校验
|
||||
for (const param of paramsList.value) {
|
||||
if (
|
||||
param.required &&
|
||||
(!parsed[param.identifier] || parsed[param.identifier] === '')
|
||||
) {
|
||||
const value = parsed[param.identifier];
|
||||
if (param.required && isEmptyVal(value)) {
|
||||
jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.PARAM_REQUIRED_ERROR(
|
||||
param.name,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
IoTDataSpecsDataTypeEnum,
|
||||
IotRuleSceneTriggerConditionParameterOperatorEnum,
|
||||
} from '@vben/constants';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ onMounted(() => {
|
|||
{{ product.productKey }}
|
||||
</div>
|
||||
</div>
|
||||
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
|
||||
<DictTag :type="DICT_TYPE.IOT_PRODUCT_STATUS" :value="product.status" />
|
||||
</div>
|
||||
</Select.Option>
|
||||
</Select>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ const props = withDefaults(defineProps<FileUploadProps>(), {
|
|||
multiple: false,
|
||||
api: undefined,
|
||||
resultField: '',
|
||||
returnText: false,
|
||||
showDescription: false,
|
||||
});
|
||||
const emit = defineEmits([
|
||||
|
|
@ -163,9 +164,6 @@ function handleUploadError(error: any) {
|
|||
*/
|
||||
/* eslint-disable unicorn/no-nested-ternary */
|
||||
async function beforeUpload(file: File) {
|
||||
const fileContent = await file.text();
|
||||
emit('returnText', fileContent);
|
||||
|
||||
// 检查文件数量限制(使用 getValue 获取实际已上传的文件数量)
|
||||
const currentFiles = getValue();
|
||||
const currentCount = Array.isArray(currentFiles)
|
||||
|
|
@ -198,6 +196,10 @@ async function beforeUpload(file: File) {
|
|||
|
||||
// 只有在验证通过后才增加计数器
|
||||
uploadNumber.value++;
|
||||
if (props.returnText) {
|
||||
const fileContent = await file.text();
|
||||
emit('returnText', fileContent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ const textareaProps = computed(() => {
|
|||
const fileUploadProps = computed(() => {
|
||||
return {
|
||||
...props.fileUploadProps,
|
||||
returnText: true,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export interface FileUploadProps {
|
|||
maxSize?: number; // 文件最大多少 MB
|
||||
multiple?: boolean; // 是否支持多选
|
||||
resultField?: string; // support xxx.xxx.xx
|
||||
returnText?: boolean; // 是否返回文件文本内容
|
||||
showDescription?: boolean; // 是否显示下面的描述
|
||||
value?: string | string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,12 +44,6 @@ async function handleProcess(row: AlertRecordApi.AlertRecord) {
|
|||
cancelButtonText: '取消',
|
||||
inputType: 'textarea',
|
||||
inputPlaceholder: '请输入处理原因',
|
||||
inputValidator: (value: string) => {
|
||||
if (!value) {
|
||||
return '请输入处理原因';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
);
|
||||
const loadingInstance = ElLoading.service({ text: '正在处理...' });
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { computed, h, onMounted, ref } from 'vue';
|
|||
import { confirm, useVbenModal } from '@vben/common-ui';
|
||||
import { DICT_TYPE, ModbusFunctionCodeOptions } from '@vben/constants';
|
||||
|
||||
import { ElButton, ElMessage } from 'element-plus';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getModbusConfig } from '#/api/iot/device/modbus/config';
|
||||
|
|
@ -307,7 +307,16 @@ onMounted(async () => {
|
|||
<!-- 连接配置区域 -->
|
||||
<ConfigDescriptions :data="modbusConfig" class="mb-4">
|
||||
<template #extra>
|
||||
<ElButton type="primary" @click="handleEditConfig">编辑</ElButton>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '编辑',
|
||||
type: 'primary',
|
||||
auth: ['iot:device:create'],
|
||||
onClick: handleEditConfig,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</ConfigDescriptions>
|
||||
|
||||
|
|
@ -320,6 +329,7 @@ onMounted(async () => {
|
|||
label: '新增点位',
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['iot:device:create'],
|
||||
onClick: handleAddPoint,
|
||||
},
|
||||
]"
|
||||
|
|
@ -332,12 +342,14 @@ onMounted(async () => {
|
|||
label: '编辑',
|
||||
type: 'primary',
|
||||
link: true,
|
||||
auth: ['iot:device:update'],
|
||||
onClick: () => handleEditPoint(row),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
type: 'danger',
|
||||
link: true,
|
||||
auth: ['iot:device:delete'],
|
||||
popConfirm: {
|
||||
title: `确定要删除点位【${row.name}】吗?`,
|
||||
confirm: () => handleDeletePoint(row),
|
||||
|
|
|
|||
|
|
@ -202,13 +202,15 @@ async function handleEventPost(row: ThingModelApi.ThingModel) {
|
|||
const valueStr = formData.value[row.identifier!];
|
||||
let eventValue: any;
|
||||
|
||||
if (valueStr) {
|
||||
try {
|
||||
eventValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
ElMessage.error('事件参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (valueStr === undefined || valueStr === null || valueStr === '') {
|
||||
ElMessage.warning('请输入事件参数');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
eventValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
ElMessage.error('事件参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
|
||||
// 与后端 IotDeviceEventPostReqDTO 对齐 :{ identifier, value, time }
|
||||
|
|
@ -286,21 +288,23 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
|||
const valueStr = formData.value[row.identifier!];
|
||||
let inputParams: any = {};
|
||||
|
||||
if (valueStr) {
|
||||
try {
|
||||
inputParams = JSON.parse(valueStr);
|
||||
} catch {
|
||||
ElMessage.error('服务参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof inputParams !== 'object' ||
|
||||
inputParams === null ||
|
||||
Array.isArray(inputParams)
|
||||
) {
|
||||
ElMessage.error('服务参数必须是 JSON 对象');
|
||||
return;
|
||||
}
|
||||
if (valueStr === undefined || valueStr === null || valueStr === '') {
|
||||
ElMessage.warning('请输入服务参数');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
inputParams = JSON.parse(valueStr);
|
||||
} catch {
|
||||
ElMessage.error('服务参数格式错误,请输入有效的JSON格式');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof inputParams !== 'object' ||
|
||||
inputParams === null ||
|
||||
Array.isArray(inputParams)
|
||||
) {
|
||||
ElMessage.error('服务参数必须是 JSON 对象');
|
||||
return;
|
||||
}
|
||||
|
||||
// 与后端 IotDeviceServiceInvokeReqDTO 对齐 :{ identifier, inputParams }
|
||||
|
|
|
|||
|
|
@ -315,12 +315,14 @@ watch(
|
|||
label: '添加子设备',
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['iot:device:update'],
|
||||
onClick: openAddModal,
|
||||
},
|
||||
{
|
||||
label: '批量解绑',
|
||||
type: 'danger',
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['iot:device:update'],
|
||||
disabled: isEmpty(checkedIds),
|
||||
onClick: handleUnbindBatch,
|
||||
},
|
||||
|
|
@ -340,6 +342,7 @@ watch(
|
|||
label: '解绑',
|
||||
type: 'danger',
|
||||
link: true,
|
||||
auth: ['iot:device:update'],
|
||||
onClick: () => handleUnbind(row),
|
||||
},
|
||||
]"
|
||||
|
|
|
|||
|
|
@ -282,6 +282,7 @@ onBeforeUnmount(() => {
|
|||
clearable
|
||||
placeholder="请输入属性名称、标识符"
|
||||
style="width: 240px"
|
||||
@clear="handleQuery"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
<ElSwitch
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
|||
import { deleteOtaFirmware, getOtaFirmwarePage } from '#/api/iot/ota/firmware';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { getProductName, useGridColumns, useGridFormSchema } from './data';
|
||||
import {
|
||||
getProductName,
|
||||
useGridColumns,
|
||||
useGridFormSchema,
|
||||
} from './data';
|
||||
import OtaFirmwareForm from './modules/form.vue';
|
||||
|
||||
const { push } = useRouter();
|
||||
|
|
@ -113,7 +117,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
<!-- 所属产品列:点击跳产品详情 -->
|
||||
<template #productName="{ row }">
|
||||
<a
|
||||
v-if="row.productId"
|
||||
v-if="row.productId && getProductName(row.productId) !== '-'"
|
||||
class="cursor-pointer text-[var(--el-color-primary)] hover:underline"
|
||||
@click="handleOpenProductDetail(row.productId)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -21,21 +21,31 @@ const fullUrl = computed(() =>
|
|||
urlPath.value ? urlPrefix.value + urlPath.value : '',
|
||||
);
|
||||
|
||||
function syncUrlFields(url?: string) {
|
||||
if (url?.startsWith('https://')) {
|
||||
urlPrefix.value = 'https://';
|
||||
urlPath.value = url.slice(8);
|
||||
} else if (url?.startsWith('http://')) {
|
||||
urlPrefix.value = 'http://';
|
||||
urlPath.value = url.slice(7);
|
||||
} else {
|
||||
urlPath.value = url ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
watch([urlPrefix, urlPath], () => {
|
||||
config.value.url = fullUrl.value;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => config.value?.url,
|
||||
(url) => syncUrlFields(url),
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (!isEmpty(config.value)) {
|
||||
if (config.value.url?.startsWith('https://')) {
|
||||
urlPrefix.value = 'https://';
|
||||
urlPath.value = config.value.url.slice(8);
|
||||
} else if (config.value.url?.startsWith('http://')) {
|
||||
urlPrefix.value = 'http://';
|
||||
urlPath.value = config.value.url.slice(7);
|
||||
} else {
|
||||
urlPath.value = config.value.url ?? '';
|
||||
}
|
||||
syncUrlFields(config.value.url);
|
||||
return;
|
||||
}
|
||||
config.value = {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,11 @@ onMounted(() => {
|
|||
class="w-full"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="config.password" label="密码">
|
||||
<ElFormItem
|
||||
prop="config.password"
|
||||
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
|
||||
label="密码"
|
||||
>
|
||||
<ElInput
|
||||
v-model="config.password"
|
||||
type="password"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
JsonParamsInputTypeEnum,
|
||||
} from '@vben/constants';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { isEmptyVal } from '@vben/utils';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { ElButton, ElInput, ElPopover, ElTag } from 'element-plus';
|
||||
|
|
@ -242,10 +243,8 @@ function handleParamsChange() {
|
|||
|
||||
// 必填参数校验
|
||||
for (const param of paramsList.value) {
|
||||
if (
|
||||
param.required &&
|
||||
(!parsed[param.identifier] || parsed[param.identifier] === '')
|
||||
) {
|
||||
const value = parsed[param.identifier];
|
||||
if (param.required && isEmptyVal(value)) {
|
||||
jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.PARAM_REQUIRED_ERROR(
|
||||
param.name,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ onMounted(() => {
|
|||
{{ product.productKey }}
|
||||
</div>
|
||||
</div>
|
||||
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
|
||||
<DictTag :type="DICT_TYPE.IOT_PRODUCT_STATUS" :value="product.status" />
|
||||
</div>
|
||||
</ElOption>
|
||||
</ElSelect>
|
||||
|
|
|
|||
Loading…
Reference in New Issue