fix: 修改设备新增

This commit is contained in:
100011797 2023-03-06 11:19:11 +08:00
parent 21e45c060d
commit 66234bdfd4
10 changed files with 151 additions and 93 deletions

View File

@ -28,5 +28,4 @@ const props = defineProps({
*/ */
statusNames: { type: Object }, statusNames: { type: Object },
}); });
</script> </script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="upload-image-warp"> <div class="upload-image-warp">
<div class="upload-image-border"> <div class="upload-image-border">
<a-upload <j-upload
name="file" name="file"
list-type="picture-card" list-type="picture-card"
class="avatar-uploader" class="avatar-uploader"
@ -45,7 +45,7 @@
/> />
</template> </template>
</div> </div>
</a-upload> </j-upload>
<div class="upload-loading-mask" v-if="props.disabled"></div> <div class="upload-loading-mask" v-if="props.disabled"></div>
<div class="upload-loading-mask" v-if="imageUrl && loading"> <div class="upload-loading-mask" v-if="imageUrl && loading">
<AIcon type="LoadingOutlined" style="font-size: 20px" /> <AIcon type="LoadingOutlined" style="font-size: 20px" />

View File

@ -8,7 +8,7 @@ import CardBox from './CardBox/index.vue';
// import Search from './Search' // import Search from './Search'
import NormalUpload from './NormalUpload/index.vue' import NormalUpload from './NormalUpload/index.vue'
import FileFormat from './FileFormat/index.vue' import FileFormat from './FileFormat/index.vue'
// import JUpload from './JUpload/index.vue' import JProUpload from './JUpload/index.vue'
import { BasicLayoutPage, BlankLayoutPage } from './Layout' import { BasicLayoutPage, BlankLayoutPage } from './Layout'
import { PageContainer } from 'jetlinks-ui-components/es/components' import { PageContainer } from 'jetlinks-ui-components/es/components'
import Ellipsis from './Ellipsis/index.vue' import Ellipsis from './Ellipsis/index.vue'
@ -27,7 +27,7 @@ export default {
// .component('Search', Search) // .component('Search', Search)
.component('NormalUpload', NormalUpload) .component('NormalUpload', NormalUpload)
.component('FileFormat', FileFormat) .component('FileFormat', FileFormat)
// .component('JUpload', JUpload) .component('JProUpload', JProUpload)
.component('BasicLayoutPage', BasicLayoutPage) .component('BasicLayoutPage', BasicLayoutPage)
.component('BlankLayoutPage', BlankLayoutPage) .component('BlankLayoutPage', BlankLayoutPage)
.component('PageContainer', PageContainer) .component('PageContainer', PageContainer)

View File

@ -1,5 +1,12 @@
<template> <template>
<a-modal :maskClosable="false" width="800px" :visible="true" title="导出" @ok="handleOk" @cancel="handleCancel"> <j-modal
:maskClosable="false"
width="800px"
:visible="true"
title="导出"
@ok="handleOk"
@cancel="handleCancel"
>
<div style="background-color: rgb(236, 237, 238)"> <div style="background-color: rgb(236, 237, 238)">
<p style="padding: 10px"> <p style="padding: 10px">
<AIcon type="ExclamationCircleOutlined" /> <AIcon type="ExclamationCircleOutlined" />
@ -7,63 +14,86 @@
</p> </p>
</div> </div>
<div style="margin-top: 20px"> <div style="margin-top: 20px">
<a-form :layout="'vertical'"> <j-form :layout="'vertical'">
<a-form-item label="产品"> <j-form-item label="产品">
<a-select showSearch v-model:value="modelRef.product" placeholder="请选择产品"> <j-select
<a-select-option :value="item.id" v-for="item in productList" :key="item.id" :title="item.name"></a-select-option> show-search
</a-select> :filter-option="filterOption"
</a-form-item> v-model:value="modelRef.product"
<a-form-item label="文件格式"> placeholder="请选择产品"
<a-radio-group button-style="solid" v-model:value="modelRef.fileType" placeholder="请选择文件格式"> allowClear
<a-radio-button value="xlsx">xlsx</a-radio-button> >
<a-radio-button value="csv">csv</a-radio-button> <j-select-option
</a-radio-group> :value="item.id"
</a-form-item> v-for="item in productList"
</a-form> :key="item.id"
:label="item.name"
>{{ item.name }}</j-select-option
>
</j-select>
</j-form-item>
<j-form-item label="文件格式">
<j-radio-group
button-style="solid"
v-model:value="modelRef.fileType"
placeholder="请选择文件格式"
>
<j-radio-button value="xlsx">xlsx</j-radio-button>
<j-radio-button value="csv">csv</j-radio-button>
</j-radio-group>
</j-form-item>
</j-form>
</div> </div>
</a-modal> </j-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { queryNoPagingPost } from '@/api/device/product' import { queryNoPagingPost } from '@/api/device/product';
import { downloadFile } from '@/utils/utils' import { downloadFile } from '@/utils/utils';
import encodeQuery from '@/utils/encodeQuery' import encodeQuery from '@/utils/encodeQuery';
import { BASE_API_PATH } from '@/utils/variable' import { BASE_API_PATH } from '@/utils/variable';
import { deviceExport } from '@/api/device/instance' import { deviceExport } from '@/api/device/instance';
const emit = defineEmits(['close']) const emit = defineEmits(['close']);
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default: undefined default: undefined,
} },
}) });
const modelRef = reactive({ const modelRef = reactive({
product: undefined, product: undefined,
fileType: 'xlsx' fileType: 'xlsx',
}); });
const productList = ref<Record<string, any>[]>([]) const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const productList = ref<Record<string, any>[]>([]);
watch( watch(
() => props.data, () => props.data,
() => { () => {
queryNoPagingPost({paging: false}).then(resp => { queryNoPagingPost({ paging: false }).then((resp) => {
if(resp.status === 200){ if (resp.status === 200) {
productList.value = resp.result as Record<string, any>[] productList.value = resp.result as Record<string, any>[];
} }
}) });
}, },
{immediate: true, deep: true} { immediate: true, deep: true },
) );
const handleOk = () => { const handleOk = () => {
const params = encodeQuery(props.data); const params = encodeQuery(props.data);
downloadFile(deviceExport(modelRef.product || "", modelRef.fileType),params); downloadFile(
emit('close') deviceExport(modelRef.product || '', modelRef.fileType),
} params,
);
emit('close');
};
const handleCancel = () => { const handleCancel = () => {
emit('close') emit('close');
} };
</script> </script>

