feat: 设备导入
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>
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -51,8 +51,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) => {
|
||||
|
|
|
@ -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: 48px 90px;
|
||||
box-sizing: border-box;
|
||||
.view-content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
.select-item {
|
||||
border: 2px solid transparent;
|
||||
img {
|
||||
width: 100%;
|
||||
background-size: cover;
|
||||
}
|
||||
cursor: pointer;
|
||||
// width: 312px;
|
||||
|
||||
&.selected {
|
||||
border-color: #10239e;
|
||||
img {
|
||||
width: 312px;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin: 48px auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 68px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -19,8 +19,6 @@
|
|||
<div class="box-item">
|
||||
<div class="box-item-img">
|
||||
<j-dropdown placement="top" :trigger="['click']">
|
||||
<!-- :visible="show?.[slotProps?.id]"
|
||||
@visibleChange="onVisibleChange(slotProps)" -->
|
||||
<div>
|
||||
<img
|
||||
:src="
|
||||
|
@ -28,6 +26,7 @@
|
|||
slotProps?.channelProvider,
|
||||
)
|
||||
"
|
||||
style="width: 60px;"
|
||||
/>
|
||||
<div
|
||||
:class="{
|
||||
|
@ -37,13 +36,6 @@
|
|||
}"
|
||||
></div>
|
||||
</div>
|
||||
<!-- v-if="
|
||||
notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
) &&
|
||||
slotProps?.channelProvider !==
|
||||
'inside-mail'
|
||||
" -->
|
||||
<template #overlay>
|
||||
<j-menu>
|
||||
<j-menu-item
|
||||
|
@ -97,13 +89,13 @@
|
|||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
<div class="box-item-checked">
|
||||
<!-- <div class="box-item-checked">
|
||||
<j-checkbox
|
||||
:checked="
|
||||
notifyChannels?.includes(slotProps?.id)
|
||||
"
|
||||
></j-checkbox>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="box-item-text">
|
||||
{{ slotProps?.name }}
|
||||
|
@ -140,12 +132,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);
|
||||
|
@ -303,30 +295,21 @@ 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;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
|
@ -1,482 +0,0 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<div class="center-container">
|
||||
<div class="card">
|
||||
<div class="content" style="margin-top: 0">
|
||||
<div
|
||||
class="content-item flex-item"
|
||||
style="width: 350px; justify-content: center"
|
||||
>
|
||||
<img
|
||||
v-if="userInfo.avatar"
|
||||
:src="userInfo.avatar"
|
||||
style="width: 140px; border-radius: 70px"
|
||||
alt=""
|
||||
/>
|
||||
<div class="default-avatar" v-else>
|
||||
<AIcon type="UserOutlined" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
"
|
||||
>
|
||||
<j-upload
|
||||
v-model:file-list="upload.fileList"
|
||||
accept=".jpg,.png,.jfif,.pjp,.pjpeg,.jpeg"
|
||||
:maxCount="1"
|
||||
:show-upload-list="false"
|
||||
:headers="{
|
||||
[TOKEN_KEY]: LocalStore.get(TOKEN_KEY),
|
||||
}"
|
||||
:action="`${BASE_API_PATH}/file/static`"
|
||||
@change="upload.changeBackUpload"
|
||||
:beforeUpload="upload.beforeUpload"
|
||||
>
|
||||
<j-button>
|
||||
<AIcon type="UploadOutlined" />
|
||||
更换头像
|
||||
</j-button>
|
||||
</j-upload>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="content-item flex-item"
|
||||
style="flex: 1; padding: 15px 0"
|
||||
>
|
||||
<div class="info-card">
|
||||
<p>用户名</p>
|
||||
<p>{{ userInfo.username }}</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>账号ID</p>
|
||||
<p>{{ userInfo.id }}</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>注册时间</p>
|
||||
<p>
|
||||
{{
|
||||
userInfo.createTime ? moment(userInfo.createTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
) : '-'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>电话</p>
|
||||
<p>{{ userInfo.telephone || '-' }}</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>姓名</p>
|
||||
<p>{{ userInfo.name }}</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>角色</p>
|
||||
<p>
|
||||
{{
|
||||
(userInfo.roleList &&
|
||||
userInfo.roleList
|
||||
.map((item) => item.name)
|
||||
.join(',')) ||
|
||||
'-'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>组织</p>
|
||||
<p>
|
||||
{{
|
||||
(userInfo.orgList &&
|
||||
userInfo.orgList
|
||||
.map((item) => item.name)
|
||||
.join(',')) ||
|
||||
'-'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<p>邮箱</p>
|
||||
<p>{{ userInfo.email || '-' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<AIcon
|
||||
type="EditOutlined"
|
||||
class="edit"
|
||||
style="right: 40px"
|
||||
@click="editInfoVisible = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" v-if='updatePassword'>
|
||||
<h3>修改密码</h3>
|
||||
<div class="content">
|
||||
<div class="content" style="align-items: flex-end">
|
||||
<AIcon
|
||||
type="LockOutlined"
|
||||
style="color: #1d39c4; font-size: 70px"
|
||||
/>
|
||||
<span
|
||||
style="margin-left: 5px; color: rgba(0, 0, 0, 0.55)"
|
||||
>安全性高的密码可以使帐号更安全。建议您定期更换密码,设置一个包含字母,符号或数字中至少两项且长度超过8位的密码</span
|
||||
>
|
||||
</div>
|
||||
<span class="edit">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
@click="editPasswordVisible = true"
|
||||
>
|
||||
<AIcon type="EditOutlined" style="color: #1d39c4" />
|
||||
</PermissionButton>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 社区版不显示 -->
|
||||
<div class="card" v-if="isNoCommunity">
|
||||
<h3>绑定三方账号</h3>
|
||||
<div class="content">
|
||||
<div class="account-card" v-for="item in bindList" :key="item.id">
|
||||
<img
|
||||
:src="item.logoUrl || getImage(bindIcon[item.provider])"
|
||||
style="height: 50px;width: 50px"
|
||||
width='50px'
|
||||
height='50px'
|
||||
alt=""
|
||||
/>
|
||||
<Ellipsis style="width: 150px; font-size: 22px">
|
||||
<div v-if="item.bound">
|
||||
<div>绑定名:{{ item.others.name }}</div>
|
||||
<div>
|
||||
绑定时间:{{
|
||||
moment(item.bindTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>{{ item.name }}未绑定</div>
|
||||
</Ellipsis>
|
||||
<j-popconfirm
|
||||
v-if="item.bound"
|
||||
title="确认解除绑定嘛?"
|
||||
@confirm="() => unBind(item.id)"
|
||||
>
|
||||
<j-button>解除绑定</j-button>
|
||||
</j-popconfirm>
|
||||
<j-button
|
||||
v-else
|
||||
type="primary"
|
||||
@click="clickBind(item.id)"
|
||||
>立即绑定</j-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 第三方用户不显示 -->
|
||||
<div class="card" v-if="!isApiUser">
|
||||
<h3>首页视图</h3>
|
||||
<div class="choose-view">
|
||||
<j-row class="view-content" :gutter="24">
|
||||
<j-col
|
||||
:span="6"
|
||||
class="select-item"
|
||||
:class="{ selected: currentView === 'device' }"
|
||||
@click="currentView = 'device'"
|
||||
>
|
||||
<img :src="getImage('/home/device.png')" alt="" />
|
||||
</j-col>
|
||||
<j-col
|
||||
:span="6"
|
||||
class="select-item"
|
||||
:class="{ selected: currentView === 'ops' }"
|
||||
@click="currentView = 'ops'"
|
||||
>
|
||||
<img :src="getImage('/home/ops.png')" alt="" />
|
||||
</j-col>
|
||||
<j-col
|
||||
:span="6"
|
||||
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
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditInfoDialog
|
||||
v-if="editInfoVisible"
|
||||
v-model:visible="editInfoVisible"
|
||||
:data="{ ...userInfo }"
|
||||
@ok="getUserInfo"
|
||||
/>
|
||||
<EditPasswordDialog
|
||||
v-if="editPasswordVisible"
|
||||
v-model:visible="editPasswordVisible"
|
||||
/>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Center">
|
||||
import PermissionButton from '@/components/PermissionButton/index.vue';
|
||||
import EditInfoDialog from './components/EditInfoDialog.vue';
|
||||
import EditPasswordDialog from './components/EditPasswordDialog.vue';
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore, getImage, onlyMessage } from '@/utils/comm'
|
||||
import { message, UploadChangeParam, UploadFile } from 'ant-design-vue';
|
||||
import {
|
||||
getMeInfo_api,
|
||||
getSsoBinds_api,
|
||||
unBind_api,
|
||||
updateMeInfo_api
|
||||
} from '@/api/account/center';
|
||||
import moment from 'moment';
|
||||
import { getMe_api, getView_api, setView_api } from '@/api/home';
|
||||
import { isNoCommunity } from '@/utils/utils';
|
||||
import { userInfoType } from './typing';
|
||||
import { usePermissionStore } from 'store/permission'
|
||||
|
||||
const btnHasPermission = usePermissionStore().hasPermission;
|
||||
const updatePassword = btnHasPermission('account-center:user-center-passwd-update')
|
||||
const permission = 'system/User';
|
||||
const userInfo = ref<userInfoType>({} as any);
|
||||
// 第三方账号
|
||||
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',
|
||||
};
|
||||
const unBind = (id: string) => {
|
||||
unBind_api(id).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
message.success('解绑成功');
|
||||
getSsoBinds();
|
||||
}
|
||||
});
|
||||
};
|
||||
const clickBind = (id: string) => {
|
||||
window.open(
|
||||
`${BASE_API_PATH}/application/sso/${id}/login?autoCreateUser=false`,
|
||||
);
|
||||
localStorage.setItem('onBind', 'false');
|
||||
localStorage.setItem('onLogin', 'yes');
|
||||
window.onstorage = (e) => {
|
||||
if (e.newValue) {
|
||||
getSsoBinds();
|
||||
}
|
||||
};
|
||||
};
|
||||
const upload = reactive({
|
||||
fileList: [] as any[],
|
||||
uploadLoading: false,
|
||||
changeBackUpload: (info: UploadChangeParam<UploadFile<any>>) => {
|
||||
if (info.file.status === 'uploading') {
|
||||
upload.uploadLoading = true;
|
||||
} else if (info.file.status === 'done') {
|
||||
info.file.url = info.file.response?.result;
|
||||
upload.uploadLoading = false;
|
||||
userInfo.value.avatar = info.file.response?.result;
|
||||
updateMeInfo_api(userInfo.value).then(res => {
|
||||
if(res.success) {
|
||||
onlyMessage('上传成功')
|
||||
}
|
||||
})
|
||||
} else if (info.file.status === 'error') {
|
||||
upload.uploadLoading = false;
|
||||
onlyMessage('logo上传失败,请稍后再试', 'error');
|
||||
}
|
||||
},
|
||||
beforeUpload: ({ size, type }: File) => {
|
||||
const imageTypes = ['jpg', 'png', 'jfif', 'pjp', 'pjpeg', 'jpeg'];
|
||||
const typeBool =
|
||||
imageTypes.filter((typeStr) => type.includes(typeStr)).length > 0;
|
||||
const sizeBool = size < 4 * 1024 * 1024;
|
||||
|
||||
(typeBool && sizeBool) || message.error('请上传正确格式的图片');
|
||||
return typeBool && sizeBool;
|
||||
},
|
||||
});
|
||||
// 首页视图
|
||||
const isApiUser = ref<boolean>();
|
||||
const currentView = ref<string>('');
|
||||
const confirm = () => {
|
||||
setView_api({
|
||||
name: 'view',
|
||||
content: currentView.value,
|
||||
}).then(() => message.success('保存成功'));
|
||||
};
|
||||
|
||||
const editInfoVisible = ref<boolean>(false);
|
||||
const editPasswordVisible = ref<boolean>(false);
|
||||
init();
|
||||
|
||||
function init() {
|
||||
getUserInfo();
|
||||
isNoCommunity && getSsoBinds();
|
||||
getViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
function getUserInfo() {
|
||||
getMeInfo_api().then((resp) => {
|
||||
userInfo.value = resp.result as userInfoType;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取绑定第三方账号
|
||||
*/
|
||||
function getSsoBinds() {
|
||||
getSsoBinds_api().then((resp: any) => {
|
||||
if (resp.status === 200) bindList.value = resp.result;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取首页视图
|
||||
*/
|
||||
function getViews() {
|
||||
// 判断是否是api用户 不是则获取选中的视图
|
||||
getMe_api()
|
||||
.then((resp: any) => {
|
||||
if (resp && resp.status === 200) {
|
||||
isApiUser.value = resp.result.dimensions.find(
|
||||
(item: any) =>
|
||||
item.type === 'api-client' ||
|
||||
item.type.id === 'api-client',
|
||||
);
|
||||
if (!isApiUser.value) return getView_api();
|
||||
}
|
||||
})
|
||||
.then((resp: any) => {
|
||||
if (resp?.status === 200) {
|
||||
if (resp.result) currentView.value = resp.result?.content;
|
||||
else if (resp.result?.username === 'admin') {
|
||||
currentView.value = 'comprehensive';
|
||||
} else currentView.value = 'init';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.center-container {
|
||||
background-color: #f0f2f5;
|
||||
min-height: 100vh;
|
||||
.card {
|
||||
margin: 16px 0;
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
|
||||
h3 {
|
||||
font-size: 22px;
|
||||
|
||||
&::before {
|
||||
display: inline-block;
|
||||
width: 3px;
|
||||
height: 0.7em;
|
||||
content: '';
|
||||
background-color: #2f54eb;
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
margin-top: 24px;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
|
||||
.content-item {
|
||||
margin-right: 24px;
|
||||
|
||||
.default-avatar {
|
||||
background-color: #ccc;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
font-size: 70px;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.info-card {
|
||||
width: 25%;
|
||||
|
||||
:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
:last-child {
|
||||
color: #666363d9;
|
||||
}
|
||||
}
|
||||
&.flex-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.edit {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 30px;
|
||||
right: 24px;
|
||||
color: #1d39c4;
|
||||
}
|
||||
|
||||
.account-card {
|
||||
width: 415px;
|
||||
background-image: url(/images/notice/dingtalk-background.png);
|
||||
border-right: 1px solid #f0f0f0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-view {
|
||||
width: 100%;
|
||||
margin-top: 48px;
|
||||
.view-content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
.select-item {
|
||||
border: 2px solid transparent;
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-color: #10239e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin: 48px auto;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -16,69 +16,41 @@
|
|||
</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>
|
||||
<span>{{ _org }}部门 · {{ _role }}角色</span>
|
||||
</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 type="primary" @click="visible = true"
|
||||
>查看详情</j-button
|
||||
>
|
||||
<j-button @click="editInfoVisible = true"
|
||||
>编辑资料</j-button
|
||||
>
|
||||
<PermissionButton
|
||||
v-if="permission"
|
||||
@click="editPasswordVisible = true"
|
||||
>
|
||||
修改密码
|
||||
</PermissionButton>
|
||||
</j-space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="person-content">
|
||||
<div class="person-content-item">
|
||||
<FullPage>
|
||||
<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>
|
||||
<div class="person-content-item-content">
|
||||
<component :is="tabs[user.tabKey]" />
|
||||
</div>
|
||||
|
@ -114,9 +86,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([
|
||||
|
@ -165,7 +137,8 @@ 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 permission = () =>
|
||||
hasPermission(`${USER_CENTER_MENU_CODE}:${USER_CENTER_MENU_BUTTON_CODE}`);
|
||||
|
||||
const onActivated = (_key: KeyType) => {
|
||||
user.tabKey = _key;
|
||||
|
@ -219,15 +192,16 @@ watchEffect(() => {
|
|||
.person {
|
||||
.person-header {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
height: 156px;
|
||||
padding: 0 150px;
|
||||
background-color: rgba(2, 125, 180, 0.368);
|
||||
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;
|
||||
|
@ -238,61 +212,43 @@ watchEffect(() => {
|
|||
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;
|
||||
// > :not(:last-child) {
|
||||
// margin-right: 20px;
|
||||
// }
|
||||
}
|
||||
.person-header-item-info-right-info {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
> :not(:last-child) {
|
||||
margin-right: 20px;
|
||||
span {
|
||||
background-color: #f7f8fa;
|
||||
border-radius: 5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.person-header-item-action-right {
|
||||
:deep(button) {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
button {
|
||||
width: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.person-content-item {
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.person-content {
|
||||
width: 100%;
|
||||
padding: 0 150px;
|
||||
padding: 0 260px;
|
||||
// margin-top: 15px;
|
||||
.person-content-item-content {
|
||||
padding: 20px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -285,6 +285,14 @@ const getProtocol = async () => {
|
|||
if (productStore.current?.accessProvider === 'plugin_gateway') {
|
||||
list.value.push({ key: 'MetadataMap', tab: '物模型映射'})
|
||||
}
|
||||
// if (
|
||||
// instanceStore.current?.features?.find(
|
||||
// (item: any) => item?.id === 'diffMetadataSameProduct',
|
||||
// ) &&
|
||||
// !keys.includes('MetadataMap')
|
||||
// ) {
|
||||
// list.value.push({ key: 'MetadataMap', tab: '物模型映射'});
|
||||
// }
|
||||
}
|
||||
};
|
||||
/**
|
||||
|
|
|
@ -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,5 +1,5 @@
|
|||
<template>
|
||||
<div class="child-item">
|
||||
<div class="child-item" :class="{'border': !isLast}">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
{{ data?.name }}
|
||||
|
@ -156,6 +156,10 @@ const props = defineProps({
|
|||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
isLast: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['refresh']);
|
||||
|
@ -347,7 +351,6 @@ const onSave = (_data: any) => {
|
|||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
@ -410,5 +413,9 @@ const onSave = (_data: any) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.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');
|
||||
|
|
|
@ -30,12 +30,13 @@
|
|||
>
|
||||
<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 +157,18 @@ onMounted(() => {
|
|||
background-color: #f6f6f6;
|
||||
}
|
||||
.custom {
|
||||
background: #f7f7f7;
|
||||
// background: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.child {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.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 {
|
||||
|
|
10
yarn.lock
|
@ -3825,8 +3825,8 @@ jetlinks-store@^0.0.3:
|
|||
|
||||
jetlinks-ui-components@^1.0.24:
|
||||
version "1.0.24"
|
||||
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.24.tgz#97580bed720526b50b3244440c7ae16d3d0a26c0"
|
||||
integrity sha512-7ccv/eu9moZZFzCRuBa8Pe4NLd/knDARWwJaivH+qgkPSIIdij0Wax27zFwoRqivsDzbOAs2iRButcwSNvR9AQ==
|
||||
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.24.tgz#747dbd3c6d8af389d4eb02ffc37e9ee9a8da94c5"
|
||||
integrity sha512-gJ+IJ90p6Q8YQJxfBjep3BCBHg/conxYOHv3v0aiGrzKzdidSk075OcXxOx7bIeAWoqBbY1uCNhYfnhFWCwVIQ==
|
||||
dependencies:
|
||||
"@vueuse/core" "^9.12.0"
|
||||
"@vueuse/router" "^9.13.0"
|
||||
|
@ -3834,6 +3834,7 @@ jetlinks-ui-components@^1.0.24:
|
|||
colorpicker-v3 "^2.10.2"
|
||||
lodash-es "^4.17.21"
|
||||
monaco-editor "^0.35.0"
|
||||
sortablejs "^1.15.0"
|
||||
vuedraggable "^4.1.0"
|
||||
|
||||
js-cookie@^3.0.1:
|
||||
|
@ -6168,6 +6169,11 @@ sortablejs@1.14.0:
|
|||
resolved "http://registry.jetlinks.cn/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
|
||||
integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
|
||||
|
||||
sortablejs@^1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "http://registry.jetlinks.cn/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"
|
||||
integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||
|
|