Merge remote-tracking branch 'origin/dev' into dev
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 776 B |
After Width: | Height: | Size: 710 B |
After Width: | Height: | Size: 697 B |
After Width: | Height: | Size: 544 B |
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 897 B |
|
@ -99,7 +99,7 @@ export const templateDownload = (productId: string, type: string) => server.get(
|
|||
* @param type 文件类型
|
||||
* @returns
|
||||
*/
|
||||
export const deviceImport = (productId: string, fileUrl: string, autoDeploy: boolean) => `${BASE_API_PATH}/device-instance/${productId}/import?fileUrl=${fileUrl}&autoDeploy=${autoDeploy}&:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`
|
||||
export const deviceImport = (productId: string, fileUrl: string, autoDeploy: boolean) => `${BASE_API_PATH}/device-instance/${productId}/import/_withlog?fileUrl=${fileUrl}&autoDeploy=${autoDeploy}&:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`
|
||||
|
||||
/**
|
||||
* 设备导出
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
123
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps({
|
||||
// options:
|
||||
})
|
||||
</script>
|
|
@ -1,14 +1,11 @@
|
|||
<template>
|
||||
<div class="box">
|
||||
<div class="box-item" v-if="data.length > showLength">
|
||||
<div class="box-item" v-if="pageIndex > 0">
|
||||
<j-button
|
||||
@click="onLeft"
|
||||
type="primary"
|
||||
:disabled="!(pageIndex > 0)"
|
||||
shape="circle"
|
||||
class="box-item-action"
|
||||
><AIcon type="LeftOutlined"
|
||||
/></j-button>
|
||||
>+{{ pageIndex * showLength }}</j-button>
|
||||
</div>
|
||||
<div class="box-item" v-for="item in getData" :key="item.id">
|
||||
<slot name="card" v-bind="item"></slot>
|
||||
|
@ -16,15 +13,12 @@
|
|||
<div class="box-item">
|
||||
<slot name="add"></slot>
|
||||
</div>
|
||||
<div class="box-item" v-if="data.length > showLength">
|
||||
<div class="box-item" v-if="(pageIndex + 1) * showLength < data.length">
|
||||
<j-button
|
||||
:disabled="!(pageIndex + showLength < data.length)"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
class="box-item-action"
|
||||
@click="onRight"
|
||||
><AIcon type="RightOutlined"
|
||||
/></j-button>
|
||||
>+{{ data.length - (pageIndex + 1) * showLength }}</j-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -43,15 +37,13 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
// const emit = defineEmits(['add']);
|
||||
|
||||
const pageIndex = ref<number>(0);
|
||||
|
||||
const getData = computed(() => {
|
||||
const start = pageIndex.value >= 0 ? pageIndex.value : 0;
|
||||
const start = pageIndex.value >= 0 ? pageIndex.value * props.showLength : 0;
|
||||
const end =
|
||||
props.showLength + pageIndex.value < props.data.length
|
||||
? props.showLength + pageIndex.value
|
||||
(pageIndex.value + 1) * props.showLength < props.data.length
|
||||
? props.showLength * (pageIndex.value + 1)
|
||||
: props.data.length;
|
||||
return props.data.slice(start, end);
|
||||
});
|
||||
|
@ -69,10 +61,6 @@ const onLeft = () => {
|
|||
pageIndex.value -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// const onAdd = () => {
|
||||
// emit('add');
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
:src="
|
||||
iconMap.get(
|
||||
bindUser?.applicationProvider,
|
||||
) || getImage('/apply/provider1.png')
|
||||
) || getImage('/apply/internal-standalone.png')
|
||||
"
|
||||
/>
|
||||
<p>账号:{{ bindUser?.result?.userId || '-' }}</p>
|
||||
|
@ -153,8 +153,8 @@ interface formData {
|
|||
const iconMap = new Map()
|
||||
iconMap.set('dingtalk-ent-app', getImage('/notice/dingtalk.png'))
|
||||
iconMap.set('wechat-webapp', getImage('/notice/wechat.png'))
|
||||
iconMap.set('internal-standalone', getImage('/apply/provider1.png'))
|
||||
iconMap.set('third-party', getImage('/apply/provider5.png'))
|
||||
iconMap.set('internal-standalone', getImage('/apply/internal-standalone.png'))
|
||||
iconMap.set('third-party', getImage('/apply/third-party.png'))
|
||||
|
||||
const token = computed(() => LocalStore.get(TOKEN_KEY))
|
||||
|
||||
|
|
|
@ -2,27 +2,32 @@
|
|||
<div class="box">
|
||||
<div class="content">
|
||||
<template v-if="bindList.length">
|
||||
<div class="content-item" v-for="item in bindList" :key="item.id">
|
||||
<div
|
||||
class="content-item"
|
||||
v-for="item in bindList"
|
||||
:key="item.id"
|
||||
>
|
||||
<div class="content-item-left">
|
||||
<img
|
||||
:src="item.logoUrl || getImage(bindIcon[item.provider])"
|
||||
style="height: 50px; width: 50px"
|
||||
width="50px"
|
||||
height="50px"
|
||||
:src="
|
||||
item.logoUrl ||
|
||||
getImage(bindIcon[item.provider])
|
||||
"
|
||||
style="height: 24px; width: 24px"
|
||||
alt=""
|
||||
/>
|
||||
<Ellipsis style="max-width: 200px; font-size: 22px">{{
|
||||
<Ellipsis style="max-width: 200px; color: #333; margin: 0 8px 0 6px">{{
|
||||
item?.name
|
||||
}}</Ellipsis>
|
||||
<div>
|
||||
<j-tag v-if="item.bound">已绑定</j-tag>
|
||||
<j-tag v-else>未绑定</j-tag>
|
||||
<span v-if="item.bound" style="color: #2BA245">已绑定</span>
|
||||
<span v-else style="color: #999">未绑定</span>
|
||||
</div>
|
||||
<div v-if="item.others?.name">
|
||||
绑定名:{{ item.others?.name }}
|
||||
<div v-if="item.others?.name" style="color: #666666">
|
||||
{{ item.others?.name }}(已绑定的用户名)
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="content-item-right">
|
||||
<j-popconfirm
|
||||
v-if="item.bound"
|
||||
title="确认解除绑定嘛?"
|
||||
|
@ -30,13 +35,17 @@
|
|||
>
|
||||
<j-button>解除绑定</j-button>
|
||||
</j-popconfirm>
|
||||
<j-button v-else type="primary" @click="clickBind(item.id)"
|
||||
<j-button
|
||||
v-else
|
||||
ghost
|
||||
type="primary"
|
||||
@click="clickBind(item.id)"
|
||||
>立即绑定</j-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<j-empty v-else style="margin: 200px 0;" />
|
||||
<j-empty v-else style="margin: 200px 0" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -51,8 +60,8 @@ const bindList = ref<any[]>([]);
|
|||
const bindIcon = {
|
||||
'dingtalk-ent-app': '/notice/dingtalk.png',
|
||||
'wechat-webapp': '/notice/wechat.png',
|
||||
'internal-standalone': '/apply/provider1.png',
|
||||
'third-party': '/apply/provider5.png',
|
||||
'internal-standalone': '/apply/internal-standalone.png',
|
||||
'third-party': '/apply/third-party.png',
|
||||
};
|
||||
const unBind = (id: string) => {
|
||||
unBind_api(id).then((resp) => {
|
||||
|
@ -93,18 +102,19 @@ onMounted(() => {
|
|||
.box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
.content {
|
||||
margin-top: 24px;
|
||||
width: 80%;
|
||||
|
||||
width: 100%;
|
||||
.content-item {
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
margin-bottom: 16px;
|
||||
padding: 15px;
|
||||
border: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
border-radius: 6px;
|
||||
background: #f7f8fa;
|
||||
|
||||
.content-item-left {
|
||||
display: flex;
|
||||
|
@ -112,6 +122,13 @@ onMounted(() => {
|
|||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content-item-right {
|
||||
button:hover {
|
||||
background-color: @primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,34 +1,31 @@
|
|||
<template>
|
||||
<div class="choose-view">
|
||||
<j-row class="view-content" :gutter="24">
|
||||
<j-col
|
||||
<div class="view-content">
|
||||
<div
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{ selected: currentView === 'device' }"
|
||||
@click="currentView = 'device'"
|
||||
>
|
||||
<img :src="getImage('/home/device.png')" alt="" />
|
||||
</j-col>
|
||||
<j-col
|
||||
<img :src="getImage(`/home/home-view/device${currentView === 'device' ? '-active' : ''}.png`)" alt="" />
|
||||
</div>
|
||||
<div
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{ selected: currentView === 'ops' }"
|
||||
@click="currentView = 'ops'"
|
||||
>
|
||||
<img :src="getImage('/home/ops.png')" alt="" />
|
||||
</j-col>
|
||||
<j-col
|
||||
<img :src="getImage(`/home/home-view/ops${currentView === 'ops' ? '-active' : ''}.png`)" alt="" />
|
||||
</div>
|
||||
<div
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{
|
||||
selected: currentView === 'comprehensive',
|
||||
}"
|
||||
@click="currentView = 'comprehensive'"
|
||||
>
|
||||
<img :src="getImage('/home/comprehensive.png')" alt="" />
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-button type="primary" class="btn" @click="confirm">确定</j-button>
|
||||
<img :src="getImage(`/home/home-view/comprehensive${currentView === 'comprehensive' ? '-active' : ''}.png`)" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<j-button type="primary" @click="confirm">保存修改</j-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -76,28 +73,26 @@ onMounted(() => {
|
|||
<style lang="less" scoped>
|
||||
.choose-view {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
padding: 48px 150px;
|
||||
padding: 4% 9% 0 9%;
|
||||
box-sizing: border-box;
|
||||
.view-content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
.select-item {
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
width: 30%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-color: #10239e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin: 48px auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 68px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,88 +1,81 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<div class="notification-record-container">
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="category"
|
||||
style="padding: 0"
|
||||
@search="queryParams"
|
||||
/>
|
||||
|
||||
<j-pro-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:request="getList_api"
|
||||
model="TABLE"
|
||||
:params="queryParams"
|
||||
:bodyStyle="{ padding: 0 }"
|
||||
:defaultParams="defaultParams"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<j-popconfirm title="确认全部已读?" @confirm="onAllRead">
|
||||
<j-button type="primary">全部已读</j-button>
|
||||
</j-popconfirm>
|
||||
</template>
|
||||
<template #topicProvider="slotProps">
|
||||
{{ slotProps.topicName }}
|
||||
</template>
|
||||
<template #notifyTime="slotProps">
|
||||
{{
|
||||
dayjs(slotProps.notifyTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state.value"
|
||||
:text="slotProps.state.text"
|
||||
:statusNames="{
|
||||
read: 'success',
|
||||
unread: 'error',
|
||||
<div class="notification-record-container">
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
:target="type"
|
||||
style="padding: 0"
|
||||
@search="(e) => (queryParams = e)"
|
||||
/>
|
||||
<j-pro-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:request="getList_api"
|
||||
model="TABLE"
|
||||
:params="queryParams"
|
||||
:bodyStyle="{ padding: 0 }"
|
||||
:defaultParams="defaultParams"
|
||||
>
|
||||
<template #rightExtraRender>
|
||||
<j-popconfirm title="确认全部已读?" @confirm="onAllRead">
|
||||
<j-button type="primary">全部已读</j-button>
|
||||
</j-popconfirm>
|
||||
</template>
|
||||
<template #topicProvider="slotProps">
|
||||
{{ slotProps.topicName }}
|
||||
</template>
|
||||
<template #notifyTime="slotProps">
|
||||
{{ dayjs(slotProps.notifyTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state.value"
|
||||
:text="slotProps.state.text"
|
||||
:statusNames="{
|
||||
read: 'success',
|
||||
unread: 'error',
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<j-space :size="16">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确认标为${
|
||||
slotProps.state.value === 'read'
|
||||
? '未读'
|
||||
: '已读'
|
||||
}`,
|
||||
onConfirm: () => changeStatus(slotProps),
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<j-space :size="16">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确认标为${
|
||||
slotProps.state.value === 'read'
|
||||
? '未读'
|
||||
: '已读'
|
||||
}`,
|
||||
onConfirm: () => changeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{
|
||||
title:
|
||||
slotProps.state.value === 'read'
|
||||
? '标为未读'
|
||||
: '标为已读',
|
||||
}"
|
||||
>
|
||||
<AIcon type="icon-a-PIZHU1" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '查看',
|
||||
}"
|
||||
@click="view(slotProps)"
|
||||
>
|
||||
<AIcon type="SearchOutlined" />
|
||||
</PermissionButton>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-pro-table>
|
||||
<ViewDialog
|
||||
v-if="viewVisible"
|
||||
v-model:visible="viewVisible"
|
||||
:data="viewItem"
|
||||
:type="type"
|
||||
/>
|
||||
</div>
|
||||
</page-container>
|
||||
:tooltip="{
|
||||
title:
|
||||
slotProps.state.value === 'read'
|
||||
? '标为未读'
|
||||
: '标为已读',
|
||||
}"
|
||||
>
|
||||
<AIcon type="icon-a-PIZHU1" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '查看',
|
||||
}"
|
||||
@click="view(slotProps)"
|
||||
>
|
||||
<AIcon type="SearchOutlined" />
|
||||
</PermissionButton>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-pro-table>
|
||||
<ViewDialog
|
||||
v-if="viewVisible"
|
||||
v-model:visible="viewVisible"
|
||||
:data="viewItem"
|
||||
:type="type"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="NotificationRecord">
|
||||
|
@ -91,7 +84,7 @@ import PermissionButton from '@/components/PermissionButton/index.vue';
|
|||
import {
|
||||
getList_api,
|
||||
changeStatus_api,
|
||||
changeAllStatus
|
||||
changeAllStatus,
|
||||
} from '@/api/account/notificationRecord';
|
||||
import dayjs from 'dayjs';
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
|
@ -115,11 +108,11 @@ const getType = computed(() => {
|
|||
return ['system-event'];
|
||||
} else {
|
||||
return [
|
||||
'alarm',
|
||||
'alarm-product',
|
||||
'alarm-device',
|
||||
'alarm-other',
|
||||
'alarm-org',
|
||||
'alarm',
|
||||
];
|
||||
}
|
||||
});
|
||||
|
@ -132,16 +125,18 @@ const columns = [
|
|||
search: {
|
||||
type: 'select',
|
||||
options: () =>
|
||||
getTypeList_api().then((resp: any) =>
|
||||
resp.result
|
||||
getTypeList_api().then((resp: any) => {
|
||||
return resp.result
|
||||
.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))
|
||||
.filter((item: any) =>
|
||||
[...getType.value].includes(item?.value),
|
||||
),
|
||||
),
|
||||
.filter((item: any) => {
|
||||
return [...getType.value].includes(item?.value)
|
||||
}).sort((a: any, b: any) => {
|
||||
return b?.value?.length - a?.value?.length
|
||||
});
|
||||
}),
|
||||
},
|
||||
scopedSlots: true,
|
||||
ellipsis: true,
|
||||
|
@ -240,18 +235,18 @@ const changeStatus = (row: any) => {
|
|||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if(user.messageInfo?.id) {
|
||||
view(user.messageInfo)
|
||||
if (user.messageInfo?.id) {
|
||||
view(user.messageInfo);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const onAllRead = async () => {
|
||||
const resp = await changeAllStatus('_read', getType.value)
|
||||
if(resp.status === 200){
|
||||
onlyMessage('操作成功!')
|
||||
refresh()
|
||||
const resp = await changeAllStatus('_read', getType.value);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (routerParams.params?.value.row) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div style="margin-top: 24px">
|
||||
<div>
|
||||
<j-tabs
|
||||
tab-position="left"
|
||||
v-if="tabs.length"
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<div class="child-item">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
<div style="color: #333333">
|
||||
{{ data?.name }}
|
||||
</div>
|
||||
<div class="child-item-left-auth" v-if="data?.description">
|
||||
<j-tooltip :title="data.description">
|
||||
<AIcon
|
||||
style="font-size: 20px"
|
||||
style="font-size: 16px"
|
||||
type="ExclamationCircleOutlined"
|
||||
/>
|
||||
</j-tooltip>
|
||||
|
@ -19,31 +19,22 @@
|
|||
<div class="box-item">
|
||||
<div class="box-item-img">
|
||||
<j-dropdown placement="top" :trigger="['click']">
|
||||
<!-- :visible="show?.[slotProps?.id]"
|
||||
@visibleChange="onVisibleChange(slotProps)" -->
|
||||
<div>
|
||||
<div
|
||||
:class="{
|
||||
disabled: !notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
),
|
||||
}"
|
||||
>
|
||||
<img
|
||||
:src="
|
||||
iconMap.get(
|
||||
slotProps?.channelProvider,
|
||||
)
|
||||
"
|
||||
style="width: 32px"
|
||||
/>
|
||||
<div
|
||||
:class="{
|
||||
disabled: !notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
),
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
<!-- v-if="
|
||||
notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
) &&
|
||||
slotProps?.channelProvider !==
|
||||
'inside-mail'
|
||||
" -->
|
||||
<template #overlay>
|
||||
<j-menu>
|
||||
<j-menu-item
|
||||
|
@ -97,13 +88,6 @@
|
|||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
<div class="box-item-checked">
|
||||
<j-checkbox
|
||||
:checked="
|
||||
notifyChannels?.includes(slotProps?.id)
|
||||
"
|
||||
></j-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-item-text">
|
||||
{{ slotProps?.name }}
|
||||
|
@ -140,12 +124,12 @@ import { useUserInfo } from '@/store/userInfo';
|
|||
import EditInfo from '../../EditInfo/index.vue';
|
||||
|
||||
const iconMap = new Map();
|
||||
iconMap.set('notifier-dingTalk', getImage('/notice/dingtalk.png'));
|
||||
iconMap.set('notifier-weixin', getImage('/notice/wechat.png'));
|
||||
iconMap.set('notifier-email', getImage('/notice/email.png'));
|
||||
iconMap.set('notifier-voice', getImage('/notice/voice.png'));
|
||||
iconMap.set('notifier-sms', getImage('/notice/sms.png'));
|
||||
iconMap.set('inside-mail', getImage('/notice/inside-mail.png'));
|
||||
iconMap.set('notifier-dingTalk', getImage('/notice-rule/dingtalk.png'));
|
||||
iconMap.set('notifier-weixin', getImage('/notice-rule/wechat.png'));
|
||||
iconMap.set('notifier-email', getImage('/notice-rule/email.png'));
|
||||
iconMap.set('notifier-voice', getImage('/notice-rule/voice.png'));
|
||||
iconMap.set('notifier-sms', getImage('/notice-rule/sms.png'));
|
||||
iconMap.set('inside-mail', getImage('/notice-rule/inside-mail.png'));
|
||||
|
||||
const current = ref<any>({});
|
||||
const visible = ref<boolean>(false);
|
||||
|
@ -272,17 +256,15 @@ const onSave = () => {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0px 1px 0px 0px #E2E2E2;
|
||||
|
||||
.child-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
|
@ -303,40 +285,29 @@ const onSave = () => {
|
|||
.box-item {
|
||||
margin-left: 10px;
|
||||
.box-item-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
width: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.box-item-checked {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background-color: rgba(#000, 0.38);
|
||||
position: absolute;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
filter: grayscale(100%);
|
||||
// filter: brightness(0);
|
||||
// opacity: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<j-spin :spinning="loading">
|
||||
<div style="margin-top: 24px">
|
||||
<div>
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
你可以在该页面选择需要订阅的主题及接收通知的方式。
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<div class="content-collapse">
|
||||
<template v-if="dataSource.length">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey" expand-icon-position="right">
|
||||
<template #expandIcon="{ isActive }">
|
||||
<AIcon
|
||||
type="CaretRightOutlined"
|
||||
|
@ -22,6 +22,7 @@
|
|||
v-for="item in dataSource"
|
||||
:key="item.provider"
|
||||
class="custom"
|
||||
:header="item.name"
|
||||
>
|
||||
<template #header
|
||||
><h3>{{ item.name }}</h3></template
|
||||
|
@ -120,13 +121,19 @@ onMounted(() => {
|
|||
background-color: #f6f6f6;
|
||||
}
|
||||
.custom {
|
||||
background: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
background: #F7F8FA;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
color: #333333;
|
||||
}
|
||||
.child {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.content-collapse {
|
||||
:deep(.ant-collapse-content > .ant-collapse-content-box) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -154,8 +154,8 @@ const saveImage = (url: string) => {
|
|||
<style lang="less" scoped>
|
||||
@border: 1px dashed @border-color-base;
|
||||
@mask-color: rgba(#000, 0.35);
|
||||
@with: 66px;
|
||||
@height: 66px;
|
||||
@with: 96px;
|
||||
@height: 96px;
|
||||
|
||||
.flex-center() {
|
||||
align-items: center;
|
||||
|
|
|
@ -16,73 +16,58 @@
|
|||
</div>
|
||||
<div class="person-header-item-info-right">
|
||||
<div class="person-header-item-info-right-top">
|
||||
<span>{{ _org }}部门 · {{ _role }}角色</span>
|
||||
Hi, {{ user.userInfos?.name }}
|
||||
</div>
|
||||
<div class="person-header-item-info-right-info">
|
||||
<div>用户名 {{ user.userInfos?.username }}</div>
|
||||
<div>账号ID {{ user.userInfos?.id }}</div>
|
||||
<div>
|
||||
<j-tag
|
||||
v-for="i in user.userInfos?.orgList || []"
|
||||
:key="i?.id"
|
||||
>{{ i?.name }}</j-tag
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<j-tag
|
||||
v-for="i in user.userInfos?.roleList || []"
|
||||
:key="i?.id"
|
||||
>{{ i?.name }}</j-tag
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="person-header-item-action">
|
||||
<div class="person-header-item-action-left">
|
||||
<j-space>
|
||||
<j-button
|
||||
@click="onActivated(item.key)"
|
||||
v-for="item in list"
|
||||
:type="
|
||||
user.tabKey === item.key
|
||||
? 'primary'
|
||||
: 'default'
|
||||
"
|
||||
:key="item.key"
|
||||
>{{ item.title }}</j-button
|
||||
>
|
||||
</j-space>
|
||||
</div>
|
||||
<div class="person-header-item-action-right">
|
||||
<j-space :size="24">
|
||||
<j-tooltip title="查看详情"
|
||||
><j-button
|
||||
@click="visible = true"
|
||||
shape="circle"
|
||||
><AIcon
|
||||
style="font-size: 24px"
|
||||
type="FileSearchOutlined" /></j-button
|
||||
></j-tooltip>
|
||||
<j-tooltip title="编辑资料"
|
||||
><j-button
|
||||
shape="circle"
|
||||
@click="editInfoVisible = true"
|
||||
><AIcon
|
||||
style="font-size: 24px"
|
||||
type="FormOutlined" /></j-button
|
||||
></j-tooltip>
|
||||
<PermissionButton
|
||||
shape="circle"
|
||||
v-if="permission"
|
||||
:tooltip="{
|
||||
title: '修改密码'
|
||||
}"
|
||||
@click="editPasswordVisible = true"
|
||||
>
|
||||
<AIcon
|
||||
style="font-size: 24px"
|
||||
type="LockOutlined"
|
||||
/>
|
||||
</PermissionButton>
|
||||
</j-space>
|
||||
</div>
|
||||
<j-space :size="24">
|
||||
<j-button class="btn" @click="visible = true"
|
||||
>查看详情</j-button
|
||||
>
|
||||
<j-button @click="editInfoVisible = true"
|
||||
>编辑资料</j-button
|
||||
>
|
||||
<j-button
|
||||
v-if="permission"
|
||||
@click="editPasswordVisible = true"
|
||||
>
|
||||
修改密码
|
||||
</j-button>
|
||||
</j-space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="person-content">
|
||||
<div class="person-content-item">
|
||||
<FullPage>
|
||||
<div class="person-content-item-content">
|
||||
<div class="person-content-item-content">
|
||||
<j-tabs v-model:activeKey="user.tabKey" type="card">
|
||||
<j-tab-pane
|
||||
v-for="item in list"
|
||||
:key="item.key"
|
||||
:tab="item.title"
|
||||
/>
|
||||
</j-tabs>
|
||||
<j-scrollbar :height="`calc(100% - 51px)`">
|
||||
<component :is="tabs[user.tabKey]" />
|
||||
</div>
|
||||
</FullPage>
|
||||
</j-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Detail v-if="visible" @close="visible = false" />
|
||||
|
@ -114,9 +99,9 @@ import { updateMeInfo_api } from '@/api/account/center';
|
|||
import { onlyMessage } from '@/utils/comm';
|
||||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import {
|
||||
USER_CENTER_MENU_BUTTON_CODE,
|
||||
USER_CENTER_MENU_CODE
|
||||
} from '@/utils/consts'
|
||||
USER_CENTER_MENU_BUTTON_CODE,
|
||||
USER_CENTER_MENU_CODE,
|
||||
} from '@/utils/consts';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
|
||||
const imageTypes = reactive([
|
||||
|
@ -164,28 +149,9 @@ const visible = ref<boolean>(false);
|
|||
const editInfoVisible = ref<boolean>(false);
|
||||
const editPasswordVisible = ref<boolean>(false);
|
||||
|
||||
const hasPermission = usePermissionStore().hasPermission;
|
||||
const permission = () => hasPermission(`${USER_CENTER_MENU_CODE}:${USER_CENTER_MENU_BUTTON_CODE}`);
|
||||
|
||||
const onActivated = (_key: KeyType) => {
|
||||
user.tabKey = _key;
|
||||
};
|
||||
|
||||
const _org = computed(() => {
|
||||
return user.userInfos?.orgList
|
||||
?.map((item: any) => {
|
||||
return item?.name;
|
||||
})
|
||||
.join(',');
|
||||
});
|
||||
|
||||
const _role = computed(() => {
|
||||
return user.userInfos?.roleList
|
||||
?.map((item: any) => {
|
||||
return item?.name;
|
||||
})
|
||||
.join(',');
|
||||
});
|
||||
const permission = usePermissionStore().hasPermission(
|
||||
`${USER_CENTER_MENU_CODE}:${USER_CENTER_MENU_BUTTON_CODE}`,
|
||||
);
|
||||
|
||||
const onSave = () => {
|
||||
user.getUserInfo();
|
||||
|
@ -213,21 +179,27 @@ watchEffect(() => {
|
|||
user.tabKey = router.params.value?.tabKey;
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
user.tabKey = 'HomeView'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@padding: 14%;
|
||||
.person {
|
||||
.person-header {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
padding: 0 150px;
|
||||
background-color: rgba(2, 125, 180, 0.368);
|
||||
height: 156px;
|
||||
padding: 0 @padding;
|
||||
background-color: #fff;
|
||||
|
||||
.person-header-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
.person-header-item-info {
|
||||
padding-top: 30px;
|
||||
display: flex;
|
||||
.person-header-item-info-left {
|
||||
margin-right: 30px;
|
||||
|
@ -236,64 +208,52 @@ watchEffect(() => {
|
|||
.person-header-item-info-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.person-header-item-info-right-top {
|
||||
span {
|
||||
background-color: rgba(
|
||||
255,
|
||||
255,
|
||||
128,
|
||||
0.43137254901960786
|
||||
);
|
||||
border-radius: 5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
display: flex;
|
||||
font-size: 26px;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
}
|
||||
.person-header-item-info-right-info {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
> :not(:last-child) {
|
||||
margin-right: 20px;
|
||||
div {
|
||||
margin: 5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.person-header-item-action {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
z-index: 2;
|
||||
left: 0;
|
||||
bottom: -25px;
|
||||
padding: 0 50px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.person-header-item-action-left {
|
||||
button {
|
||||
height: 35px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
button {
|
||||
width: 110px;
|
||||
background-color: #ebeef4;
|
||||
color: #333333;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.person-header-item-action-right {
|
||||
:deep(button) {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
.btn {
|
||||
background-color: @primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.person-content-item {
|
||||
padding: 10px 20px;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.person-content {
|
||||
width: 100%;
|
||||
padding: 0 150px;
|
||||
.person-content-item-content {
|
||||
padding: 20px;
|
||||
}
|
||||
padding: 0 @padding;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.person-content-item-content {
|
||||
height: calc(100vh - 251px);
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
功能说明
|
||||
</div>
|
||||
<p>
|
||||
该功能用于将{{'协议包'}}中的
|
||||
该功能用于将协议包中的
|
||||
<b>物模型属性标识</b>与
|
||||
<b>平台物模型属性标识</b>进行映射,当两方属性标识不一致时,可在当前页面直接修改映射管理,系统将以映射后的物模型属性进行数据处理。
|
||||
</p>
|
||||
|
|
|
@ -83,6 +83,10 @@ watch(
|
|||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
const productName = computed(() => {
|
||||
return productList.value.find(item => item.id === modelRef.product)?.name || ''
|
||||
})
|
||||
|
||||
const handleOk = async () => {
|
||||
const params = encodeQuery(props.data);
|
||||
// downloadFile(
|
||||
|
@ -97,7 +101,7 @@ const handleOk = async () => {
|
|||
if (res) {
|
||||
const blob = new Blob([res], { type: modelRef.fileType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
downloadFileByUrl(url, `设备实例`, modelRef.fileType);
|
||||
downloadFileByUrl(url, `${productName.value ? (productName.value + '下设备') : '设备实例'}`, modelRef.fileType);
|
||||
emit('close');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,70 +1,68 @@
|
|||
<template>
|
||||
<div class='file'>
|
||||
<j-form layout='vertical'>
|
||||
<!-- <j-form-item label='文件格式' >
|
||||
<div class='file-type-label'>
|
||||
<a-radio-group class='file-type-radio' v-model:value="modelRef.file.fileType" >
|
||||
<a-radio-button value="xlsx">xlsx</a-radio-button>
|
||||
<a-radio-button value="csv">csv</a-radio-button>
|
||||
</a-radio-group>
|
||||
<a-checkbox v-model:checked="modelRef.file.autoDeploy">自动启用</a-checkbox>
|
||||
<div class="file">
|
||||
<j-form layout="vertical">
|
||||
<j-form-item label="下载模板">
|
||||
<div class="file-download">
|
||||
<j-button @click="downFile('xlsx')">模板格式.xlsx</j-button>
|
||||
<j-button @click="downFile('csv')">模板格式.csv</j-button>
|
||||
</div>
|
||||
</j-form-item>
|
||||
<j-form-item label="文件上传">
|
||||
<!-- 导入系统已存在的设备数据,不会更改已存在设备的所属产品信息 -->
|
||||
<a-upload-dragger
|
||||
v-model:fileList="modelRef.upload"
|
||||
name="file"
|
||||
:action="FILE_UPLOAD"
|
||||
:headers="{
|
||||
'X-Access-Token': LocalStore.get(TOKEN_KEY),
|
||||
}"
|
||||
:maxCount="1"
|
||||
:showUploadList="false"
|
||||
@change="uploadChange"
|
||||
:accept="
|
||||
modelRef?.file?.fileType
|
||||
? `.${modelRef?.file?.fileType}`
|
||||
: '.xlsx'
|
||||
"
|
||||
:before-upload="beforeUpload"
|
||||
:disabled="disabled"
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<div
|
||||
style="
|
||||
height: 115px;
|
||||
line-height: 115px;
|
||||
color: #666666;
|
||||
"
|
||||
>
|
||||
<!-- <AIcon style="font-size: 20px;" type="PlusCircleOutlined" /> -->
|
||||
点击或拖拽上传文件
|
||||
</div>
|
||||
</a-upload-dragger>
|
||||
</j-form-item>
|
||||
<div style="margin-bottom: 16px">
|
||||
<j-checkbox v-model:checked="modelRef.file.autoDeploy"
|
||||
>导入并启用</j-checkbox
|
||||
>
|
||||
</div>
|
||||
</j-form>
|
||||
<div v-if="importLoading" class="result">
|
||||
<div v-if="flag">
|
||||
<j-spin size="small" style="margin-right: 10px" />正在导入
|
||||
</div>
|
||||
<div v-else>
|
||||
<AIcon
|
||||
style="color: #08e21e; margin-right: 10px; font-size: 16px"
|
||||
type="CheckCircleOutlined"
|
||||
/>导入完成
|
||||
</div>
|
||||
<div>导入成功:{{ count }} 个</div>
|
||||
<div>
|
||||
导入失败:<span style="color: #ff595e">{{ errCount }}</span>
|
||||
个<a v-if="errMessage && !flag && errCount > 0" style="margin-left: 20px" @click="downError">下载</a>
|
||||
</div>
|
||||
</div>
|
||||
</j-form-item> -->
|
||||
<j-form-item label='下载模板'>
|
||||
<div class='file-download'>
|
||||
<j-button @click="downFile('xlsx')">模板格式.xlsx</j-button>
|
||||
<j-button @click="downFile('csv')">模板格式.csv</j-button>
|
||||
</div>
|
||||
</j-form-item>
|
||||
<j-row type="flex">
|
||||
<j-col :flex="600">
|
||||
<j-form-item label="文件上传">
|
||||
<a-upload-dragger
|
||||
v-model:fileList="modelRef.upload"
|
||||
name="file"
|
||||
:action="FILE_UPLOAD"
|
||||
:headers="{
|
||||
'X-Access-Token': LocalStore.get(TOKEN_KEY),
|
||||
}"
|
||||
:maxCount="1"
|
||||
:showUploadList="false"
|
||||
@change="uploadChange"
|
||||
:accept="
|
||||
modelRef?.file?.fileType ? `.${modelRef?.file?.fileType}` : '.xlsx'
|
||||
"
|
||||
:before-upload="beforeUpload"
|
||||
:disabled='disabled'
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<div style="height: 115px; line-height: 115px;">
|
||||
<template v-if="!modelRef.upload.length">
|
||||
点击或拖拽上传文件
|
||||
</template>
|
||||
<template v-else>
|
||||
重传
|
||||
</template>
|
||||
</div>
|
||||
</a-upload-dragger>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col flex="auto">
|
||||
<j-form-item>
|
||||
<a-checkbox style="margin: 30px 0 0 30px;" v-model:checked="modelRef.file.autoDeploy">导入并启用</a-checkbox>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</j-form>
|
||||
<div v-if="importLoading">
|
||||
<!-- <j-badge v-if="flag" status="processing" text="正在导入" />
|
||||
<j-badge v-else status="success" text="导入完成" /> -->
|
||||
<div v-if="flag">正在导入</div>
|
||||
<div v-else>导入完成</div>
|
||||
<!-- <span>总数量:{{ count }}</span>
|
||||
<p style="color: red">{{ errMessage }}</p> -->
|
||||
<div>导入成功:{{ count }} 个</div>
|
||||
<div>导入失败:{{ count }} 个<a style="margin-left: 20px;">下载</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='DeviceImportFile'>
|
||||
|
@ -72,129 +70,143 @@ import { FILE_UPLOAD } from '@/api/comm';
|
|||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore, onlyMessage } from '@/utils/comm';
|
||||
import { downloadFileByUrl } from '@/utils/utils';
|
||||
import {
|
||||
deviceImport,
|
||||
templateDownload,
|
||||
} from '@/api/device/instance';
|
||||
import { deviceImport, templateDownload } from '@/api/device/instance';
|
||||
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||
import { message } from 'jetlinks-ui-components'
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
|
||||
const props = defineProps({
|
||||
product: {
|
||||
type: String,
|
||||
default: undefined
|
||||
}
|
||||
})
|
||||
product: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const modelRef = reactive({
|
||||
product: props.product,
|
||||
upload: [],
|
||||
file: {
|
||||
fileType: 'xlsx',
|
||||
autoDeploy: false,
|
||||
},
|
||||
product: props.product,
|
||||
upload: [],
|
||||
file: {
|
||||
fileType: 'xlsx',
|
||||
autoDeploy: false,
|
||||
},
|
||||
});
|
||||
|
||||
const importLoading = ref<boolean>(false);
|
||||
const flag = ref<boolean>(false);
|
||||
const count = ref<number>(0);
|
||||
const errCount = ref<number>(0);
|
||||
|
||||
const errMessage = ref<string>('');
|
||||
const disabled = ref(false)
|
||||
const disabled = ref(false);
|
||||
|
||||
const downFile = async (type: string) => {
|
||||
const res: any = await templateDownload(props.product!, type);
|
||||
if (res) {
|
||||
const blob = new Blob([res], { type: type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
downloadFileByUrl(url, `设备导入模板`, type);
|
||||
}
|
||||
const res: any = await templateDownload(props.product!, type);
|
||||
if (res) {
|
||||
const blob = new Blob([res], { type: type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
downloadFileByUrl(url, `设备导入模板`, type);
|
||||
}
|
||||
};
|
||||
|
||||
const beforeUpload = (_file: any) => {
|
||||
const fileType = modelRef.file?.fileType === 'csv' ? 'csv' : 'xlsx';
|
||||
const isCsv = _file.type === 'text/csv';
|
||||
const isXlsx = _file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
if (!isCsv && fileType !== 'xlsx') {
|
||||
onlyMessage('请上传.csv格式文件', 'warning');
|
||||
}
|
||||
if (!isXlsx && fileType !== 'csv') {
|
||||
onlyMessage('请上传.xlsx格式文件', 'warning');
|
||||
}
|
||||
return (isCsv && fileType !== 'xlsx') || (isXlsx && fileType !== 'csv');
|
||||
const fileType = modelRef.file?.fileType === 'csv' ? 'csv' : 'xlsx';
|
||||
const isCsv = _file.type === 'text/csv';
|
||||
const isXlsx =
|
||||
_file.type ===
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
if (!isCsv && fileType !== 'xlsx') {
|
||||
onlyMessage('请上传.csv格式文件', 'warning');
|
||||
}
|
||||
if (!isXlsx && fileType !== 'csv') {
|
||||
onlyMessage('请上传.xlsx格式文件', 'warning');
|
||||
}
|
||||
return (isCsv && fileType !== 'xlsx') || (isXlsx && fileType !== 'csv');
|
||||
};
|
||||
|
||||
const handleDrop = () => {
|
||||
const handleDrop = () => {};
|
||||
|
||||
const downError = () => {
|
||||
window.open(errMessage.value)
|
||||
}
|
||||
|
||||
const submitData = async (fileUrl: string) => {
|
||||
if (!!fileUrl) {
|
||||
count.value = 0;
|
||||
errMessage.value = '';
|
||||
const autoDeploy = !!modelRef?.file?.autoDeploy || false;
|
||||
importLoading.value = true;
|
||||
let dt = 0;
|
||||
const source = new EventSourcePolyfill(
|
||||
deviceImport(props.product!, fileUrl, autoDeploy),
|
||||
);
|
||||
source.onmessage = (e: any) => {
|
||||
const res = JSON.parse(e.data);
|
||||
if (res.success) {
|
||||
const temp = res.result.total;
|
||||
dt += temp;
|
||||
count.value = dt;
|
||||
} else {
|
||||
errMessage.value = res.message || '失败';
|
||||
}
|
||||
disabled.value = false
|
||||
};
|
||||
source.onerror = (e: { status: number }) => {
|
||||
if (e.status === 403) errMessage.value = '暂无权限,请联系管理员';
|
||||
flag.value = false;
|
||||
disabled.value = false
|
||||
source.close();
|
||||
};
|
||||
source.onopen = () => {};
|
||||
} else {
|
||||
message.error('请先上传文件');
|
||||
}
|
||||
if (!!fileUrl) {
|
||||
count.value = 0;
|
||||
errCount.value = 0;
|
||||
const autoDeploy = !!modelRef?.file?.autoDeploy || false;
|
||||
importLoading.value = true;
|
||||
let dt = 0;
|
||||
let et = 0;
|
||||
const source = new EventSourcePolyfill(
|
||||
deviceImport(props.product!, fileUrl, autoDeploy),
|
||||
);
|
||||
source.onmessage = (e: any) => {
|
||||
const res = JSON.parse(e.data);
|
||||
if (res.success) {
|
||||
const temp = res.result.total;
|
||||
dt += temp;
|
||||
count.value = dt;
|
||||
} else {
|
||||
if (res.detailFile) {
|
||||
errMessage.value = res.detailFile
|
||||
} else {
|
||||
et += 1;
|
||||
errCount.value = et;
|
||||
}
|
||||
}
|
||||
disabled.value = false;
|
||||
};
|
||||
source.onerror = (e: { status: number }) => {
|
||||
if (e.status === 403) errMessage.value = '暂无权限,请联系管理员';
|
||||
flag.value = false;
|
||||
disabled.value = false;
|
||||
source.close();
|
||||
};
|
||||
source.onopen = () => {};
|
||||
} else {
|
||||
message.error('请先上传文件');
|
||||
}
|
||||
};
|
||||
|
||||
const uploadChange = async (info: Record<string, any>) => {
|
||||
disabled.value = true
|
||||
// console.log(info.file)
|
||||
if (info.file.status === 'done') {
|
||||
const resp: any = info.file.response || { result: '' };
|
||||
await submitData(resp?.result || '');
|
||||
}
|
||||
disabled.value = true;
|
||||
if (info.file.status === 'done') {
|
||||
const resp: any = info.file.response || { result: '' };
|
||||
await submitData(resp?.result || '');
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.file {
|
||||
.file-type-label {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
.file-type-label {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
.file-type-radio {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
.file-type-radio {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
||||
:deep(.ant-radio-button-wrapper) {
|
||||
width: 50%;
|
||||
}
|
||||
:deep(.ant-radio-button-wrapper) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-download {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
>button {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
.file-download {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
> button {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.result {
|
||||
div {
|
||||
margin: 5px 0;
|
||||
color: #605e5c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -172,7 +172,7 @@ const saveImage = (url: string) => {
|
|||
width: @with;
|
||||
height: @height;
|
||||
overflow: hidden;
|
||||
//border-radius: 50%;
|
||||
border-radius: 5px;
|
||||
// border: @border;
|
||||
transition: all 0.3s;
|
||||
|
||||
|
@ -197,9 +197,9 @@ const saveImage = (url: string) => {
|
|||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(#000, 0.06);
|
||||
// background-color: rgba(#000, 0.06);
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
// padding: 8px;
|
||||
|
||||
.upload-image-mask {
|
||||
.flex-center();
|
||||
|
@ -211,7 +211,7 @@ const saveImage = (url: string) => {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
background-color: @mask-color;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ const props = defineProps({
|
|||
},
|
||||
photoUrl: {
|
||||
type: String,
|
||||
default: getImage('/apply/provider1.png'),
|
||||
default: getImage('/apply/internal-standalone.png'),
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<any[]>,
|
||||
|
@ -58,12 +58,12 @@ const props = defineProps({
|
|||
const emit = defineEmits(['update:value', 'update:photoUrl']);
|
||||
|
||||
const defaultImg = {
|
||||
'internal-standalone': getImage('/apply/provider1.png'),
|
||||
'internal-integrated': getImage('/apply/provider2.png'),
|
||||
'wechat-webapp': getImage('/apply/provider4.png'),
|
||||
'dingtalk-ent-app': getImage('/apply/provider3.png'),
|
||||
'third-party': getImage('/apply/provider5.png'),
|
||||
'wechat-miniapp': getImage('/apply/provider1.png'),
|
||||
'internal-standalone': getImage('/apply/internal-standalone.png'),
|
||||
'internal-integrated': getImage('/apply/internal-integrated.png'),
|
||||
'wechat-webapp': getImage('/apply/wechat-webapp.png'),
|
||||
'dingtalk-ent-app': getImage('/apply/dingtalk-ent-app.png'),
|
||||
'third-party': getImage('/apply/third-party.png'),
|
||||
'wechat-miniapp': getImage('/apply/wechat-miniapp.png'),
|
||||
}
|
||||
|
||||
const urlValue = ref<any>({...defaultImg});
|
||||
|
|
|
@ -1427,7 +1427,7 @@ const loading = ref<boolean>(false);
|
|||
const initForm: formType = {
|
||||
name: '',
|
||||
provider: 'internal-standalone',
|
||||
logoUrl: getImage('/apply/provider1.png'),
|
||||
logoUrl: getImage('/apply/internal-standalone.png'),
|
||||
integrationModes: [],
|
||||
description: '',
|
||||
page: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="child-item">
|
||||
<div class="child-item" :class="{ border: !isLast }">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
<div style="color: #333333">
|
||||
{{ data?.name }}
|
||||
</div>
|
||||
<div>
|
||||
|
@ -14,7 +14,7 @@
|
|||
</j-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-item-right" v-if="checked">
|
||||
<div class="child-item-right" :class="{ 'disabled': !checked }">
|
||||
<MCarousel :data="data?.channels">
|
||||
<template #card="slotProps">
|
||||
<div class="box-item">
|
||||
|
@ -74,29 +74,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #add>
|
||||
<div class="box-item">
|
||||
<div class="box-item-img">
|
||||
<j-tooltip
|
||||
:title="!add ? '暂无权限,请联系管理员' : ''"
|
||||
>
|
||||
<j-button
|
||||
:disabled="!add"
|
||||
type="text"
|
||||
@click="onAdd"
|
||||
>
|
||||
<AIcon
|
||||
style="font-size: 20px"
|
||||
type="PlusOutlined"
|
||||
/>
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</div>
|
||||
<div class="box-item-text"></div>
|
||||
</div>
|
||||
</template>
|
||||
</MCarousel>
|
||||
|
||||
<div class="box-item-add">
|
||||
<div class="box-item-img">
|
||||
<j-tooltip :title="!add ? '暂无权限,请联系管理员' : ''">
|
||||
<j-button :disabled="!add" type="text" @click="onAdd">
|
||||
<AIcon
|
||||
style="font-size: 20px"
|
||||
type="PlusOutlined"
|
||||
/>
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</div>
|
||||
<div class="box-item-text"></div>
|
||||
</div>
|
||||
|
||||
<div class="child-item-right-auth">
|
||||
<j-tooltip :title="!update ? '暂无权限,请联系管理员' : ''">
|
||||
<j-button :disabled="!update" type="text" @click="onAuth">
|
||||
|
@ -156,6 +149,10 @@ const props = defineProps({
|
|||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
isLast: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['refresh']);
|
||||
|
@ -345,9 +342,7 @@ const onSave = (_data: any) => {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
@ -368,14 +363,15 @@ const onSave = (_data: any) => {
|
|||
|
||||
.child-item-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.box-item {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
.box-item-img {
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -384,10 +380,21 @@ const onSave = (_data: any) => {
|
|||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.box-item-add {
|
||||
cursor: pointer;
|
||||
margin-left: 16px;
|
||||
background-color: #F8F9FC;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.child-item-right-auth {
|
||||
margin-left: 20px;
|
||||
|
||||
|
@ -409,6 +416,14 @@ const onSave = (_data: any) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
&.border {
|
||||
box-shadow: 0px 1px 0px 0px #e2e2e2;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,12 +1,12 @@
|
|||
import { getImage } from "@/utils/comm";
|
||||
|
||||
const iconMap = new Map();
|
||||
iconMap.set('notifier-dingTalk', getImage('/notice/dingtalk.png'));
|
||||
iconMap.set('notifier-weixin', getImage('/notice/wechat.png'));
|
||||
iconMap.set('notifier-email', getImage('/notice/email.png'));
|
||||
iconMap.set('notifier-voice', getImage('/notice/voice.png'));
|
||||
iconMap.set('notifier-sms', getImage('/notice/sms.png'));
|
||||
iconMap.set('inside-mail', getImage('/notice/inside-mail.png'));
|
||||
iconMap.set('notifier-dingTalk', getImage('/notice-rule/dingtalk.png'));
|
||||
iconMap.set('notifier-weixin', getImage('/notice-rule/wechat.png'));
|
||||
iconMap.set('notifier-email', getImage('/notice-rule/email.png'));
|
||||
iconMap.set('notifier-voice', getImage('/notice-rule/voice.png'));
|
||||
iconMap.set('notifier-sms', getImage('/notice-rule/sms.png'));
|
||||
iconMap.set('inside-mail', getImage('/notice-rule/inside-mail.png'));
|
||||
|
||||
const noticeType = new Map();
|
||||
noticeType.set('notifier-dingTalk', 'dingTalk');
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="content-collapse">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey">
|
||||
<template #expandIcon="{ isActive }">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey" expand-icon-position="right">
|
||||
<!-- <template #expandIcon="{ isActive }">
|
||||
<AIcon
|
||||
type="CaretRightOutlined"
|
||||
:style="{
|
||||
|
@ -19,23 +19,22 @@
|
|||
}deg)`,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
</template> -->
|
||||
<j-collapse-panel
|
||||
v-for="item in dataSource"
|
||||
:key="item.provider"
|
||||
class="custom"
|
||||
:header="item.name"
|
||||
>
|
||||
<template #header
|
||||
><h3>{{ item.name }}</h3></template
|
||||
>
|
||||
<div class="child">
|
||||
<template
|
||||
v-for="child in item.children"
|
||||
v-for="(child, index) in item.children"
|
||||
:key="child.provider"
|
||||
>
|
||||
<Item
|
||||
:data="data.find(i => i?.provider === child?.provider)"
|
||||
@refresh="onRefresh"
|
||||
:isLast="index === item.children?.length"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -156,13 +155,19 @@ onMounted(() => {
|
|||
background-color: #f6f6f6;
|
||||
}
|
||||
.custom {
|
||||
background: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
background: #F7F8FA;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
color: #333333;
|
||||
}
|
||||
.child {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.content-collapse {
|
||||
:deep(.ant-collapse-content > .ant-collapse-content-box) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -239,12 +239,13 @@ const loading = ref(false);
|
|||
const bindings = ref<any[]>();
|
||||
// const basis = ref<any>({});
|
||||
|
||||
const defaultImg = getImage('/apply/provider1.png');
|
||||
const defaultImg = getImage('/apply/internal-standalone.png');
|
||||
const iconMap = new Map();
|
||||
iconMap.set('dingtalk-ent-app', getImage('/bind/dingtalk.png'));
|
||||
iconMap.set('wechat-webapp', getImage('/bind/wechat-webapp.png'));
|
||||
iconMap.set('internal-standalone', getImage('/apply/provider1.png'));
|
||||
iconMap.set('third-party', getImage('/apply/provider5.png'));
|
||||
iconMap.set('internal-standalone', getImage('/apply/internal-standalone.png'));
|
||||
iconMap.set('third-party', getImage('/apply/third-party.png'));
|
||||
iconMap.set('wechat-miniapp', getImage('/apply/wechat-miniapp.png'));
|
||||
|
||||
const onFinish = async () => {
|
||||
try {
|
||||
|
|