View File

@ -1,36 +1,35 @@
<template> <template>
<a-modal :maskClosable="false" width="800px" :visible="true" title="导入" @ok="handleCancel" @cancel="handleCancel"> <j-modal :maskClosable="false" width="800px" :visible="true" title="导入" @ok="handleSave" @cancel="handleCancel">
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<a-form :layout="'vertical'"> <j-form :layout="'vertical'">
<a-row> <j-row>
<a-col span="24"> <j-col span="24">
<a-form-item label="产品" required> <j-form-item label="产品" required>
<a-select showSearch v-model:value="modelRef.product" placeholder="请选择产品"> <j-select showSearch v-model:value="modelRef.product" placeholder="请选择产品">
<a-select-option :value="item.id" v-for="item in productList" :key="item.id" :title="item.name"></a-select-option> <j-select-option :value="item.id" v-for="item in productList" :key="item.id" :label="item.name">{{ item.name }}</j-select-option>
</a-select> </j-select>
</a-form-item> </j-form-item>
</a-col> </j-col>
<a-col span="24"> <j-col span="24">
<a-form-item label="文件格式" v-if="modelRef.product"> <j-form-item label="文件格式" v-if="modelRef.product">
<FileFormat v-model="modelRef.file" /> <FileFormat v-model="modelRef.file" />
</a-form-item> </j-form-item>
</a-col> </j-col>
<a-col span="12"> <j-col span="12">
<a-form-item label="文件上传" v-if="modelRef.product"> <j-form-item label="文件上传" v-if="modelRef.product">
<NormalUpload :product="modelRef.product" v-model="modelRef.upload" :file="modelRef.file" /> <NormalUpload :product="modelRef.product" v-model="modelRef.upload" :file="modelRef.file" />
</a-form-item> </j-form-item>
</a-col> </j-col>
</a-row> </j-row>
</a-form> </j-form>
</div> </div>
</a-modal> </j-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { queryNoPagingPost } from '@/api/device/product' import { queryNoPagingPost } from '@/api/device/product'
import { Form } from 'ant-design-vue';
const emit = defineEmits(['close']) const emit = defineEmits(['close', 'save'])
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
@ -38,7 +37,6 @@ const props = defineProps({
} }
}) })
const productList = ref<Record<string, any>[]>([]) const productList = ref<Record<string, any>[]>([])
const useForm = Form.useForm;
const modelRef = reactive({ const modelRef = reactive({
product: undefined, product: undefined,
@ -64,4 +62,8 @@ watch(
const handleCancel = () => { const handleCancel = () => {
emit('close') emit('close')
} }
const handleSave = () => {
emit('close')
}
</script> </script>

View File

@ -18,7 +18,7 @@
<j-row type="flex"> <j-row type="flex">
<j-col flex="180px"> <j-col flex="180px">
<j-form-item name="photoUrl"> <j-form-item name="photoUrl">
<JUpload v-model="modelRef.photoUrl" /> <JProUpload v-model="modelRef.photoUrl" />
</j-form-item> </j-form-item>
</j-col> </j-col>
<j-col flex="auto"> <j-col flex="auto">
@ -60,15 +60,14 @@
<j-select <j-select
showSearch showSearch
v-model:value="modelRef.productId" v-model:value="modelRef.productId"
placeholder="请选择所属产品" :disabled="!!data?.id"
:filter-option="filterOption" placeholder="请选择状态为“正常”的产品"
> >
<j-select-option <j-select-option
:value="item.id" :value="item.id"
v-for="item in productList" v-for="item in productList"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:disabled="!!data?.id"
>{{item.name}}</j-select-option> >{{item.name}}</j-select-option>
</j-select> </j-select>
</j-form-item> </j-form-item>
@ -105,16 +104,12 @@ const formRef = ref();
const modelRef = reactive({ const modelRef = reactive({
productId: undefined, productId: undefined,
id: '', id: undefined,
name: '', name: '',
describe: '', describe: '',
photoUrl: getImage('/device/instance/device-card.png'), photoUrl: getImage('/device/instance/device-card.png'),
}); });
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const vailId = async (_: Record<string, any>, value: string) => { const vailId = async (_: Record<string, any>, value: string) => {
if (!props?.data?.id && value) { if (!props?.data?.id && value) {
const resp = await isExists(value); const resp = await isExists(value);
@ -202,10 +197,15 @@ const handleCancel = () => {
const handleSave = () => { const handleSave = () => {
formRef.value formRef.value
.validate() .validate()
.then(async () => { .then(async (_data: any) => {
loading.value = true; loading.value = true;
const resp = await update(toRaw(modelRef)); const obj = {...toRaw(modelRef), ..._data}
if(!obj.id){
delete obj.id
}
const resp = await update(obj).finally(() => {
loading.value = false; loading.value = false;
})
if (resp.status === 200) { if (resp.status === 200) {
message.success('操作成功!'); message.success('操作成功!');
emit('save'); emit('save');

View File

@ -229,7 +229,7 @@
</template> </template>
</JProTable> </JProTable>
</page-container> </page-container>
<Import v-if="importVisible" @close="importVisible = false" /> <Import v-if="importVisible" @close="importVisible = false" @save="onRefresh" />
<Export <Export
v-if="exportVisible" v-if="exportVisible"
@close="exportVisible = false" @close="exportVisible = false"
@ -259,7 +259,6 @@ import {
batchDeployDevice, batchDeployDevice,
batchDeleteDevice, batchDeleteDevice,
} from '@/api/device/instance'; } from '@/api/device/instance';
// import type { ActionsType } from '@/components/Table/index.vue';
import { getImage, LocalStore } from '@/utils/comm'; import { getImage, LocalStore } from '@/utils/comm';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import Import from './Import/index.vue'; import Import from './Import/index.vue';
@ -275,6 +274,7 @@ import {
} from '@/api/device/product'; } from '@/api/device/product';
import { queryTree } from '@/api/device/category'; import { queryTree } from '@/api/device/category';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { ActionsType } from './typings';
const router = useRouter(); const router = useRouter();
const instanceRef = ref<Record<string, any>>({}); const instanceRef = ref<Record<string, any>>({});
@ -696,4 +696,8 @@ const saveBtn = () => {
const handleSearch = (_params: any) => { const handleSearch = (_params: any) => {
params.value = _params; params.value = _params;
}; };
const onRefresh = () => {
instanceRef.value?.reload();
}
</script> </script>

View File

@ -84,3 +84,16 @@ type InstanceModel = {
active?: string; // 当前编辑的Card active?: string; // 当前编辑的Card
selectedRows: Map<string, any>; selectedRows: Map<string, any>;
} }
export interface ActionsType {
key: string;
text?: string;
disabled?: boolean;
permission?: boolean;
onClick?: (data: any) => void;
style?: CSSProperties;
tooltip?: TooltipProps;
popConfirm?: PopconfirmProps;
icon?: string;
children?: ActionsType[];
}

View File

@ -1,6 +1,6 @@
<template> <template>
<page-container> <page-container>
<Search :columns="columns" target="scene" @search="handleSearch" /> <j-advanced-search :columns="columns" target="scene" @search="handleSearch" />
<JProTable <JProTable
ref="sceneRef" ref="sceneRef"
:columns="columns" :columns="columns"
@ -23,7 +23,6 @@
<template #card="slotProps"> <template #card="slotProps">
<SceneCard <SceneCard
:value="slotProps" :value="slotProps"
@click="handleClick"
:actions="getActions(slotProps, 'card')" :actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value" :status="slotProps.state?.value"
:statusText="slotProps.state?.text" :statusText="slotProps.state?.text"
@ -50,7 +49,7 @@
<Ellipsis style="width: calc(100% - 100px)"> <Ellipsis style="width: calc(100% - 100px)">
<span <span
style="font-size: 16px; font-weight: 600" style="font-size: 16px; font-weight: 600"
@click.stop="handleView(slotProps.id)" @click.stop="handleView(slotProps.id, slotProps.triggerType)"
> >
{{ slotProps.name }} {{ slotProps.name }}
</span> </span>
@ -126,7 +125,7 @@
import SaveModal from './Save/save.vue'; import SaveModal from './Save/save.vue';
import type { SceneItem } from './typings'; import type { SceneItem } from './typings';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';
import { query, _delete, _action } from '@/api/rule-engine/scene'; import { query, _delete, _action, _execute } from '@/api/rule-engine/scene';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import type { ActionsType } from '@/components/Table'; import type { ActionsType } from '@/components/Table';
import { getImage } from '@/utils/comm'; import { getImage } from '@/utils/comm';
@ -180,10 +179,12 @@ const columns = [
scopedSlots: true, scopedSlots: true,
search: { search: {
type: 'select', type: 'select',
options: Array.from(typeMap).map((item) => ({ options: Array.from(typeMap).map((item) => {
label: item[1], return {
label: item[1]?.text,
value: item[0], value: item[0],
})), }
}),
}, },
}, },
{ {
@ -305,9 +306,18 @@ const getActions = (
: '未启用,不能手动触发', : '未启用,不能手动触发',
}, },
icon: 'LikeOutlined', icon: 'LikeOutlined',
onClick: () => { popConfirm: {
// handleView(data.id, data.triggerType); title: '',
}, onConfirm: async () => {
const resp = await _execute(data.id)
if (resp.status === 200) {
message.success('操作成功!');
sceneRef.value?.reload();
} else {
message.error('操作失败!');
}
}
}
}; };
actions.splice(1, 0, _item); actions.splice(1, 0, _item);
} }

View File

@ -3903,8 +3903,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.4: jetlinks-ui-components@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.4.tgz#38f2abbb6c686ce1e1d7c08a318a6c2f50267adc" resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.4.tgz#31f6879f83d394ba45bfd6e94ce0b20de817d490"
integrity sha512-bpmSoKVpdgZ2FUxIBaqBpewt2T9g1tTf4tECam9uTdww6SDxyvLzWmeKIUfVIwp2Ts7uKpHPFsCtI8fPmZuRjw== integrity sha512-5X26+GsqsduCUSmlaYOAw/MDwKRsZFnifzzRqHcm5qbCi0KrrkID9aKatsMRaeTVEEca1/nzPaPGgXAo6bEpfQ==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"