Merge remote-tracking branch 'origin/dev' into dev-hub

This commit is contained in:
jackhoo_98 2023-03-08 09:27:42 +08:00
commit de603868c4
21 changed files with 163 additions and 107 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

@ -5,7 +5,7 @@
<!-- 工具栏 --> <!-- 工具栏 -->
<div class="player-screen-tool" v-if="showScreen"> <div class="player-screen-tool" v-if="showScreen">
<a-radio-group <a-radio-group
v-model:value="screen" :value="screen"
button-style="solid" button-style="solid"
@change="handleScreenChange" @change="handleScreenChange"
> >
@ -208,9 +208,7 @@ const formData = ref({
// //
const fullscreenRef = ref(null); const fullscreenRef = ref(null);
const { isFullscreen, enter, exit, toggle } = useFullscreen( const { isFullscreen, enter, exit, toggle } = useFullscreen(fullscreenRef);
fullscreenRef.value,
);
/** /**
* 刷新视频 * 刷新视频

View File

@ -30,7 +30,7 @@ const options = reactive({
muted: false, // muted: false, //
webFullScreen: false, webFullScreen: false,
speedRate: ['0.75', '1.0', '1.25', '1.5', '2.0'], // speedRate: ['0.75', '1.0', '1.25', '1.5', '2.0'], //
autoPlay: true, // autoPlay: false, //
loop: false, // loop: false, //
mirror: false, // mirror: false, //
ligthOff: false, // ligthOff: false, //

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}
loading.value = false; if(!obj.id){
delete obj.id
}
const resp = await update(obj).finally(() => {
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

@ -83,4 +83,17 @@ type InstanceModel = {
params: Set<string>; // 处理无限循环Card params: Set<string>; // 处理无限循环Card
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

@ -10,7 +10,7 @@
@cancel="_vis = false" @cancel="_vis = false"
:confirmLoading="loading" :confirmLoading="loading"
> >
<Search <j-advanced-search
type="simple" type="simple"
:columns="columns" :columns="columns"
target="media" target="media"

View File

@ -1,7 +1,7 @@
<!-- 国标级联-通道列表 --> <!-- 国标级联-通道列表 -->
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
type="simple" type="simple"
:columns="columns" :columns="columns"
target="media" target="media"

View File

@ -1,6 +1,6 @@
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
:columns="columns" :columns="columns"
target="media-cascade" target="media-cascade"
@search="handleSearch" @search="handleSearch"

View File

@ -1,7 +1,7 @@
<!-- 视频设备-通道列表 --> <!-- 视频设备-通道列表 -->
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
type="simple" type="simple"
:columns="columns" :columns="columns"
target="product" target="product"

View File

@ -1,6 +1,6 @@
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
:columns="columns" :columns="columns"
target="notice-config" target="notice-config"
@search="handleSearch" @search="handleSearch"

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%"> <a-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%">
<Search <j-search
type="simple" type="simple"
:columns="columns" :columns="columns"
target="product" target="product"

View File

@ -1,6 +1,6 @@
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
:columns="columns" :columns="columns"
target="notice-config" target="notice-config"
@search="handleSearch" @search="handleSearch"

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%"> <a-modal v-model:visible="_vis" title="通知记录" :footer="null" width="70%">
<Search <j-search
type="simple" type="simple"
:columns="columns" :columns="columns"
target="product" target="product"

View File

@ -1,6 +1,6 @@
<template> <template>
<page-container> <page-container>
<Search <j-advanced-search
:columns="columns" :columns="columns"
target="notice-config" target="notice-config"
@search="handleSearch" @search="handleSearch"

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 {
value: item[0], label: item[1]?.text,
})), 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"