Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
2559138a4a
|
@ -1 +1,2 @@
|
||||||
|
ENV=develop
|
||||||
VITE_APP_BASE_API=/api
|
VITE_APP_BASE_API=/api
|
|
@ -1 +1,2 @@
|
||||||
|
ENV=production
|
||||||
VITE_APP_BASE_API=/api
|
VITE_APP_BASE_API=/api
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const rootPath = path.resolve(__dirname, '../')
|
||||||
|
|
||||||
|
function optimizeAntdComponents(moduleName: string): string[] {
|
||||||
|
const moduleESPath = `${moduleName}/es`
|
||||||
|
const nodeModulePath = `./node_modules/${moduleESPath}`
|
||||||
|
const includes: string[] = [moduleESPath]
|
||||||
|
|
||||||
|
const folders = fs.readdirSync(
|
||||||
|
path.resolve(rootPath, nodeModulePath)
|
||||||
|
)
|
||||||
|
|
||||||
|
folders.map(name => {
|
||||||
|
const folderName = path.resolve(
|
||||||
|
rootPath,
|
||||||
|
nodeModulePath,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
let stat = fs.lstatSync(folderName)
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
let styleFolder = path.resolve(folderName, 'style')
|
||||||
|
if (fs.existsSync((styleFolder))) {
|
||||||
|
let _stat = fs.lstatSync(styleFolder)
|
||||||
|
if (_stat.isDirectory()) {
|
||||||
|
includes.push(`${moduleESPath}/${name}/style`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return includes
|
||||||
|
}
|
||||||
|
|
||||||
|
export function optimizeDeps() {
|
||||||
|
return {
|
||||||
|
name: "optimizeDeps",
|
||||||
|
configResolved: async (config) => {
|
||||||
|
const components = [
|
||||||
|
...optimizeAntdComponents('ant-design-vue'),
|
||||||
|
...optimizeAntdComponents('jetlinks-ui-components')
|
||||||
|
]
|
||||||
|
let concat = config.optimizeDeps.include.concat(components)
|
||||||
|
config.optimizeDeps.include = Array.from(new Set(concat))
|
||||||
|
console.log(config.optimizeDeps.include)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 285 KiB |
|
@ -1,8 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view />
|
<ConfigProvider :locale='zhCN'>
|
||||||
|
<router-view />
|
||||||
|
</ConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ConfigProvider } from 'jetlinks-ui-components'
|
||||||
|
import zhCN from 'jetlinks-ui-components/es/locale/zh_CN';
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -33,6 +33,13 @@ export const detail = (id: string) => server.get<DeviceInstance>(`/device-instan
|
||||||
*/
|
*/
|
||||||
export const query = (data?: Record<string, any>) => server.post('/device-instance/_query', data)
|
export const query = (data?: Record<string, any>) => server.post('/device-instance/_query', data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不分页查询设备
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const queryNoPagingPost = (data?: Record<string, any>) => server.post('/device-instance/_query/no-paging?paging=false', data)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除设备
|
* 删除设备
|
||||||
* @param id 设备ID
|
* @param id 设备ID
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import server from '@/utils/request'
|
||||||
|
|
||||||
|
export const restPassword = (id: string) => server.post(`/edge/operations/${id}/auth-user-password-reset/invoke`)
|
||||||
|
|
||||||
|
export const _control = (deviceId: string) => server.get(`/edge/remote/${deviceId}/url`)
|
||||||
|
|
||||||
|
export const _stopControl = (deviceId: string) => server.get(`/edge/remote/${deviceId}/stop`, {})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import server from '@/utils/request'
|
||||||
|
|
||||||
|
export const query = (data: Record<string, any>) => server.post(`/entity/template/_query`, data)
|
||||||
|
|
||||||
|
export const modify = (id: string, data: Record<string, any>) => server.put(`/entity/template/${id}`, data)
|
||||||
|
|
||||||
|
export const _delete = (id: string) => server.remove(`/entity/template/${id}`)
|
||||||
|
|
||||||
|
export const _start = (data: Record<string, any>) => server.post(`/entity/template/start/_batch`, data)
|
||||||
|
|
||||||
|
export const _stop = (data: Record<string, any>) => server.post(`/entity/template/stop/_batch`, data)
|
||||||
|
|
||||||
|
export const queryDeviceList = (data: Record<string, any>) => server.post(`/device-instance/detail/_query`, data)
|
||||||
|
|
|
@ -23,4 +23,13 @@ export const addOperations_api = (data:object) => server.patch(`/application/ope
|
||||||
/**
|
/**
|
||||||
* 删除可授权的接口ID
|
* 删除可授权的接口ID
|
||||||
*/
|
*/
|
||||||
export const delOperations_api = (data:object) => server.remove(`/application/operations/_batch`,{},{data});
|
export const delOperations_api = (data:object) => server.remove(`/application/operations/_batch`,{},{data});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赋权-选中/取消选中api
|
||||||
|
* @param id
|
||||||
|
* @param type
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateOperations_api = (code:string,type:'_add'| '_delete', data: object) => server.post(`/application/${code}/grant/${type}`, data);
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
const color = {
|
||||||
|
'processing': '64, 169, 255',
|
||||||
|
'error': '247, 79, 70',
|
||||||
|
'success': '74, 234, 220',
|
||||||
|
'warning': '250, 178, 71',
|
||||||
|
'default': '63, 73, 96'
|
||||||
|
}
|
||||||
|
export const getHexColor = (code: string, pe: number = 0.3) => {
|
||||||
|
const _color = color[code] || color.default
|
||||||
|
if (code === 'default') {
|
||||||
|
pe = 0.1
|
||||||
|
}
|
||||||
|
return `rgba(${_color}, ${pe})`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default color
|
|
@ -1,12 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<j-badge
|
<j-badge
|
||||||
:status="statusNames ? statusNames[status] : 'default'"
|
:color="_color"
|
||||||
:text="text"
|
:text="text"
|
||||||
></j-badge>
|
></j-badge>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import { StatusColorEnum } from '@/utils/consts.ts';
|
// import { StatusColorEnum } from '@/utils/consts.ts';
|
||||||
|
import { getHexColor } from './color'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
text: {
|
text: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -26,6 +27,18 @@ const props = defineProps({
|
||||||
* 0: 'error'
|
* 0: 'error'
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
statusNames: { type: Object },
|
statusNames: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
'success': 'success',
|
||||||
|
'warning': 'warning',
|
||||||
|
'error': 'error',
|
||||||
|
'default': 'default',
|
||||||
|
})
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const _color = computed(() => {
|
||||||
|
return getHexColor(props.statusNames[props.status], 1)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
<div
|
<div
|
||||||
v-if="showStatus"
|
v-if="showStatus"
|
||||||
class="card-state"
|
class="card-state"
|
||||||
:class="statusNames ? statusNames[status] : ''"
|
:style='{
|
||||||
|
backgroundColor: getHexColor(statusNames[status])
|
||||||
|
}'
|
||||||
>
|
>
|
||||||
<div class="card-state-content">
|
<div class="card-state-content">
|
||||||
<BadgeStatus
|
<BadgeStatus
|
||||||
|
@ -68,9 +70,10 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name='CardBox'>
|
||||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||||
import type { ActionsType } from '@/components/Table/index.vue';
|
import { getHexColor } from '../BadgeStatus/color'
|
||||||
|
import type { ActionsType } from '@/components/Table';
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
type EmitProps = {
|
type EmitProps = {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:request='saveSearchHistory'
|
:request='saveSearchHistory'
|
||||||
:historyRequest='getSearchHistory'
|
:historyRequest='getSearchHistory'
|
||||||
:columns='columns'
|
:columns='columns'
|
||||||
|
:class='props.class'
|
||||||
@search='searchSubmit'
|
@search='searchSubmit'
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup name='JProUpload'>
|
||||||
import { message, UploadChangeParam, UploadProps } from 'ant-design-vue';
|
import { message, UploadChangeParam, UploadProps } from 'ant-design-vue';
|
||||||
import { FILE_UPLOAD } from '@/api/comm';
|
import { FILE_UPLOAD } from '@/api/comm';
|
||||||
import { TOKEN_KEY } from '@/utils/variable';
|
import { TOKEN_KEY } from '@/utils/variable';
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- 参数类型输入组件 -->
|
<!-- 参数类型输入组件 -->
|
||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="value-item-warp">
|
||||||
<j-select
|
<j-select
|
||||||
v-if="typeMap.get(itemType) === 'select'"
|
v-if="typeMap.get(itemType) === 'select'"
|
||||||
v-model:value="myValue"
|
v-model:value="myValue"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
allowClear
|
allowClear
|
||||||
>
|
>
|
||||||
<template #addonAfter>
|
<template #addonAfter>
|
||||||
<j-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
:action="FILE_UPLOAD"
|
:action="FILE_UPLOAD"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
@change="handleFileChange"
|
@change="handleFileChange"
|
||||||
>
|
>
|
||||||
<AIcon type="UploadOutlined" />
|
<AIcon type="UploadOutlined" />
|
||||||
</j-upload>
|
</a-upload>
|
||||||
</template>
|
</template>
|
||||||
</j-input>
|
</j-input>
|
||||||
<j-input
|
<j-input
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name='ValueItem'>
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
import { UploadChangeParam, UploadFile } from 'ant-design-vue';
|
import { UploadChangeParam, UploadFile } from 'ant-design-vue';
|
||||||
import { DefaultOptionType } from 'ant-design-vue/lib/select';
|
import { DefaultOptionType } from 'ant-design-vue/lib/select';
|
||||||
|
@ -102,6 +102,7 @@ import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||||
import { LocalStore } from '@/utils/comm';
|
import { LocalStore } from '@/utils/comm';
|
||||||
import { ItemData, ITypes } from './types';
|
import { ItemData, ITypes } from './types';
|
||||||
import { FILE_UPLOAD } from '@/api/comm';
|
import { FILE_UPLOAD } from '@/api/comm';
|
||||||
|
import { Upload } from 'jetlinks-ui-components'
|
||||||
|
|
||||||
type Emits = {
|
type Emits = {
|
||||||
(e: 'update:modelValue', data: string | number | boolean): void;
|
(e: 'update:modelValue', data: string | number | boolean): void;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import CardBox from './CardBox/index.vue';
|
||||||
import Search from './Search'
|
import Search from './Search'
|
||||||
import NormalUpload from './NormalUpload/index.vue'
|
import NormalUpload from './NormalUpload/index.vue'
|
||||||
import FileFormat from './FileFormat/index.vue'
|
import FileFormat from './FileFormat/index.vue'
|
||||||
import JProUpload from './JUpload/index.vue'
|
import JProUpload from './Upload/index.vue'
|
||||||
import { BasicLayoutPage, BlankLayoutPage } from './Layout'
|
import { BasicLayoutPage, BlankLayoutPage } from './Layout'
|
||||||
import { PageContainer, AIcon } from 'jetlinks-ui-components'
|
import { PageContainer, AIcon } from 'jetlinks-ui-components'
|
||||||
import Ellipsis from './Ellipsis/index.vue'
|
import Ellipsis from './Ellipsis/index.vue'
|
||||||
|
|
|
@ -4,13 +4,14 @@ import store from './store'
|
||||||
import components from './components'
|
import components from './components'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import './style.less'
|
import './style.less'
|
||||||
// import jComponents from 'jetlinks-ui-components'
|
|
||||||
// import 'jetlinks-ui-components/es/style.js'
|
import dayjs from 'dayjs';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
dayjs.locale('zh-cn');
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(store)
|
app.use(store)
|
||||||
.use(router)
|
.use(router)
|
||||||
.use(components)
|
.use(components)
|
||||||
// .use(jComponents)
|
|
||||||
.mount('#app')
|
.mount('#app')
|
||||||
|
|
|
@ -145,6 +145,9 @@ const extraRouteObj = {
|
||||||
{ code: 'Save', name: '详情' },
|
{ code: 'Save', name: '详情' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
'edge/Device': {
|
||||||
|
children: [{ code: 'Remote', name: '远程控制' }],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<!-- 已登录-绑定三方账号 -->
|
<!-- 已登录-绑定三方账号 -->
|
||||||
<template v-if="!token">
|
<template v-if="!token">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<a-card style="width: 280px">
|
<j-card style="width: 280px">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="info-head">
|
<div class="info-head">
|
||||||
<img :src="getImage('/bind/Rectangle.png')" />
|
<img :src="getImage('/bind/Rectangle.png')" />
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
<p>账号:admin</p>
|
<p>账号:admin</p>
|
||||||
<p>用户名:超级管理员</p>
|
<p>用户名:超级管理员</p>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</j-card>
|
||||||
<img :src="getImage('/bind/Vector.png')" />
|
<img :src="getImage('/bind/Vector.png')" />
|
||||||
<a-card style="width: 280px">
|
<j-card style="width: 280px">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="info-head">
|
<div class="info-head">
|
||||||
<img :src="getImage('/bind/Rectangle.png')" />
|
<img :src="getImage('/bind/Rectangle.png')" />
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
<p>用户名:-</p>
|
<p>用户名:-</p>
|
||||||
<p>名称:{{ accountInfo?.name || '-' }}</p>
|
<p>名称:{{ accountInfo?.name || '-' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</j-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
<a-button type="primary" @click="handleBind"
|
<j-button type="primary" @click="handleBind"
|
||||||
>立即绑定</a-button
|
>立即绑定</j-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -60,30 +60,30 @@
|
||||||
你已通过微信授权,完善以下登录信息即可以完成绑定
|
你已通过微信授权,完善以下登录信息即可以完成绑定
|
||||||
</div>
|
</div>
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
<a-form layout="vertical">
|
<j-form layout="vertical">
|
||||||
<a-form-item
|
<j-form-item
|
||||||
label="账户"
|
label="账户"
|
||||||
v-bind="validateInfos.username"
|
v-bind="validateInfos.username"
|
||||||
>
|
>
|
||||||
<a-input
|
<j-input
|
||||||
v-model:value="formData.username"
|
v-model:value="formData.username"
|
||||||
placeholder="请输入账户"
|
placeholder="请输入账户"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</j-form-item>
|
||||||
<a-form-item
|
<j-form-item
|
||||||
label="密码"
|
label="密码"
|
||||||
v-bind="validateInfos.password"
|
v-bind="validateInfos.password"
|
||||||
>
|
>
|
||||||
<a-input-password
|
<j-input-password
|
||||||
v-model:value="formData.password"
|
v-model:value="formData.password"
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</j-form-item>
|
||||||
<a-form-item
|
<j-form-item
|
||||||
label="验证码"
|
label="验证码"
|
||||||
v-bind="validateInfos.verifyCode"
|
v-bind="validateInfos.verifyCode"
|
||||||
>
|
>
|
||||||
<a-input
|
<j-input
|
||||||
v-model:value="formData.verifyCode"
|
v-model:value="formData.verifyCode"
|
||||||
placeholder="请输入验证码"
|
placeholder="请输入验证码"
|
||||||
>
|
>
|
||||||
|
@ -94,18 +94,18 @@
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</j-input>
|
||||||
</a-form-item>
|
</j-form-item>
|
||||||
<a-form-item>
|
<j-form-item>
|
||||||
<a-button
|
<j-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleLoginBind"
|
@click="handleLoginBind"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
登录并绑定账户
|
登录并绑定账户
|
||||||
</a-button>
|
</j-button>
|
||||||
</a-form-item>
|
</j-form-item>
|
||||||
</a-form>
|
</j-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="notification-record-container">
|
<div class="notification-record-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="notification-subscription-container">
|
<div class="notification-subscription-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
|
|
|
@ -1,12 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<j-modal :maskClosable="false" width="800px" :visible="true" title="导入" @ok="handleSave" @cancel="handleCancel">
|
<j-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
width="800px"
|
||||||
|
:visible="true"
|
||||||
|
title="导入"
|
||||||
|
@ok="handleSave"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
<div style="margin-top: 10px">
|
<div style="margin-top: 10px">
|
||||||
<j-form :layout="'vertical'">
|
<j-form :layout="'vertical'">
|
||||||
<j-row>
|
<j-row>
|
||||||
<j-col span="24">
|
<j-col span="24">
|
||||||
<j-form-item label="产品" required>
|
<j-form-item label="产品" required>
|
||||||
<j-select showSearch v-model:value="modelRef.product" placeholder="请选择产品">
|
<j-select
|
||||||
<j-select-option :value="item.id" v-for="item in productList" :key="item.id" :label="item.name">{{ item.name }}</j-select-option>
|
showSearch
|
||||||
|
v-model:value="modelRef.product"
|
||||||
|
placeholder="请选择产品"
|
||||||
|
>
|
||||||
|
<j-select-option
|
||||||
|
:value="item.id"
|
||||||
|
v-for="item in productList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
>{{ item.name }}</j-select-option
|
||||||
|
>
|
||||||
</j-select>
|
</j-select>
|
||||||
</j-form-item>
|
</j-form-item>
|
||||||
</j-col>
|
</j-col>
|
||||||
|
@ -17,7 +34,11 @@
|
||||||
</j-col>
|
</j-col>
|
||||||
<j-col span="12">
|
<j-col span="12">
|
||||||
<j-form-item label="文件上传" v-if="modelRef.product">
|
<j-form-item label="文件上传" v-if="modelRef.product">
|
||||||
<NormalUpload :product="modelRef.product" v-model="modelRef.upload" :file="modelRef.file" />
|
<NormalUpload
|
||||||
|
:product="modelRef.product"
|
||||||
|
v-model="modelRef.upload"
|
||||||
|
:file="modelRef.file"
|
||||||
|
/>
|
||||||
</j-form-item>
|
</j-form-item>
|
||||||
</j-col>
|
</j-col>
|
||||||
</j-row>
|
</j-row>
|
||||||
|
@ -27,16 +48,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { queryNoPagingPost } from '@/api/device/product'
|
import { queryNoPagingPost } from '@/api/device/product';
|
||||||
|
|
||||||
const emit = defineEmits(['close', 'save'])
|
const emit = defineEmits(['close', 'save']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: undefined
|
default: undefined,
|
||||||
}
|
},
|
||||||
})
|
type: String,
|
||||||
const productList = ref<Record<string, any>[]>([])
|
});
|
||||||
|
const productList = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
const modelRef = reactive({
|
const modelRef = reactive({
|
||||||
product: undefined,
|
product: undefined,
|
||||||
|
@ -44,26 +66,40 @@ const modelRef = reactive({
|
||||||
file: {
|
file: {
|
||||||
fileType: 'xlsx',
|
fileType: 'xlsx',
|
||||||
autoDeploy: false,
|
autoDeploy: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.data,
|
() => props.data,
|
||||||
() => {
|
() => {
|
||||||
queryNoPagingPost({paging: false}).then(resp => {
|
queryNoPagingPost({
|
||||||
if(resp.status === 200){
|
paging: false,
|
||||||
productList.value = resp.result as Record<string, any>[]
|
terms: [
|
||||||
|
{
|
||||||
|
column: 'state',
|
||||||
|
value: '1',
|
||||||
|
type: 'and'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
column: 'accessProvider',
|
||||||
|
value: props?.type
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sorts: [{ name: 'createTime', order: 'desc' }]
|
||||||
|
}).then((resp) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
productList.value = resp.result as Record<string, any>[];
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
{immediate: true, deep: true}
|
{ immediate: true, deep: true },
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
emit('close')
|
emit('close');
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
emit('save')
|
emit('save');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
|
@ -289,7 +289,6 @@ import { queryTree } from '@/api/device/category';
|
||||||
import { useMenuStore } from '@/store/menu';
|
import { useMenuStore } from '@/store/menu';
|
||||||
import type { ActionsType } from './typings';
|
import type { ActionsType } from './typings';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { throttle } from 'lodash-es';
|
|
||||||
|
|
||||||
const instanceRef = ref<Record<string, any>>({});
|
const instanceRef = ref<Record<string, any>>({});
|
||||||
const params = ref<Record<string, any>>({});
|
const params = ref<Record<string, any>>({});
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<div class="box">
|
||||||
|
<iframe :src="url" class="box-iframe"></iframe>
|
||||||
|
</div>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { _control, _stopControl } from '@/api/edge/device';
|
||||||
|
|
||||||
|
const url = ref<string>('');
|
||||||
|
const deviceId = ref<string>('');
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => history.state?.params?.id,
|
||||||
|
(newId) => {
|
||||||
|
if (newId) {
|
||||||
|
deviceId.value = newId as string;
|
||||||
|
_control(newId).then((resp: any) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
const item = `http://${resp.result?.url}/#/login?token=${resp.result.token}`;
|
||||||
|
url.value = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (deviceId.value) {
|
||||||
|
_stopControl(unref(deviceId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.box {
|
||||||
|
width: 100%;
|
||||||
|
height: 85vh;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.box-iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,265 @@
|
||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
width="650px"
|
||||||
|
:visible="true"
|
||||||
|
:title="!!data?.id ? '编辑' : '新增'"
|
||||||
|
@ok="handleSave"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:confirmLoading="loading"
|
||||||
|
>
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<j-form :layout="'vertical'" ref="formRef" :model="modelRef">
|
||||||
|
<j-row type="flex">
|
||||||
|
<j-col flex="180px">
|
||||||
|
<j-form-item name="photoUrl">
|
||||||
|
<JProUpload v-model="modelRef.photoUrl" />
|
||||||
|
</j-form-item>
|
||||||
|
</j-col>
|
||||||
|
<j-col flex="auto">
|
||||||
|
<j-form-item
|
||||||
|
name="id"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
pattern: /^[a-zA-Z0-9_\-]+$/,
|
||||||
|
message: '请输入英文或者数字或者-或者_',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
max: 64,
|
||||||
|
message: '最多输入64个字符',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: vailId,
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
ID
|
||||||
|
<j-tooltip
|
||||||
|
title="若不填写,系统将自动生成唯一ID"
|
||||||
|
>
|
||||||
|
<AIcon
|
||||||
|
type="QuestionCircleOutlined"
|
||||||
|
style="margin-left: 2px"
|
||||||
|
/>
|
||||||
|
</j-tooltip>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<j-input
|
||||||
|
v-model:value="modelRef.id"
|
||||||
|
placeholder="请输入ID"
|
||||||
|
:disabled="!!data?.id"
|
||||||
|
/>
|
||||||
|
</j-form-item>
|
||||||
|
<j-form-item
|
||||||
|
label="名称"
|
||||||
|
name="name"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入名称',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
max: 64,
|
||||||
|
message: '最多输入64个字符',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<j-input
|
||||||
|
v-model:value="modelRef.name"
|
||||||
|
placeholder="请输入名称"
|
||||||
|
/>
|
||||||
|
</j-form-item>
|
||||||
|
</j-col>
|
||||||
|
</j-row>
|
||||||
|
<j-row>
|
||||||
|
<j-col :span="22">
|
||||||
|
<j-form-item
|
||||||
|
name="productId"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择所属产品',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span
|
||||||
|
>所属产品
|
||||||
|
<j-tooltip title="只能选择“正常”状态的产品">
|
||||||
|
<AIcon
|
||||||
|
type="QuestionCircleOutlined"
|
||||||
|
style="margin-left: 2px"
|
||||||
|
/>
|
||||||
|
</j-tooltip>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<j-select
|
||||||
|
showSearch
|
||||||
|
v-model:value="modelRef.productId"
|
||||||
|
:disabled="!!data?.id"
|
||||||
|
placeholder="请选择所属产品"
|
||||||
|
>
|
||||||
|
<j-select-option
|
||||||
|
:value="item.id"
|
||||||
|
v-for="item in productList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
>{{ item.name }}</j-select-option
|
||||||
|
>
|
||||||
|
</j-select>
|
||||||
|
</j-form-item>
|
||||||
|
</j-col>
|
||||||
|
<j-col :span="2" style="margin-top: 30px">
|
||||||
|
<PermissionButton
|
||||||
|
type="link"
|
||||||
|
:disabled="data.id"
|
||||||
|
@click="visible = true"
|
||||||
|
hasPermission="device/Product:add"
|
||||||
|
>
|
||||||
|
<AIcon type="PlusOutlined" />
|
||||||
|
</PermissionButton>
|
||||||
|
</j-col>
|
||||||
|
</j-row>
|
||||||
|
<j-form-item
|
||||||
|
label="说明"
|
||||||
|
name="describe"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
max: 200,
|
||||||
|
message: '最多输入200个字符',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<j-textarea
|
||||||
|
v-model:value="modelRef.describe"
|
||||||
|
placeholder="请输入说明"
|
||||||
|
showCount
|
||||||
|
:maxlength="200"
|
||||||
|
/>
|
||||||
|
</j-form-item>
|
||||||
|
</j-form>
|
||||||
|
</div>
|
||||||
|
</j-modal>
|
||||||
|
<SaveProduct
|
||||||
|
v-model:visible="visible"
|
||||||
|
v-model:productId="modelRef.productId"
|
||||||
|
:channel="'official-edge-gateway'"
|
||||||
|
@close="onClose"
|
||||||
|
:deviceType="'gateway'"
|
||||||
|
@save="onSave"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { queryNoPagingPost } from '@/api/device/product';
|
||||||
|
import { isExists, update } from '@/api/device/instance';
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import { message } from 'jetlinks-ui-components';
|
||||||
|
import SaveProduct from '@/views/media/Device/Save/SaveProduct.vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['close', 'save']);
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const productList = ref<Record<string, any>[]>([]);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
|
||||||
|
const formRef = ref();
|
||||||
|
|
||||||
|
const modelRef = reactive({
|
||||||
|
productId: undefined,
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
describe: '',
|
||||||
|
photoUrl: getImage('/device/instance/device-card.png'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const vailId = async (_: Record<string, any>, value: string) => {
|
||||||
|
if (!props?.data?.id && value) {
|
||||||
|
const resp = await isExists(value);
|
||||||
|
if (resp.status === 200 && resp.result) {
|
||||||
|
return Promise.reject('ID重复');
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(newValue) => {
|
||||||
|
queryNoPagingPost({
|
||||||
|
paging: false,
|
||||||
|
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
termType: 'eq',
|
||||||
|
column: 'state',
|
||||||
|
value: 1,
|
||||||
|
type: 'and',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
termType: 'eq',
|
||||||
|
column: 'accessProvider',
|
||||||
|
value: 'official-edge-gateway',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).then((resp) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
productList.value = resp.result as Record<string, any>[];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.assign(modelRef, newValue);
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('close');
|
||||||
|
formRef.value.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSave = (_data: any) => {
|
||||||
|
productList.value.push(_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
formRef.value
|
||||||
|
.validate()
|
||||||
|
.then(async (_data: any) => {
|
||||||
|
loading.value = true;
|
||||||
|
const obj = { ..._data };
|
||||||
|
if (!obj.id) {
|
||||||
|
delete obj.id;
|
||||||
|
}
|
||||||
|
const resp = await update(obj).finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
emit('save');
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
console.log('error', err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,438 @@
|
||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="edge-device"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<JProTable
|
||||||
|
ref="edgeDeviceRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="query"
|
||||||
|
:defaultParams="defaultParams"
|
||||||
|
:params="params"
|
||||||
|
:gridColumn="3"
|
||||||
|
>
|
||||||
|
<template #headerTitle>
|
||||||
|
<j-space>
|
||||||
|
<PermissionButton
|
||||||
|
type="primary"
|
||||||
|
@click="handleAdd"
|
||||||
|
hasPermission="edge/Device:add"
|
||||||
|
>
|
||||||
|
<template #icon><AIcon type="PlusOutlined" /></template>
|
||||||
|
新增
|
||||||
|
</PermissionButton>
|
||||||
|
<PermissionButton
|
||||||
|
@click="importVisible = true"
|
||||||
|
hasPermission="edge/Device:import"
|
||||||
|
>
|
||||||
|
<template #icon
|
||||||
|
><AIcon type="ImportOutlined"
|
||||||
|
/></template>
|
||||||
|
导入
|
||||||
|
</PermissionButton>
|
||||||
|
</j-space>
|
||||||
|
</template>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value="slotProps"
|
||||||
|
:actions="getActions(slotProps, 'card')"
|
||||||
|
:status="slotProps.state?.value"
|
||||||
|
:statusText="slotProps.state?.text"
|
||||||
|
:statusNames="{
|
||||||
|
online: 'success',
|
||||||
|
offline: 'error',
|
||||||
|
notActive: 'warning',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #img>
|
||||||
|
<img
|
||||||
|
:src="getImage('/device/instance/device-card.png')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<Ellipsis style="width: calc(100% - 100px)">
|
||||||
|
<span
|
||||||
|
style="font-size: 16px; font-weight: 600"
|
||||||
|
@click.stop="handleView(slotProps.id)"
|
||||||
|
>
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</span>
|
||||||
|
</Ellipsis>
|
||||||
|
<j-row style="margin-top: 20px">
|
||||||
|
<j-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
设备类型
|
||||||
|
</div>
|
||||||
|
<div>{{ slotProps.deviceType?.text }}</div>
|
||||||
|
</j-col>
|
||||||
|
<j-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
产品名称
|
||||||
|
</div>
|
||||||
|
<Ellipsis style="width: 100%">
|
||||||
|
{{ slotProps.productName }}
|
||||||
|
</Ellipsis>
|
||||||
|
</j-col>
|
||||||
|
</j-row>
|
||||||
|
</template>
|
||||||
|
<template #actions="item">
|
||||||
|
<PermissionButton
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:popConfirm="item.popConfirm"
|
||||||
|
:tooltip="{
|
||||||
|
...item.tooltip,
|
||||||
|
}"
|
||||||
|
@click="item.onClick"
|
||||||
|
:hasPermission="'edge/Device:' + item.key"
|
||||||
|
>
|
||||||
|
<AIcon
|
||||||
|
type="DeleteOutlined"
|
||||||
|
v-if="item.key === 'delete'"
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<AIcon :type="item.icon" />
|
||||||
|
<span>{{ item?.text }}</span>
|
||||||
|
</template>
|
||||||
|
</PermissionButton>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
<template #state="slotProps">
|
||||||
|
<j-badge
|
||||||
|
:text="slotProps.state?.text"
|
||||||
|
:status="statusMap.get(slotProps.state?.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #createTime="slotProps">
|
||||||
|
<span>{{
|
||||||
|
dayjs(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
<template #action="slotProps">
|
||||||
|
<j-space>
|
||||||
|
<template
|
||||||
|
v-for="i in getActions(slotProps, 'table')"
|
||||||
|
:key="i.key"
|
||||||
|
>
|
||||||
|
<PermissionButton
|
||||||
|
:disabled="i.disabled"
|
||||||
|
:popConfirm="i.popConfirm"
|
||||||
|
:tooltip="{
|
||||||
|
...i.tooltip,
|
||||||
|
}"
|
||||||
|
@click="i.onClick"
|
||||||
|
type="link"
|
||||||
|
style="padding: 0 5px"
|
||||||
|
:hasPermission="'edge/Device:' + i.key"
|
||||||
|
>
|
||||||
|
<template #icon><AIcon :type="i.icon" /></template>
|
||||||
|
</PermissionButton>
|
||||||
|
</template>
|
||||||
|
</j-space>
|
||||||
|
</template>
|
||||||
|
</JProTable>
|
||||||
|
<Save
|
||||||
|
v-if="visible"
|
||||||
|
:data="current"
|
||||||
|
@close="visible = false"
|
||||||
|
@save="saveBtn"
|
||||||
|
/>
|
||||||
|
<Import @save="onRefresh" @close="importVisible = false" v-if="importVisible" type="official-edge-gateway" />
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { queryNoPagingPost } from '@/api/device/product';
|
||||||
|
import { queryTree } from '@/api/device/category';
|
||||||
|
import { message } from 'jetlinks-ui-components';
|
||||||
|
import { ActionsType } from '@/views/device/Instance/typings';
|
||||||
|
import { useMenuStore } from '@/store/menu';
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { query, _delete, _deploy, _undeploy } from '@/api/device/instance';
|
||||||
|
import { restPassword } from '@/api/edge/device';
|
||||||
|
import Save from './Save/index.vue';
|
||||||
|
import Import from '@/views/device/Instance/Import/index.vue';
|
||||||
|
|
||||||
|
const menuStory = useMenuStore();
|
||||||
|
|
||||||
|
const defaultParams = {
|
||||||
|
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
column: 'productId$product-info',
|
||||||
|
value: 'accessProvider is official-edge-gateway',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'and',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusMap = new Map();
|
||||||
|
statusMap.set('online', 'success');
|
||||||
|
statusMap.set('offline', 'error');
|
||||||
|
statusMap.set('notActive', 'warning');
|
||||||
|
|
||||||
|
const params = ref<Record<string, any>>({});
|
||||||
|
const edgeDeviceRef = ref<Record<string, any>>({});
|
||||||
|
const importVisible = ref<boolean>(false);
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
const current = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
defaultTermType: 'eq',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
first: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '产品名称',
|
||||||
|
dataIndex: 'productName',
|
||||||
|
key: 'productName',
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
queryNoPagingPost({ paging: false }).then((resp: any) => {
|
||||||
|
resolve(
|
||||||
|
resp.result.map((item: any) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '注册时间',
|
||||||
|
dataIndex: 'registryTime',
|
||||||
|
key: 'registryTime',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'date',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 'notActive' },
|
||||||
|
{ label: '离线', value: 'offline' },
|
||||||
|
{ label: '在线', value: 'online' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'classifiedId',
|
||||||
|
dataIndex: 'classifiedId',
|
||||||
|
title: '产品分类',
|
||||||
|
hideInTable: true,
|
||||||
|
search: {
|
||||||
|
type: 'treeSelect',
|
||||||
|
options: () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
queryTree({ paging: false }).then((resp: any) => {
|
||||||
|
resolve(resp.result);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'deviceType',
|
||||||
|
title: '设备类型',
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '直连设备', value: 'device' },
|
||||||
|
{ label: '网关子设备', value: 'childrenDevice' },
|
||||||
|
{ label: '网关设备', value: 'gateway' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '说明',
|
||||||
|
dataIndex: 'describe',
|
||||||
|
key: 'describe',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 250,
|
||||||
|
scopedSlots: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getActions = (
|
||||||
|
data: Partial<Record<string, any>>,
|
||||||
|
type: 'card' | 'table',
|
||||||
|
): ActionsType[] => {
|
||||||
|
if (!data) return [];
|
||||||
|
const actions = [
|
||||||
|
{
|
||||||
|
key: 'view',
|
||||||
|
text: '查看',
|
||||||
|
tooltip: {
|
||||||
|
title: '查看',
|
||||||
|
},
|
||||||
|
icon: 'EyeOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
handleView(data.id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'update',
|
||||||
|
text: '编辑',
|
||||||
|
tooltip: {
|
||||||
|
title: '编辑',
|
||||||
|
},
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
visible.value = true;
|
||||||
|
current.value = data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'setting',
|
||||||
|
text: '远程控制',
|
||||||
|
tooltip: {
|
||||||
|
title: '远程控制',
|
||||||
|
},
|
||||||
|
icon: 'ControlOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
menuStory.jumpPage('edge/Device/Remote', { id: data.id });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'password',
|
||||||
|
text: '重置密码',
|
||||||
|
tooltip: {
|
||||||
|
title: '重置密码',
|
||||||
|
},
|
||||||
|
icon: 'RedoOutlined',
|
||||||
|
popConfirm: {
|
||||||
|
title: '确认重置密码为P@ssw0rd?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
restPassword(data.id).then((resp: any) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
edgeDeviceRef.value?.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'action',
|
||||||
|
text: data.state?.value !== 'notActive' ? '禁用' : '启用',
|
||||||
|
tooltip: {
|
||||||
|
title: data.state?.value !== 'notActive' ? '禁用' : '启用',
|
||||||
|
},
|
||||||
|
icon:
|
||||||
|
data.state.value !== 'notActive'
|
||||||
|
? 'StopOutlined'
|
||||||
|
: 'CheckCircleOutlined',
|
||||||
|
popConfirm: {
|
||||||
|
title: `确认${
|
||||||
|
data.state.value !== 'notActive' ? '禁用' : '启用'
|
||||||
|
}?`,
|
||||||
|
onConfirm: async () => {
|
||||||
|
let response = undefined;
|
||||||
|
if (data.state.value !== 'notActive') {
|
||||||
|
response = await _undeploy(data.id);
|
||||||
|
} else {
|
||||||
|
response = await _deploy(data.id);
|
||||||
|
}
|
||||||
|
if (response && response.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
edgeDeviceRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
message.error('操作失败!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'delete',
|
||||||
|
text: '删除',
|
||||||
|
disabled: data.state?.value !== 'notActive',
|
||||||
|
tooltip: {
|
||||||
|
title:
|
||||||
|
data.state.value !== 'notActive'
|
||||||
|
? '已启用的设备不能删除'
|
||||||
|
: '删除',
|
||||||
|
},
|
||||||
|
popConfirm: {
|
||||||
|
title: '确认删除?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
const resp = await _delete(data.id);
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
edgeDeviceRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
message.error('操作失败!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
icon: 'DeleteOutlined',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (type === 'card')
|
||||||
|
return actions.filter((i: ActionsType) => i.key !== 'view');
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (_params: any) => {
|
||||||
|
params.value = _params;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleView = (id: string) => {
|
||||||
|
menuStory.jumpPage('device/Instance/Detail', { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
visible.value = true;
|
||||||
|
current.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveBtn = () => {
|
||||||
|
visible.value = false;
|
||||||
|
edgeDeviceRef.value?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRefresh = () => {
|
||||||
|
importVisible.value = false
|
||||||
|
edgeDeviceRef.value?.reload();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,132 @@
|
||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
visible
|
||||||
|
title="下发结果"
|
||||||
|
:width="900"
|
||||||
|
@ok="emit('close')"
|
||||||
|
@cancel="emit('close')"
|
||||||
|
>
|
||||||
|
<j-row>
|
||||||
|
<j-col :span="8">
|
||||||
|
<div>成功:{{ count }}</div>
|
||||||
|
<div>
|
||||||
|
失败:{{ countErr }}
|
||||||
|
<j-button @click="_download(errMessage || '', '下发失败原因')" v-if="errMessage.length" type="link"
|
||||||
|
>下载</j-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</j-col>
|
||||||
|
<j-col :span="8">下发设备数量:{{ list.length || 0 }}</j-col>
|
||||||
|
<j-col :span="8">已下发数量:{{ countErr + count }}</j-col>
|
||||||
|
</j-row>
|
||||||
|
<div v-if="!flag">
|
||||||
|
<j-textarea :rows="20" :value="JSON.stringify(errMessage)" />
|
||||||
|
</div>
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { LocalStore } from '@/utils/comm';
|
||||||
|
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const count = ref<number>(0);
|
||||||
|
const countErr = ref<number>(0);
|
||||||
|
const flag = ref<boolean>(true);
|
||||||
|
const errMessage = ref<any[]>([]);
|
||||||
|
|
||||||
|
const getData = () => {
|
||||||
|
let dt = 0;
|
||||||
|
let et = 0;
|
||||||
|
const errMessages: any[] = [];
|
||||||
|
const _terms = {
|
||||||
|
deviceId: (props.list || []).map((item: any) => item?.id),
|
||||||
|
params: JSON.stringify({
|
||||||
|
name: props.data.name,
|
||||||
|
targetId: props.data.targetId,
|
||||||
|
targetType: props.data.targetType,
|
||||||
|
category: props.data.category,
|
||||||
|
metadata: props.data?.metadata,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const url = new URLSearchParams();
|
||||||
|
Object.keys(_terms).forEach((key) => {
|
||||||
|
if (Array.isArray(_terms[key]) && _terms[key].length) {
|
||||||
|
_terms[key].map((item: string) => {
|
||||||
|
url.append(key, item);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
url.append(key, _terms[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const source = new EventSourcePolyfill(
|
||||||
|
`${BASE_API_PATH}/edge/operations/entity-template-save/invoke/_batch?:X_Access_Token=${LocalStore.get(
|
||||||
|
TOKEN_KEY,
|
||||||
|
)}&${url}`,
|
||||||
|
);
|
||||||
|
source.onmessage = (e: any) => {
|
||||||
|
const res = JSON.parse(e.data);
|
||||||
|
if (res.successful) {
|
||||||
|
dt += 1;
|
||||||
|
count.value = dt;
|
||||||
|
} else {
|
||||||
|
et += 1;
|
||||||
|
countErr.value = et;
|
||||||
|
flag.value = false;
|
||||||
|
if (errMessages.length <= 5) {
|
||||||
|
errMessages.push({ ...res });
|
||||||
|
errMessage.value = [...errMessages];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
source.onerror = () => {
|
||||||
|
source.close();
|
||||||
|
};
|
||||||
|
source.onopen = () => {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const _download = (record: Record<string, any>, fileName: string, format?: string) => {
|
||||||
|
// 创建隐藏的可下载链接
|
||||||
|
const ghostLink = document.createElement('a');
|
||||||
|
ghostLink.download = `${fileName ? '' : record?.name}${fileName}_${dayjs(new Date()).format(
|
||||||
|
format || 'YYYY_MM_DD',
|
||||||
|
)}.txt`;
|
||||||
|
ghostLink.style.display = 'none';
|
||||||
|
//字符串内容转成Blob地址
|
||||||
|
const blob = new Blob([JSON.stringify(record)]);
|
||||||
|
ghostLink.href = URL.createObjectURL(blob);
|
||||||
|
//触发点击
|
||||||
|
document.body.appendChild(ghostLink);
|
||||||
|
ghostLink.click();
|
||||||
|
//移除
|
||||||
|
document.body.removeChild(ghostLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data.id,
|
||||||
|
(newId) => {
|
||||||
|
if(newId){
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,181 @@
|
||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
visible
|
||||||
|
title="下发设备"
|
||||||
|
:width="1000"
|
||||||
|
@ok="onSave"
|
||||||
|
@cancel="onCancel"
|
||||||
|
>
|
||||||
|
<div class="alert">
|
||||||
|
<AIcon
|
||||||
|
type="InfoCircleOutlined"
|
||||||
|
style="margin-right: 10px"
|
||||||
|
/>离线设备无法进行设备模板下发
|
||||||
|
</div>
|
||||||
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="edge-resource-issue"
|
||||||
|
@search="handleSearch"
|
||||||
|
type="simple"
|
||||||
|
class="search"
|
||||||
|
/>
|
||||||
|
<JProTable
|
||||||
|
ref="edgeResourceIssueRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="queryDeviceList"
|
||||||
|
:defaultParams="defaultParams"
|
||||||
|
:params="params"
|
||||||
|
model="TABLE"
|
||||||
|
:bodyStyle="{ padding: 0 }"
|
||||||
|
:rowSelection="{
|
||||||
|
selectedRowKeys: _selectedRowKeys,
|
||||||
|
onChange: onSelectChange,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #state="slotProps">
|
||||||
|
<j-badge
|
||||||
|
:text="slotProps.state?.text"
|
||||||
|
:status="statusMap.get(slotProps.state?.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #sourceId="slotProps">
|
||||||
|
{{ slotProps.sourceName }}
|
||||||
|
</template>
|
||||||
|
<template #registerTime="slotProps">
|
||||||
|
<span>{{
|
||||||
|
dayjs(slotProps.registerTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</JProTable>
|
||||||
|
<Result v-if="visible" :data="props.data" :list="_data" @close="onCancel" />
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onlyMessage } from '@/utils/comm';
|
||||||
|
import { queryDeviceList } from '@/api/edge/resource';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import Result from './Result.vue';
|
||||||
|
|
||||||
|
const defaultParams = {
|
||||||
|
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
termType: 'eq',
|
||||||
|
column: 'productId$product-info',
|
||||||
|
value: 'accessProvider is official-edge-gateway',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'and',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const params = ref({});
|
||||||
|
const edgeResourceIssueRef = ref();
|
||||||
|
const _selectedRowKeys = ref<string[]>([]);
|
||||||
|
const _data = ref<any[]>([]);
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
|
||||||
|
const statusMap = new Map();
|
||||||
|
statusMap.set('online', 'success');
|
||||||
|
statusMap.set('offline', 'error');
|
||||||
|
statusMap.set('notActive', 'warning');
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
ellipsis: true,
|
||||||
|
width: 200,
|
||||||
|
fixed: 'left',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '产品名称',
|
||||||
|
dataIndex: 'productName',
|
||||||
|
key: 'productName',
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备名称',
|
||||||
|
ellipsis: true,
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '注册时间',
|
||||||
|
dataIndex: 'registerTime',
|
||||||
|
key: 'registerTime',
|
||||||
|
width: 200,
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'date',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 'notActive' },
|
||||||
|
{ label: '离线', value: 'offline' },
|
||||||
|
{ label: '在线', value: 'online' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const onSelectChange = (keys: string[], _options: any[]) => {
|
||||||
|
_selectedRowKeys.value = [...keys];
|
||||||
|
_data.value = _options;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (v: any) => {
|
||||||
|
params.value = v;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSave = () => {
|
||||||
|
if(_data.value.length){
|
||||||
|
visible.value = true
|
||||||
|
} else {
|
||||||
|
onlyMessage('请选择设备', 'error')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.search {
|
||||||
|
padding: 0 0 0 24px;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
height: 40px;
|
||||||
|
padding-left: 10px;
|
||||||
|
color: rgba(0, 0, 0, 0.55);
|
||||||
|
line-height: 40px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<j-modal visible title="编辑" :width="700" @ok="onSave" @cancel="onCancel">
|
||||||
|
<MonacoEditor
|
||||||
|
style="width: 100%; height: 370px"
|
||||||
|
theme="vs"
|
||||||
|
v-model="monacoValue"
|
||||||
|
language="json"
|
||||||
|
/>
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import MonacoEditor from '@/components/MonacoEditor/index.vue';
|
||||||
|
import { modify } from '@/api/edge/resource';
|
||||||
|
import { onlyMessage } from '@/utils/comm';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['close', 'save']);
|
||||||
|
|
||||||
|
const monacoValue = ref<string>('{}');
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
monacoValue.value = props.data?.metadata || '{}';
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSave = async () => {
|
||||||
|
const resp = await modify(props.data.id, { metadata: unref(monacoValue) });
|
||||||
|
if (resp.status === 200) {
|
||||||
|
emit('save');
|
||||||
|
onlyMessage('操作成功', 'success');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,383 @@
|
||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="edge-resource"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<JProTable
|
||||||
|
ref="edgeResourceRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="query"
|
||||||
|
:defaultParams="defaultParams"
|
||||||
|
:params="params"
|
||||||
|
>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value="slotProps"
|
||||||
|
:actions="getActions(slotProps, 'card')"
|
||||||
|
:status="slotProps.state?.value"
|
||||||
|
:statusText="slotProps.state?.text"
|
||||||
|
:statusNames="{
|
||||||
|
enabled: 'success',
|
||||||
|
disabled: 'error',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #img>
|
||||||
|
<img
|
||||||
|
:src="getImage('/device/instance/device-card.png')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<Ellipsis style="width: calc(100% - 100px)">
|
||||||
|
<span
|
||||||
|
style="font-size: 16px; font-weight: 600"
|
||||||
|
@click.stop="handleView(slotProps.id)"
|
||||||
|
>
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</span>
|
||||||
|
</Ellipsis>
|
||||||
|
<j-row style="margin-top: 20px">
|
||||||
|
<j-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
通讯协议
|
||||||
|
</div>
|
||||||
|
<Ellipsis>{{
|
||||||
|
options.find(
|
||||||
|
(i) => i.value === slotProps.category,
|
||||||
|
)?.label || slotProps.category
|
||||||
|
}}</Ellipsis>
|
||||||
|
</j-col>
|
||||||
|
<j-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
所属边缘网关
|
||||||
|
</div>
|
||||||
|
<Ellipsis style="width: 100%">
|
||||||
|
{{ slotProps.sourceName }}
|
||||||
|
</Ellipsis>
|
||||||
|
</j-col>
|
||||||
|
</j-row>
|
||||||
|
</template>
|
||||||
|
<template #actions="item">
|
||||||
|
<PermissionButton
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:popConfirm="item.popConfirm"
|
||||||
|
:tooltip="{
|
||||||
|
...item.tooltip,
|
||||||
|
}"
|
||||||
|
@click="item.onClick"
|
||||||
|
:hasPermission="'edge/Resource:' + item.key"
|
||||||
|
>
|
||||||
|
<AIcon
|
||||||
|
type="DeleteOutlined"
|
||||||
|
v-if="item.key === 'delete'"
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<AIcon :type="item.icon" />
|
||||||
|
<span>{{ item?.text }}</span>
|
||||||
|
</template>
|
||||||
|
</PermissionButton>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
<template #state="slotProps">
|
||||||
|
<j-badge
|
||||||
|
:text="slotProps.state?.text"
|
||||||
|
:status="statusMap.get(slotProps.state?.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #sourceId="slotProps">
|
||||||
|
{{ slotProps.sourceName }}
|
||||||
|
</template>
|
||||||
|
<template #category="slotProps">
|
||||||
|
{{
|
||||||
|
options.find((i) => i.value === slotProps.category)
|
||||||
|
?.label || slotProps.category
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
<template #createTime="slotProps">
|
||||||
|
<span>{{
|
||||||
|
dayjs(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
<template #action="slotProps">
|
||||||
|
<j-space>
|
||||||
|
<template
|
||||||
|
v-for="i in getActions(slotProps, 'table')"
|
||||||
|
:key="i.key"
|
||||||
|
>
|
||||||
|
<PermissionButton
|
||||||
|
:disabled="i.disabled"
|
||||||
|
:popConfirm="i.popConfirm"
|
||||||
|
:tooltip="{
|
||||||
|
...i.tooltip,
|
||||||
|
}"
|
||||||
|
@click="i.onClick"
|
||||||
|
type="link"
|
||||||
|
style="padding: 0 5px"
|
||||||
|
:hasPermission="'edge/Resource:' + i.key"
|
||||||
|
>
|
||||||
|
<template #icon><AIcon :type="i.icon" /></template>
|
||||||
|
</PermissionButton>
|
||||||
|
</template>
|
||||||
|
</j-space>
|
||||||
|
</template>
|
||||||
|
</JProTable>
|
||||||
|
<Save
|
||||||
|
v-if="visible"
|
||||||
|
:data="current"
|
||||||
|
@close="visible = false"
|
||||||
|
@save="saveBtn"
|
||||||
|
/>
|
||||||
|
<Issue
|
||||||
|
v-if="settingVisible"
|
||||||
|
:data="current"
|
||||||
|
@close="settingVisible = false"
|
||||||
|
/>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { queryNoPagingPost } from '@/api/device/instance';
|
||||||
|
import { message } from 'jetlinks-ui-components';
|
||||||
|
import { ActionsType } from '@/views/device/Instance/typings';
|
||||||
|
import { useMenuStore } from '@/store/menu';
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { query, _delete, _start, _stop } from '@/api/edge/resource';
|
||||||
|
import Save from './Save/index.vue';
|
||||||
|
import Issue from './Issue/index.vue';
|
||||||
|
|
||||||
|
const menuStory = useMenuStore();
|
||||||
|
|
||||||
|
const defaultParams = { sorts: [{ name: 'createTime', order: 'desc' }] };
|
||||||
|
|
||||||
|
const statusMap = new Map();
|
||||||
|
statusMap.set('enabled', 'success');
|
||||||
|
statusMap.set('disabled', 'error');
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ label: 'UA接入', value: 'OPC_UA' },
|
||||||
|
{ label: 'Modbus TCP接入', value: 'MODBUS_TCP' },
|
||||||
|
{ label: 'S7-200接入', value: 'snap7' },
|
||||||
|
{ label: 'BACnet接入', value: 'BACNetIp' },
|
||||||
|
{ label: 'MODBUS_RTU接入', value: 'MODBUS_RTU' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const params = ref<Record<string, any>>({});
|
||||||
|
const edgeResourceRef = ref<Record<string, any>>({});
|
||||||
|
const settingVisible = ref<boolean>(false);
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
const current = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'category',
|
||||||
|
title: '通信协议',
|
||||||
|
valueType: 'select',
|
||||||
|
scopedSlots: true,
|
||||||
|
key: 'category',
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '所属边缘网关',
|
||||||
|
dataIndex: 'sourceId',
|
||||||
|
key: 'sourceId',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
queryNoPagingPost({
|
||||||
|
paging: false,
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
column: 'productId$product-info',
|
||||||
|
value: 'accessProvider is official-edge-gateway',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'and',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sorts: [
|
||||||
|
{
|
||||||
|
name: 'createTime',
|
||||||
|
order: 'desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).then((resp: any) => {
|
||||||
|
resolve(
|
||||||
|
resp.result.map((item: any) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'date',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 'disabled' },
|
||||||
|
{ label: '正常', value: 'enabled' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 250,
|
||||||
|
scopedSlots: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getActions = (
|
||||||
|
data: Partial<Record<string, any>>,
|
||||||
|
type: 'card' | 'table',
|
||||||
|
): ActionsType[] => {
|
||||||
|
if (!data) return [];
|
||||||
|
const actions = [
|
||||||
|
{
|
||||||
|
key: 'update',
|
||||||
|
text: '编辑',
|
||||||
|
tooltip: {
|
||||||
|
title: '编辑',
|
||||||
|
},
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
visible.value = true;
|
||||||
|
current.value = data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'setting',
|
||||||
|
text: '下发',
|
||||||
|
disabled: data.state?.value === 'disabled',
|
||||||
|
tooltip: {
|
||||||
|
title:
|
||||||
|
data.state.value === 'disabled'
|
||||||
|
? '请先启用,再下发'
|
||||||
|
: '下发',
|
||||||
|
},
|
||||||
|
icon: 'DownSquareOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
settingVisible.value = true;
|
||||||
|
current.value = data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'action',
|
||||||
|
text: data.state?.value !== 'disabled' ? '禁用' : '启用',
|
||||||
|
tooltip: {
|
||||||
|
title: data.state?.value !== 'disabled' ? '禁用' : '启用',
|
||||||
|
},
|
||||||
|
icon:
|
||||||
|
data.state.value !== 'disabled'
|
||||||
|
? 'StopOutlined'
|
||||||
|
: 'CheckCircleOutlined',
|
||||||
|
popConfirm: {
|
||||||
|
title: `确认${
|
||||||
|
data.state.value !== 'disabled' ? '禁用' : '启用'
|
||||||
|
}?`,
|
||||||
|
onConfirm: async () => {
|
||||||
|
let response = undefined;
|
||||||
|
if (data.state.value !== 'disabled') {
|
||||||
|
response = await _stop([data.id]);
|
||||||
|
} else {
|
||||||
|
response = await _start([data.id]);
|
||||||
|
}
|
||||||
|
if (response && response.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
edgeResourceRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
message.error('操作失败!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'delete',
|
||||||
|
text: '删除',
|
||||||
|
disabled: data.state?.value !== 'disabled',
|
||||||
|
tooltip: {
|
||||||
|
title:
|
||||||
|
data.state.value !== 'disabled'
|
||||||
|
? '请先禁用,再删除。'
|
||||||
|
: '删除',
|
||||||
|
},
|
||||||
|
popConfirm: {
|
||||||
|
title: '确认删除?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
const resp = await _delete(data.id);
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
edgeResourceRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
message.error('操作失败!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
icon: 'DeleteOutlined',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (type === 'card')
|
||||||
|
return actions.filter((i: ActionsType) => i.key !== 'view');
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (_params: any) => {
|
||||||
|
params.value = _params;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleView = (id: string) => {
|
||||||
|
menuStory.jumpPage('device/Instance/Detail', { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveBtn = () => {
|
||||||
|
visible.value = false;
|
||||||
|
edgeResourceRef.value?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRefresh = () => {
|
||||||
|
settingVisible.value = false;
|
||||||
|
edgeResourceRef.value?.reload();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
|
@ -1,8 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<a-card class="boot-card-container" :bordered="false">
|
<div class="boot-card-container">
|
||||||
<template #title>
|
<h5 class="title">{{ cardTitle }}</h5>
|
||||||
<h5 class="title">{{ cardTitle }}</h5>
|
|
||||||
</template>
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div
|
<div
|
||||||
class="box-item"
|
class="box-item"
|
||||||
|
@ -23,7 +21,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -46,9 +44,8 @@ const jumpPage = (item: bootConfig) => {
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.boot-card-container {
|
.boot-card-container {
|
||||||
:deep(.ant-card-body) {
|
background-color: #fff;
|
||||||
padding-top: 0;
|
padding: 24px 12px;
|
||||||
}
|
|
||||||
.title {
|
.title {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
<j-row :gutter="24">
|
<j-row :gutter="24">
|
||||||
<j-col :span="12"><DeviceCountCard /></j-col>
|
<j-col :span="12"><DeviceCountCard /></j-col>
|
||||||
<j-col :span="12"><BasicCountCard /></j-col>
|
<j-col :span="12"><BasicCountCard /></j-col>
|
||||||
<j-col :span="24" style="margin-top: 24px">
|
<j-col :span="24" style="margin-top: 24px;">
|
||||||
<PlatformPicCard image="/images/home/content1.png" />
|
<PlatformPicCard image="/images/home/content1.svg" />
|
||||||
</j-col>
|
</j-col>
|
||||||
</j-row>
|
</j-row>
|
||||||
</j-col>
|
</j-col>
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<DeviceChooseDialog
|
<DeviceChooseDialog
|
||||||
v-if="deviceDialogVisible"
|
v-if="deviceDialogVisible"
|
||||||
v-model:visible="deviceDialogVisible"
|
v-model:visible="deviceDialogVisible"
|
||||||
@confirm="(id:string)=>jumpPage('device/Instance/Detail', { id })"
|
@confirm="(id:string)=>jumpPage('device/Instance/Detail', { id, tab: 'Diagnose' })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -157,7 +157,7 @@ const deviceStepDetails: recommendList[] = [
|
||||||
linkUrl: 'device/Instance',
|
linkUrl: 'device/Instance',
|
||||||
auth: devicePermission('import'),
|
auth: devicePermission('import'),
|
||||||
params: {
|
params: {
|
||||||
import: true,
|
type: 'import'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -175,7 +175,7 @@ const opsBootConfig: bootConfig[] = [
|
||||||
label: '日志排查',
|
label: '日志排查',
|
||||||
link: 'Log',
|
link: 'Log',
|
||||||
params: {
|
params: {
|
||||||
key: 'system',
|
tab: 'system',
|
||||||
},
|
},
|
||||||
image: '/images/home/guide-home5.png',
|
image: '/images/home/guide-home5.png',
|
||||||
},
|
},
|
||||||
|
@ -220,7 +220,7 @@ const opsStepDetails: recommendList[] = [
|
||||||
iconUrl: '/images/home/bottom-5.png',
|
iconUrl: '/images/home/bottom-5.png',
|
||||||
linkUrl: 'Log',
|
linkUrl: 'Log',
|
||||||
params: {
|
params: {
|
||||||
key: 'system',
|
tab: 'system',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -39,7 +39,7 @@ const opsBootConfig: bootConfig[] = [
|
||||||
label: '日志排查',
|
label: '日志排查',
|
||||||
link: 'Log',
|
link: 'Log',
|
||||||
params: {
|
params: {
|
||||||
key: 'system',
|
tab: 'system',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -83,7 +83,7 @@ const opsStepDetails: recommendList[] = [
|
||||||
iconUrl: '/images/home/bottom-5.png',
|
iconUrl: '/images/home/bottom-5.png',
|
||||||
linkUrl: 'Log',
|
linkUrl: 'Log',
|
||||||
params: {
|
params: {
|
||||||
key: 'system',
|
tab: 'system',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<DeviceChooseDialog
|
<DeviceChooseDialog
|
||||||
v-if="deviceDialogVisible"
|
v-if="deviceDialogVisible"
|
||||||
v-model:visible="deviceDialogVisible"
|
v-model:visible="deviceDialogVisible"
|
||||||
@confirm="(id:string)=>jumpPage('device/Instance/Detail', { id })"
|
@confirm="(id:string)=>jumpPage('device/Instance/Detail', { id, tab: 'Diagnose' })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,10 +25,11 @@ const props = defineProps({
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-bottom: 1px solid #2f54eb;
|
border-bottom: 1px solid #2f54eb;
|
||||||
|
height: 458px;
|
||||||
.bj {
|
.bj {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
|
|
@ -20,33 +20,35 @@
|
||||||
placeholder="请输入名称"
|
placeholder="请输入名称"
|
||||||
/>
|
/>
|
||||||
</j-form-item>
|
</j-form-item>
|
||||||
<template v-for="(item, index) in extendFormItem" :key="index">
|
<template v-if="deviceType !== 'gateway'">
|
||||||
<j-form-item
|
<template v-for="(item, index) in extendFormItem" :key="index">
|
||||||
:name="item.name"
|
<j-form-item
|
||||||
:label="item.label"
|
:name="item.name"
|
||||||
:rules="{
|
:label="item.label"
|
||||||
required: item.required,
|
:rules="{
|
||||||
message: item.message,
|
required: item.required,
|
||||||
trigger: 'change',
|
message: item.message,
|
||||||
}"
|
trigger: 'change',
|
||||||
>
|
}"
|
||||||
<j-select
|
>
|
||||||
v-if="item.type === 'enum'"
|
<j-select
|
||||||
v-model:value="formData[item.name[0]][item.name[1]]"
|
v-if="item.type === 'enum'"
|
||||||
:options="item.options"
|
v-model:value="formData[item.name[0]][item.name[1]]"
|
||||||
:placeholder="item.message"
|
:options="item.options"
|
||||||
/>
|
:placeholder="item.message"
|
||||||
<j-input-password
|
/>
|
||||||
v-else-if="item.type === 'password'"
|
<j-input-password
|
||||||
v-model:value="formData[item.name[0]][item.name[1]]"
|
v-else-if="item.type === 'password'"
|
||||||
:placeholder="item.message"
|
v-model:value="formData[item.name[0]][item.name[1]]"
|
||||||
/>
|
:placeholder="item.message"
|
||||||
<j-input
|
/>
|
||||||
v-else
|
<j-input
|
||||||
v-model:value="formData[item.name[0]][item.name[1]]"
|
v-else
|
||||||
:placeholder="item.message"
|
v-model:value="formData[item.name[0]][item.name[1]]"
|
||||||
/>
|
:placeholder="item.message"
|
||||||
</j-form-item>
|
/>
|
||||||
|
</j-form-item>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<j-form-item
|
<j-form-item
|
||||||
label="接入网关"
|
label="接入网关"
|
||||||
|
@ -147,6 +149,7 @@ type Emits = {
|
||||||
(e: 'update:visible', data: boolean): void;
|
(e: 'update:visible', data: boolean): void;
|
||||||
(e: 'update:productId', data: string): void;
|
(e: 'update:productId', data: string): void;
|
||||||
(e: 'close'): void;
|
(e: 'close'): void;
|
||||||
|
(e: 'save', data: Record<string, any>): void;
|
||||||
};
|
};
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
@ -154,6 +157,7 @@ const props = defineProps({
|
||||||
visible: { type: Boolean, default: false },
|
visible: { type: Boolean, default: false },
|
||||||
productId: { type: String, default: '' },
|
productId: { type: String, default: '' },
|
||||||
channel: { type: String, default: '' },
|
channel: { type: String, default: '' },
|
||||||
|
deviceType: { type: String, default: 'device' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const _vis = computed({
|
const _vis = computed({
|
||||||
|
@ -186,12 +190,12 @@ const handleClick = async (e: any) => {
|
||||||
formData.value.accessId = e.id;
|
formData.value.accessId = e.id;
|
||||||
formData.value.accessName = e.name;
|
formData.value.accessName = e.name;
|
||||||
formData.value.accessProvider = e.provider;
|
formData.value.accessProvider = e.provider;
|
||||||
formData.value.messageProtocol = e.provider;
|
formData.value.messageProtocol = e.protocolDetail.id;
|
||||||
formData.value.protocolName = e.protocolDetail.name;
|
formData.value.protocolName = e.protocolDetail.name;
|
||||||
formData.value.transportProtocol = e.transport;
|
formData.value.transportProtocol = e.transport;
|
||||||
|
|
||||||
const { result } = await DeviceApi.getConfiguration(
|
const { result } = await DeviceApi.getConfiguration(
|
||||||
props.channel,
|
e.protocol,
|
||||||
e.transport,
|
e.transport,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -233,7 +237,7 @@ const formData = ref({
|
||||||
access_pwd: '',
|
access_pwd: '',
|
||||||
stream_mode: 'UDP',
|
stream_mode: 'UDP',
|
||||||
},
|
},
|
||||||
deviceType: 'device',
|
deviceType: props.deviceType,
|
||||||
messageProtocol: '',
|
messageProtocol: '',
|
||||||
name: '',
|
name: '',
|
||||||
protocolName: '',
|
protocolName: '',
|
||||||
|
@ -256,6 +260,7 @@ const handleOk = () => {
|
||||||
res.result.id,
|
res.result.id,
|
||||||
);
|
);
|
||||||
if (deployResp.success) {
|
if (deployResp.success) {
|
||||||
|
emit('save', {...res.result})
|
||||||
message.success('操作成功');
|
message.success('操作成功');
|
||||||
handleCancel();
|
handleCancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -392,53 +392,53 @@ const formRules = ref({
|
||||||
provider: [{ required: true, message: '请选择类型' }],
|
provider: [{ required: true, message: '请选择类型' }],
|
||||||
// 钉钉
|
// 钉钉
|
||||||
'configuration.appKey': [
|
'configuration.appKey': [
|
||||||
{ required: true, message: '请输入AppKey' },
|
{ required: true, message: '请输入AppKey', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
'configuration.appSecret': [
|
'configuration.appSecret': [
|
||||||
{ required: true, message: '请输入AppSecret' },
|
{ required: true, message: '请输入AppSecret', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
// 'configuration.url': [{ required: true, message: '请输入WebHook' }],
|
// 'configuration.url': [{ required: true, message: '请输入WebHook' }],
|
||||||
// 微信
|
// 微信
|
||||||
'configuration.corpId': [
|
'configuration.corpId': [
|
||||||
{ required: true, message: '请输入corpId' },
|
{ required: true, message: '请输入corpId', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
'configuration.corpSecret': [
|
'configuration.corpSecret': [
|
||||||
{ required: true, message: '请输入corpSecret' },
|
{ required: true, message: '请输入corpSecret', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
// 阿里云语音/短信
|
// 阿里云语音/短信
|
||||||
'configuration.regionId': [
|
'configuration.regionId': [
|
||||||
{ required: true, message: '请输入RegionId' },
|
{ required: true, message: '请输入RegionId', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
'configuration.accessKeyId': [
|
'configuration.accessKeyId': [
|
||||||
{ required: true, message: '请输入AccessKeyId' },
|
{ required: true, message: '请输入AccessKeyId', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
'configuration.secret': [
|
'configuration.secret': [
|
||||||
{ required: true, message: '请输入Secret' },
|
{ required: true, message: '请输入Secret', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
// 邮件
|
// 邮件
|
||||||
'configuration.host': [{ required: true, message: '请输入服务器地址' }],
|
'configuration.host': [{ required: true, message: '请输入服务器地址', trigger: 'blur' }],
|
||||||
'configuration.sender': [
|
'configuration.sender': [
|
||||||
{ required: true, message: '请输入发件人' },
|
{ required: true, message: '请输入发件人', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
'configuration.username': [
|
'configuration.username': [
|
||||||
{ required: true, message: '请输入用户名' },
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
'configuration.password': [
|
'configuration.password': [
|
||||||
{ required: true, message: '请输入密码' },
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
// webhook
|
// webhook
|
||||||
'configuration.url': [
|
'configuration.url': [
|
||||||
{ required: true, message: '请输入Webhook' },
|
{ required: true, message: '请输入Webhook', trigger: 'blur' },
|
||||||
// {
|
// {
|
||||||
// pattern:
|
// pattern:
|
||||||
// /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[j-z]{2,6}\/?/,
|
// /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[j-z]{2,6}\/?/,
|
||||||
|
@ -458,8 +458,6 @@ const getDetail = async () => {
|
||||||
const res = await configApi.detail(route.params.id as string);
|
const res = await configApi.detail(route.params.id as string);
|
||||||
// formData.value = res.result;
|
// formData.value = res.result;
|
||||||
Object.assign(formData.value, res.result);
|
Object.assign(formData.value, res.result);
|
||||||
// console.log('res.result: ', res.result);
|
|
||||||
// console.log('formData.value: ', formData.value);
|
|
||||||
};
|
};
|
||||||
getDetail();
|
getDetail();
|
||||||
|
|
||||||
|
@ -537,7 +535,6 @@ const btnLoading = ref<boolean>(false);
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
validate()
|
validate()
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
// console.log('formData.value: ', formData.value);
|
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
let res;
|
let res;
|
||||||
if (!formData.value.id) {
|
if (!formData.value.id) {
|
||||||
|
@ -545,7 +542,6 @@ const handleSubmit = () => {
|
||||||
} else {
|
} else {
|
||||||
res = await configApi.update(formData.value);
|
res = await configApi.update(formData.value);
|
||||||
}
|
}
|
||||||
// console.log('res: ', res);
|
|
||||||
if (res?.success) {
|
if (res?.success) {
|
||||||
message.success('保存成功');
|
message.success('保存成功');
|
||||||
router.back();
|
router.back();
|
||||||
|
|
|
@ -147,6 +147,19 @@
|
||||||
</template>
|
</template>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
</template>
|
</template>
|
||||||
|
<template #type="slotProps">
|
||||||
|
<span> {{ getMethodTxt(slotProps.type) }}</span>
|
||||||
|
</template>
|
||||||
|
<template #provider="slotProps">
|
||||||
|
<span>
|
||||||
|
{{ getProviderTxt(slotProps.type, slotProps.provider) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<!-- <template #description="slotProps">
|
||||||
|
<Ellipsis>
|
||||||
|
{{ slotProps.description }}
|
||||||
|
</Ellipsis>
|
||||||
|
</template> -->
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<j-space :size="16">
|
<j-space :size="16">
|
||||||
<template
|
<template
|
||||||
|
@ -205,6 +218,7 @@ const columns = [
|
||||||
title: '配置名称',
|
title: '配置名称',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
width: 100,
|
||||||
search: {
|
search: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
@ -214,6 +228,7 @@ const columns = [
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
key: 'type',
|
key: 'type',
|
||||||
scopedSlots: true,
|
scopedSlots: true,
|
||||||
|
width: 100,
|
||||||
search: {
|
search: {
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: NOTICE_METHOD,
|
options: NOTICE_METHOD,
|
||||||
|
@ -227,6 +242,7 @@ const columns = [
|
||||||
dataIndex: 'provider',
|
dataIndex: 'provider',
|
||||||
key: 'provider',
|
key: 'provider',
|
||||||
scopedSlots: true,
|
scopedSlots: true,
|
||||||
|
width: 200,
|
||||||
search: {
|
search: {
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: providerList,
|
options: providerList,
|
||||||
|
@ -239,6 +255,8 @@ const columns = [
|
||||||
title: '说明',
|
title: '说明',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
|
scopedSlots: true,
|
||||||
|
ellipsis: true,
|
||||||
search: {
|
search: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
@ -272,6 +290,14 @@ const getLogo = (type: string, provider: string) => {
|
||||||
const getMethodTxt = (type: string) => {
|
const getMethodTxt = (type: string) => {
|
||||||
return NOTICE_METHOD.find((f) => f.value === type)?.label;
|
return NOTICE_METHOD.find((f) => f.value === type)?.label;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 根据类型展示对应文案
|
||||||
|
* @param type
|
||||||
|
* @param provider
|
||||||
|
*/
|
||||||
|
const getProviderTxt = (type: string, provider: string) => {
|
||||||
|
return MSG_TYPE[type].find((f: any) => f.value === provider)?.label;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增
|
* 新增
|
||||||
|
|
|
@ -172,11 +172,11 @@ const getTemplateDetail = async () => {
|
||||||
formData.value.templateDetailTable = result.variableDefinitions.map(
|
formData.value.templateDetailTable = result.variableDefinitions.map(
|
||||||
(m: any) => ({
|
(m: any) => ({
|
||||||
...m,
|
...m,
|
||||||
type: m.expands ? m.expands.businessType : m.type,
|
type: m.expands?.businessType ? m.expands.businessType : m.type,
|
||||||
value: undefined,
|
value: undefined,
|
||||||
// 电话字段校验
|
// 电话字段校验
|
||||||
otherRules:
|
otherRules:
|
||||||
m.id === 'calledNumber'
|
m.id === 'calledNumber' || m.id === 'phoneNumber'
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
max: 64,
|
max: 64,
|
||||||
|
|
|
@ -895,23 +895,25 @@ watch(
|
||||||
const formRules = ref({
|
const formRules = ref({
|
||||||
type: [{ required: true, message: '请选择通知方式' }],
|
type: [{ required: true, message: '请选择通知方式' }],
|
||||||
name: [
|
name: [
|
||||||
{ required: true, message: '请输入名称' },
|
{ required: true, message: '请输入名称', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
],
|
],
|
||||||
provider: [{ required: true, message: '请选择类型' }],
|
provider: [{ required: true, message: '请选择类型' }],
|
||||||
configId: [{ required: true, message: '请选择绑定配置' }],
|
configId: [{ required: true, message: '请选择绑定配置', trigger: 'blur' }],
|
||||||
// 钉钉
|
// 钉钉
|
||||||
'template.agentId': [
|
'template.agentId': [
|
||||||
{ required: true, message: '请输入AgentId' },
|
{ required: true, message: '请输入AgentId', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
'template.messageType': [{ required: true, message: '请选择消息类型' }],
|
'template.messageType': [
|
||||||
|
{ required: true, message: '请选择消息类型', trigger: 'blur' },
|
||||||
|
],
|
||||||
'template.markdown.title': [
|
'template.markdown.title': [
|
||||||
{ required: true, message: '请输入标题', trigger: 'change' },
|
{ required: true, message: '请输入标题', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
'template.link.title': [
|
'template.link.title': [
|
||||||
{ required: true, message: '请输入标题', trigger: 'change' },
|
{ required: true, message: '请输入标题', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
// 'template.url': [{ required: true, message: '请输入WebHook' }],
|
// 'template.url': [{ required: true, message: '请输入WebHook' }],
|
||||||
|
@ -919,7 +921,7 @@ const formRules = ref({
|
||||||
// 'template.agentId': [{ required: true, message: '请输入AgentId' }],
|
// 'template.agentId': [{ required: true, message: '请输入AgentId' }],
|
||||||
// 邮件
|
// 邮件
|
||||||
'template.subject': [
|
'template.subject': [
|
||||||
{ required: true, message: '请输入标题' },
|
{ required: true, message: '请输入标题', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
'template.sendTo': [
|
'template.sendTo': [
|
||||||
|
@ -946,7 +948,9 @@ const formRules = ref({
|
||||||
],
|
],
|
||||||
// 阿里云语音
|
// 阿里云语音
|
||||||
'template.templateType': [{ required: true, message: '请选择类型' }],
|
'template.templateType': [{ required: true, message: '请选择类型' }],
|
||||||
'template.templateCode': [{ required: true, message: '请输入模板ID' }],
|
'template.templateCode': [
|
||||||
|
{ required: true, message: '请输入模板ID', trigger: 'blur' },
|
||||||
|
],
|
||||||
'template.calledNumber': [
|
'template.calledNumber': [
|
||||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||||
{
|
{
|
||||||
|
@ -980,14 +984,19 @@ const formRules = ref({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// 短信
|
// 短信
|
||||||
'template.code': [{ required: true, message: '请选择模板' }],
|
'template.code': [
|
||||||
'template.signName': [{ required: true, message: '请输入签名' }],
|
{ required: true, message: '请选择模板', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'template.signName': [
|
||||||
|
{ required: true, message: '请输入签名', trigger: 'blur' },
|
||||||
|
],
|
||||||
// webhook
|
// webhook
|
||||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||||
'template.message': [
|
'template.message': [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入模板内容',
|
message: '请输入模板内容',
|
||||||
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
{ max: 500, message: '最多可输入500个字符', trigger: 'change' },
|
{ max: 500, message: '最多可输入500个字符', trigger: 'change' },
|
||||||
],
|
],
|
||||||
|
@ -1073,7 +1082,7 @@ const spliceStr = () => {
|
||||||
variableFieldsStr += formData.value.template.body as string;
|
variableFieldsStr += formData.value.template.body as string;
|
||||||
if (formData.value.provider === 'aliyun')
|
if (formData.value.provider === 'aliyun')
|
||||||
variableFieldsStr += formData.value.template.ttsmessage as string;
|
variableFieldsStr += formData.value.template.ttsmessage as string;
|
||||||
// console.log('variableFieldsStr: ', variableFieldsStr);
|
|
||||||
return variableFieldsStr || '';
|
return variableFieldsStr || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1130,7 +1139,6 @@ const handleMessageTypeChange = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
formData.value.variableDefinitions = [];
|
formData.value.variableDefinitions = [];
|
||||||
// formData.value.template.message = '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1141,7 +1149,6 @@ const getDetail = async () => {
|
||||||
const res = await templateApi.detail(route.params.id as string);
|
const res = await templateApi.detail(route.params.id as string);
|
||||||
// formData.value = res.result;
|
// formData.value = res.result;
|
||||||
Object.assign(formData.value, res.result);
|
Object.assign(formData.value, res.result);
|
||||||
// console.log('formData.value: ', formData.value);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
getDetail();
|
getDetail();
|
||||||
|
@ -1176,8 +1183,7 @@ const handleTypeChange = () => {
|
||||||
const handleProviderChange = () => {
|
const handleProviderChange = () => {
|
||||||
formData.value.template =
|
formData.value.template =
|
||||||
TEMPLATE_FIELD_MAP[formData.value.type][formData.value.provider];
|
TEMPLATE_FIELD_MAP[formData.value.type][formData.value.provider];
|
||||||
// console.log('formData.value: ', formData.value);
|
|
||||||
// console.log('formData.value.template: ', formData.value.template);
|
|
||||||
getConfigList();
|
getConfigList();
|
||||||
resetPublicFiles();
|
resetPublicFiles();
|
||||||
};
|
};
|
||||||
|
@ -1245,7 +1251,6 @@ const handleSubmit = () => {
|
||||||
delete formData.value.template.link;
|
delete formData.value.template.link;
|
||||||
if (formData.value.template.messageType === 'link')
|
if (formData.value.template.messageType === 'link')
|
||||||
delete formData.value.template.markdown;
|
delete formData.value.template.markdown;
|
||||||
// console.log('formData.value: ', formData.value);
|
|
||||||
// 提交必填验证无法通过, 实际已有值, 问题未知, 暂时解决方法: 延迟验证
|
// 提交必填验证无法通过, 实际已有值, 问题未知, 暂时解决方法: 延迟验证
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
validate()
|
validate()
|
||||||
|
@ -1261,13 +1266,11 @@ const handleSubmit = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
let res;
|
|
||||||
if (!formData.value.id) {
|
const res = formData.value.id
|
||||||
res = await templateApi.save(formData.value);
|
? await templateApi.update(formData.value)
|
||||||
} else {
|
: await templateApi.save(formData.value);
|
||||||
res = await templateApi.update(formData.value);
|
|
||||||
}
|
|
||||||
// console.log('res: ', res);
|
|
||||||
if (res?.success) {
|
if (res?.success) {
|
||||||
message.success('保存成功');
|
message.success('保存成功');
|
||||||
router.back();
|
router.back();
|
||||||
|
@ -1281,14 +1284,4 @@ const handleSubmit = () => {
|
||||||
});
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
// test
|
|
||||||
// watch(
|
|
||||||
// () => formData.value,
|
|
||||||
// (val) => {
|
|
||||||
// console.log('formData.value: ', val);
|
|
||||||
// },
|
|
||||||
// { deep: true },
|
|
||||||
// );
|
|
||||||
// test
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -110,14 +110,19 @@
|
||||||
</template>
|
</template>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
</template>
|
</template>
|
||||||
<template #bodyCell="{ column, text, record }">
|
<template #type="slotProps">
|
||||||
<span v-if="column.dataIndex === 'type'">
|
<span> {{ getMethodTxt(slotProps.type) }}</span>
|
||||||
{{ getMethodTxt(record.type) }}
|
</template>
|
||||||
</span>
|
<template #provider="slotProps">
|
||||||
<span v-if="column.dataIndex === 'provider'">
|
<span>
|
||||||
{{ getProviderTxt(record.type, record.provider) }}
|
{{ getProviderTxt(slotProps.type, slotProps.provider) }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- <template #description="slotProps">
|
||||||
|
<Ellipsis>
|
||||||
|
{{ slotProps.description }}
|
||||||
|
</Ellipsis>
|
||||||
|
</template> -->
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<j-space :size="16">
|
<j-space :size="16">
|
||||||
<template
|
<template
|
||||||
|
@ -150,12 +155,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TemplateApi from '@/api/notice/template';
|
import TemplateApi from '@/api/notice/template';
|
||||||
import type { ActionsType } from '@/components/Table/index.vue';
|
import type { ActionsType } from '@/components/Table/index.vue';
|
||||||
// import { getImage, LocalStore } from '@/utils/comm';
|
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
// import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
|
||||||
|
|
||||||
import { NOTICE_METHOD, MSG_TYPE } from '@/views/notice/const';
|
import { NOTICE_METHOD, MSG_TYPE } from '@/views/notice/const';
|
||||||
|
|
||||||
import Debug from './Debug/index.vue';
|
import Debug from './Debug/index.vue';
|
||||||
import Log from './Log/index.vue';
|
import Log from './Log/index.vue';
|
||||||
import { downloadObject } from '@/utils/utils';
|
import { downloadObject } from '@/utils/utils';
|
||||||
|
@ -210,6 +211,8 @@ const columns = [
|
||||||
title: '说明',
|
title: '说明',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
|
scopedSlots: true,
|
||||||
|
ellipsis: true,
|
||||||
search: {
|
search: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
|
|
@ -82,7 +82,7 @@ export const MSG_TYPE = {
|
||||||
],
|
],
|
||||||
email: [
|
email: [
|
||||||
{
|
{
|
||||||
label: 'email',
|
label: '邮件',
|
||||||
value: 'embedded',
|
value: 'embedded',
|
||||||
logo: getImage('/notice/email.png'),
|
logo: getImage('/notice/email.png'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='dropdown-time-picker'>
|
<div class='dropdown-time-picker'>
|
||||||
<j-time-picker
|
<j-time-picker
|
||||||
v-if='type === "time"'
|
v-if='!_type'
|
||||||
open
|
open
|
||||||
class='manual-time-picker'
|
|
||||||
v-model:value='myValue'
|
v-model:value='myValue'
|
||||||
|
class='manual-time-picker'
|
||||||
:format='myFormat'
|
:format='myFormat'
|
||||||
:valueFormat='myFormat'
|
|
||||||
:getPopupContainer='getPopupContainer'
|
:getPopupContainer='getPopupContainer'
|
||||||
popupClassName='manual-time-picker-popup'
|
popupClassName='manual-time-picker-popup'
|
||||||
@change='change'
|
@change='change'
|
||||||
|
@ -17,7 +16,6 @@
|
||||||
class='manual-time-picker'
|
class='manual-time-picker'
|
||||||
v-model:value='myValue'
|
v-model:value='myValue'
|
||||||
:format='myFormat'
|
:format='myFormat'
|
||||||
:valueFormat='myFormat'
|
|
||||||
:getPopupContainer='getPopupContainer'
|
:getPopupContainer='getPopupContainer'
|
||||||
popupClassName='manual-time-picker-popup'
|
popupClassName='manual-time-picker-popup'
|
||||||
@change='change'
|
@change='change'
|
||||||
|
@ -26,7 +24,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts' name='DropdownTime'>
|
<script setup lang='ts' name='DropdownTime'>
|
||||||
import dayjs from 'dayjs'
|
import dayjs, { Dayjs } from 'dayjs'
|
||||||
|
|
||||||
type Emit = {
|
type Emit = {
|
||||||
(e: 'update:value', value: string) : void
|
(e: 'update:value', value: string) : void
|
||||||
|
@ -44,23 +42,26 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
format: {
|
format: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<Emit>()
|
const emit = defineEmits<Emit>()
|
||||||
const myFormat = props.format || ( props.type === 'time' ? 'HH:mm:ss' : 'YYYY-MM-DD HH:mm:ss')
|
const myFormat = props.format || ( props.type === 'time' ? 'HH:mm:ss' : 'YYYY-MM-DD HH:mm:ss')
|
||||||
const myValue = ref(props.value || dayjs(new Date()).format(myFormat))
|
const myValue = ref<Dayjs>(dayjs(props.value || new Date(), myFormat))
|
||||||
|
|
||||||
const getPopupContainer = (trigger: HTMLElement) => {
|
const getPopupContainer = (trigger: HTMLElement) => {
|
||||||
return trigger?.parentNode || document.body
|
return trigger?.parentNode || document.body
|
||||||
}
|
}
|
||||||
|
|
||||||
const change = (e: string) => {
|
const change = (e: Dayjs) => {
|
||||||
myValue.value = e
|
emit('update:value', e.format(myFormat))
|
||||||
emit('update:value', e)
|
emit('change', e.format(myFormat))
|
||||||
emit('change', e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _type = computed(() => {
|
||||||
|
return props.value?.includes('-')
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='less'>
|
<style lang='less'>
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const getComponent = (type: string): string => {
|
||||||
case 'long':
|
case 'long':
|
||||||
case 'float':
|
case 'float':
|
||||||
case 'double':
|
case 'double':
|
||||||
return 'number'
|
return type
|
||||||
case 'metric':
|
case 'metric':
|
||||||
case 'enum':
|
case 'enum':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
@change='timeChange'
|
@change='timeChange'
|
||||||
/>
|
/>
|
||||||
<DropdownMenus
|
<DropdownMenus
|
||||||
v-if='["select","enum", "boolean"].includes(item.component)'
|
v-else-if='["select","enum", "boolean"].includes(item.component)'
|
||||||
:options='["metric", "upper"].includes(item.key) ? metricOption : options'
|
:options='["metric", "upper"].includes(item.key) ? metricOption : options'
|
||||||
@click='onSelect'
|
@click='onSelect'
|
||||||
/>
|
/>
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
<ValueItem
|
<ValueItem
|
||||||
v-else
|
v-else
|
||||||
v-model:modelValue='myValue'
|
v-model:modelValue='myValue'
|
||||||
:itemType='getComponent(item.component)'
|
:itemType='item.component'
|
||||||
:options='item.key === "upper" ? metricOption : options'
|
:options='item.key === "upper" ? metricOption : options'
|
||||||
@change='valueItemChange'
|
@change='valueItemChange'
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1738,7 +1738,6 @@ function changeBackUpload(info: UploadChangeParam<UploadFile<any>>) {
|
||||||
if (info.file.status === 'uploading') {
|
if (info.file.status === 'uploading') {
|
||||||
form.uploadLoading = true;
|
form.uploadLoading = true;
|
||||||
} else if (info.file.status === 'done') {
|
} else if (info.file.status === 'done') {
|
||||||
console.log(info);
|
|
||||||
|
|
||||||
info.file.url = info.file.response?.result;
|
info.file.url = info.file.response?.result;
|
||||||
form.uploadLoading = false;
|
form.uploadLoading = false;
|
||||||
|
@ -1749,9 +1748,6 @@ function changeBackUpload(info: UploadChangeParam<UploadFile<any>>) {
|
||||||
message.error('logo上传失败,请稍后再试');
|
message.error('logo上传失败,请稍后再试');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function test(...args: any[]) {
|
|
||||||
console.log('test:', args);
|
|
||||||
}
|
|
||||||
function clearNullProp(obj: object) {
|
function clearNullProp(obj: object) {
|
||||||
if (typeof obj !== 'object') return;
|
if (typeof obj !== 'object') return;
|
||||||
for (const prop in obj) {
|
for (const prop in obj) {
|
||||||
|
@ -1799,6 +1795,17 @@ function clearNullProp(obj: object) {
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&.ant-radio-button-wrapper-disabled {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-radio-button-wrapper-checked {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #1d39c4;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
> :last-child {
|
> :last-child {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="apply-container">
|
<div class="apply-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -270,6 +271,8 @@ const columns = [
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
scopedSlots: true,
|
scopedSlots: true,
|
||||||
|
width:'200px',
|
||||||
|
fixed:'right'
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const queryParams = ref({});
|
const queryParams = ref({});
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="data-source-container">
|
<div class="data-source-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<a-modal
|
<j-modal
|
||||||
class="add-device-or-product-dialog-container"
|
class="add-device-or-product-dialog-container"
|
||||||
title="绑定"
|
title="绑定"
|
||||||
width="1440px"
|
width="1440px"
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span style="margin-right: 8px">批量配置</span>
|
<span style="margin-right: 8px">批量配置</span>
|
||||||
<a-switch
|
<j-switch
|
||||||
v-model:checked="bulkBool"
|
v-model:checked="bulkBool"
|
||||||
checked-children="开"
|
checked-children="开"
|
||||||
un-checked-children="关"
|
un-checked-children="关"
|
||||||
|
@ -23,16 +23,19 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="bulkBool">
|
<div v-show="bulkBool">
|
||||||
<a-checkbox-group v-model:value="bulkList" :options="options" />
|
<j-checkbox-group v-model:value="bulkList" :options="options" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Search :columns="props.queryColumns" @search="query.search" />
|
<pro-search
|
||||||
|
:columns="props.queryColumns"
|
||||||
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
|
/>
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:request="table.requestFun"
|
:request="table.requestFun"
|
||||||
:gridColumn="2"
|
:gridColumn="2"
|
||||||
:params="query.params.value"
|
:params="queryParams"
|
||||||
:rowSelection="{
|
:rowSelection="{
|
||||||
selectedRowKeys: table._selectedRowKeys.value,
|
selectedRowKeys: table._selectedRowKeys.value,
|
||||||
onChange: selectRow,
|
onChange: selectRow,
|
||||||
|
@ -69,8 +72,8 @@
|
||||||
<h3 class="card-item-content-title">
|
<h3 class="card-item-content-title">
|
||||||
{{ slotProps.name }}
|
{{ slotProps.name }}
|
||||||
</h3>
|
</h3>
|
||||||
<a-row>
|
<j-row>
|
||||||
<a-col :span="12">
|
<j-col :span="12">
|
||||||
<div class="card-item-content-text">ID</div>
|
<div class="card-item-content-text">ID</div>
|
||||||
<div
|
<div
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
|
@ -78,8 +81,8 @@
|
||||||
>
|
>
|
||||||
{{ slotProps.id }}
|
{{ slotProps.id }}
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</j-col>
|
||||||
<a-col :span="12">
|
<j-col :span="12">
|
||||||
<div class="card-item-content-text">
|
<div class="card-item-content-text">
|
||||||
资产权限
|
资产权限
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,15 +91,15 @@
|
||||||
class="card-item-content-value"
|
class="card-item-content-value"
|
||||||
@click="(e) => e.stopPropagation()"
|
@click="(e) => e.stopPropagation()"
|
||||||
>
|
>
|
||||||
<a-checkbox-group
|
<j-checkbox-group
|
||||||
v-model:value="
|
v-model:value="
|
||||||
slotProps.selectPermissions
|
slotProps.selectPermissions
|
||||||
"
|
"
|
||||||
:options="slotProps.permissionList"
|
:options="slotProps.permissionList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</j-col>
|
||||||
</a-row>
|
</j-row>
|
||||||
</template>
|
</template>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
</template>
|
</template>
|
||||||
|
@ -107,7 +110,7 @@
|
||||||
class="card-item-content-value"
|
class="card-item-content-value"
|
||||||
@click="(e) => e.stopPropagation()"
|
@click="(e) => e.stopPropagation()"
|
||||||
>
|
>
|
||||||
<a-checkbox-group
|
<j-checkbox-group
|
||||||
v-model:value="slotProps.selectPermissions"
|
v-model:value="slotProps.selectPermissions"
|
||||||
:options="slotProps.permissionList"
|
:options="slotProps.permissionList"
|
||||||
/>
|
/>
|
||||||
|
@ -125,7 +128,7 @@
|
||||||
></BadgeStatus>
|
></BadgeStatus>
|
||||||
</template>
|
</template>
|
||||||
</j-pro-table>
|
</j-pro-table>
|
||||||
</a-modal>
|
</j-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -189,58 +192,8 @@ const options = computed(() =>
|
||||||
const columns = props.queryColumns.filter(
|
const columns = props.queryColumns.filter(
|
||||||
(item) => item.dataIndex !== 'action',
|
(item) => item.dataIndex !== 'action',
|
||||||
);
|
);
|
||||||
const query = {
|
|
||||||
columns: [
|
const queryParams = ref({});
|
||||||
{
|
|
||||||
title: 'ID',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'id',
|
|
||||||
ellipsis: true,
|
|
||||||
fixed: 'left',
|
|
||||||
search: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '名称',
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name',
|
|
||||||
ellipsis: true,
|
|
||||||
fixed: 'left',
|
|
||||||
search: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
dataIndex: 'state',
|
|
||||||
key: 'state',
|
|
||||||
ellipsis: true,
|
|
||||||
fixed: 'left',
|
|
||||||
search: {
|
|
||||||
type: 'select',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: '在线',
|
|
||||||
value: 'online',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '离线',
|
|
||||||
value: 'offline',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '禁用',
|
|
||||||
value: 'notActive',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
params: ref({}),
|
|
||||||
search: (params: any) => {
|
|
||||||
query.params.value = params;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const table: any = {
|
const table: any = {
|
||||||
_selectedRowKeys: ref<string[]>([]), // 选中项的id
|
_selectedRowKeys: ref<string[]>([]), // 选中项的id
|
||||||
backRowKeys: [] as string[], // 旧选中项的id
|
backRowKeys: [] as string[], // 旧选中项的id
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
>
|
>
|
||||||
<j-form ref="formRef" :model="form.data" layout="vertical">
|
<j-form ref="formRef" :model="form.data" layout="vertical">
|
||||||
<j-form-item name="parentId" label="上级组织">
|
<j-form-item name="parentId" label="上级组织">
|
||||||
<a-tree-select
|
<j-tree-select
|
||||||
v-model:value="form.data.parentId"
|
v-model:value="form.data.parentId"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择上级组织"
|
placeholder="请选择上级组织"
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
:field-names="{ value: 'id' }"
|
:field-names="{ value: 'id' }"
|
||||||
>
|
>
|
||||||
<template #title="{ name }"> {{ name }} </template>
|
<template #title="{ name }"> {{ name }} </template>
|
||||||
</a-tree-select>
|
</j-tree-select>
|
||||||
</j-form-item>
|
</j-form-item>
|
||||||
<j-form-item
|
<j-form-item
|
||||||
name="name"
|
name="name"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-tree
|
<jTree
|
||||||
:tree-data="treeData"
|
:tree-data="treeData"
|
||||||
v-model:selected-keys="selectedKeys"
|
v-model:selected-keys="selectedKeys"
|
||||||
:fieldNames="{ key: 'id' }"
|
:fieldNames="{ key: 'id' }"
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</a-tree>
|
</jTree>
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
<!-- 编辑弹窗 -->
|
||||||
<EditDepartmentDialog
|
<EditDepartmentDialog
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="product-container">
|
<div class="product-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@search="(params:any) => (queryParams = params)"
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
|
@ -153,7 +154,7 @@
|
||||||
></BadgeStatus>
|
></BadgeStatus>
|
||||||
</template>
|
</template>
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<a-space :size="16">
|
<j-space :size="16">
|
||||||
<PermissionButton
|
<PermissionButton
|
||||||
v-for="i in table.getActions(slotProps, 'table')"
|
v-for="i in table.getActions(slotProps, 'table')"
|
||||||
:uhasPermission="i.permission"
|
:uhasPermission="i.permission"
|
||||||
|
@ -165,7 +166,7 @@
|
||||||
>
|
>
|
||||||
<AIcon :type="i.icon" />
|
<AIcon :type="i.icon" />
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
</a-space>
|
</j-space>
|
||||||
</template>
|
</template>
|
||||||
</j-pro-table>
|
</j-pro-table>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="product-container">
|
<div class="product-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
|
@ -113,35 +114,35 @@
|
||||||
</j-row>
|
</j-row>
|
||||||
</template>
|
</template>
|
||||||
<template #actions="item">
|
<template #actions="item">
|
||||||
<a-tooltip
|
<j-tooltip
|
||||||
v-bind="item.tooltip"
|
v-bind="item.tooltip"
|
||||||
:title="item.disabled && item.tooltip.title"
|
:title="item.disabled && item.tooltip.title"
|
||||||
>
|
>
|
||||||
<a-dropdown
|
<j-dropdown
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
v-if="item.key === 'others'"
|
v-if="item.key === 'others'"
|
||||||
>
|
>
|
||||||
<a-button>
|
<j-button>
|
||||||
<AIcon :type="item.icon" />
|
<AIcon :type="item.icon" />
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
</a-button>
|
</j-button>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<j-menu>
|
||||||
<a-menu-item
|
<j-menu-item
|
||||||
v-for="(o, i) in item.children"
|
v-for="(o, i) in item.children"
|
||||||
:key="i"
|
:key="i"
|
||||||
>
|
>
|
||||||
<a-button
|
<j-button
|
||||||
type="link"
|
type="link"
|
||||||
@click="o.onClick"
|
@click="o.onClick"
|
||||||
>
|
>
|
||||||
<AIcon :type="o.icon" />
|
<AIcon :type="o.icon" />
|
||||||
<span>{{ o.text }}</span>
|
<span>{{ o.text }}</span>
|
||||||
</a-button>
|
</j-button>
|
||||||
</a-menu-item>
|
</j-menu-item>
|
||||||
</a-menu>
|
</j-menu>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</j-dropdown>
|
||||||
<PermissionButton
|
<PermissionButton
|
||||||
v-else
|
v-else
|
||||||
:hasPermission="item.permission"
|
:hasPermission="item.permission"
|
||||||
|
@ -155,7 +156,7 @@
|
||||||
item.text
|
item.text
|
||||||
}}</span>
|
}}</span>
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
</a-tooltip>
|
</j-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
</template>
|
</template>
|
||||||
|
@ -178,7 +179,7 @@
|
||||||
></BadgeStatus>
|
></BadgeStatus>
|
||||||
</template>
|
</template>
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<a-space :size="16">
|
<j-space :size="16">
|
||||||
<PermissionButton
|
<PermissionButton
|
||||||
v-for="i in table.getActions(slotProps, 'table')"
|
v-for="i in table.getActions(slotProps, 'table')"
|
||||||
:hasPermission="i.permission"
|
:hasPermission="i.permission"
|
||||||
|
@ -190,7 +191,7 @@
|
||||||
>
|
>
|
||||||
<AIcon :type="i.icon" />
|
<AIcon :type="i.icon" />
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
</a-space>
|
</j-space>
|
||||||
</template>
|
</template>
|
||||||
</j-pro-table>
|
</j-pro-table>
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,17 @@
|
||||||
@ok="confirm"
|
@ok="confirm"
|
||||||
@cancel="emits('update:visible', false)"
|
@cancel="emits('update:visible', false)"
|
||||||
>
|
>
|
||||||
<Search :columns="query.columns" @search="query.search" />
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
|
/>
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:columns="table.columns"
|
:columns="columns"
|
||||||
:request="table.requestFun"
|
:request="table.requestFun"
|
||||||
:params="query.params"
|
:params="queryParams"
|
||||||
:rowSelection="{
|
:rowSelection="{
|
||||||
selectedRowKeys: table._selectedRowKeys,
|
selectedRowKeys: table._selectedRowKeys,
|
||||||
onChange: table.onSelectChange,
|
onChange: table.onSelectChange,
|
||||||
|
@ -57,47 +61,28 @@ const confirm = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const query = {
|
const columns = [
|
||||||
columns: [
|
{
|
||||||
{
|
title: '姓名',
|
||||||
title: '姓名',
|
dataIndex: 'name',
|
||||||
dataIndex: 'name',
|
key: 'name',
|
||||||
key: 'name',
|
ellipsis: true,
|
||||||
ellipsis: true,
|
search: {
|
||||||
fixed: 'left',
|
type: 'string',
|
||||||
search: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: '用户名',
|
|
||||||
dataIndex: 'username',
|
|
||||||
key: 'username',
|
|
||||||
ellipsis: true,
|
|
||||||
fixed: 'left',
|
|
||||||
search: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
params: ref({}),
|
|
||||||
search: (params: any) => {
|
|
||||||
query.params.value = params;
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
title: '用户名',
|
||||||
|
dataIndex: 'username',
|
||||||
|
key: 'username',
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const queryParams = ref({});
|
||||||
const table = reactive({
|
const table = reactive({
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: '姓名',
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用户名',
|
|
||||||
dataIndex: 'username',
|
|
||||||
key: 'username',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
_selectedRowKeys: [] as string[],
|
_selectedRowKeys: [] as string[],
|
||||||
|
|
||||||
requestFun: async (oParams: any) => {
|
requestFun: async (oParams: any) => {
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<j-advanced-search :columns="columns" @search="(p:any)=>params = p" />
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
|
/>
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:request="table.requestFun"
|
:request="table.requestFun"
|
||||||
:params="params"
|
:params="queryParams"
|
||||||
:rowSelection="{
|
:rowSelection="{
|
||||||
selectedRowKeys: table._selectedRowKeys,
|
selectedRowKeys: table._selectedRowKeys,
|
||||||
onChange: table.onSelectChange,
|
onChange: table.onSelectChange,
|
||||||
|
@ -137,7 +140,7 @@ const columns = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
// 搜索参数
|
// 搜索参数
|
||||||
const params = ref({});
|
const queryParams = ref({});
|
||||||
|
|
||||||
// 表格
|
// 表格
|
||||||
const tableRef = ref<Record<string, any>>({}); // 表格实例
|
const tableRef = ref<Record<string, any>>({}); // 表格实例
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="menu-container">
|
<div class="menu-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -202,7 +203,7 @@ const table = reactive({
|
||||||
},
|
},
|
||||||
addChildren: (row: any) => {
|
addChildren: (row: any) => {
|
||||||
const sortIndex = row?.children?.length || 0;
|
const sortIndex = row?.children?.length || 0;
|
||||||
|
|
||||||
router.push(
|
router.push(
|
||||||
`/system/Menu/detail/:id?pid=${row.id}&basePath=${
|
`/system/Menu/detail/:id?pid=${row.id}&basePath=${
|
||||||
row.url || ''
|
row.url || ''
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="permission-container">
|
<div class="permission-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@search="(params:any) => (queryParams = params)"
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
|
|
|
@ -148,7 +148,9 @@ const requestCard = reactive<tableCardType>({
|
||||||
return (requestCard.tableData = props.selectApi.parameters);
|
return (requestCard.tableData = props.selectApi.parameters);
|
||||||
const schema =
|
const schema =
|
||||||
props.selectApi.requestBody.content['application/json'].schema;
|
props.selectApi.requestBody.content['application/json'].schema;
|
||||||
const schemaName = (schema.$ref || schema.items.$ref)?.split('/').pop();
|
const _ref = schema.$ref || schema?.items?.$ref;
|
||||||
|
if(!_ref) return; // schema不是Java中的类的话则不进行解析,直接结束
|
||||||
|
const schemaName = _ref?.split('/').pop();
|
||||||
const type = schema.type || '';
|
const type = schema.type || '';
|
||||||
const tableData = findData(schemaName);
|
const tableData = findData(schemaName);
|
||||||
if (type === 'array') {
|
if (type === 'array') {
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
</j-button>
|
</j-button>
|
||||||
</div>
|
</div>
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
|
v-if="refStr"
|
||||||
v-model:modelValue="requestBody.code"
|
v-model:modelValue="requestBody.code"
|
||||||
style="height: 300px; width: 100%"
|
style="height: 300px; width: 100%"
|
||||||
theme="vs"
|
theme="vs"
|
||||||
|
@ -125,6 +126,8 @@ const props = defineProps<{
|
||||||
selectApi: apiDetailsType;
|
selectApi: apiDetailsType;
|
||||||
schemas: any;
|
schemas: any;
|
||||||
}>();
|
}>();
|
||||||
|
const responsesContent = ref({});
|
||||||
|
const editorRef = ref();
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const requestBody = reactive({
|
const requestBody = reactive({
|
||||||
tableColumns: [
|
tableColumns: [
|
||||||
|
@ -178,8 +181,16 @@ const paramsTable = computed(() => {
|
||||||
return requestBody.params.paramsTable.slice(startIndex, endIndex);
|
return requestBody.params.paramsTable.slice(startIndex, endIndex);
|
||||||
});
|
});
|
||||||
|
|
||||||
const responsesContent = ref({});
|
let schema: any = {};
|
||||||
const editorRef = ref()
|
const refStr = ref('');
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
if (!props.selectApi.requestBody) return;
|
||||||
|
schema = props.selectApi.requestBody.content['application/json'].schema;
|
||||||
|
refStr.value = schema.$ref || schema?.items?.$ref;
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
|
||||||
const send = () => {
|
const send = () => {
|
||||||
if (paramsTable.value.length)
|
if (paramsTable.value.length)
|
||||||
formRef.value &&
|
formRef.value &&
|
||||||
|
@ -210,10 +221,10 @@ const _send = () => {
|
||||||
...urlParams,
|
...urlParams,
|
||||||
};
|
};
|
||||||
server[methodObj[methodName]](url, params).then((resp: any) => {
|
server[methodObj[methodName]](url, params).then((resp: any) => {
|
||||||
if (Object.keys(params).length === 0){
|
// 如果用户没填写参数且有body的情况下,给用户展示请求示例
|
||||||
|
if (Object.keys(params).length === 0 && refStr.value) {
|
||||||
requestBody.code = JSON.stringify(getDefaultParams());
|
requestBody.code = JSON.stringify(getDefaultParams());
|
||||||
editorRef.value?.editorFormat()
|
editorRef.value?.editorFormat();
|
||||||
}
|
}
|
||||||
responsesContent.value = resp;
|
responsesContent.value = resp;
|
||||||
});
|
});
|
||||||
|
@ -224,9 +235,8 @@ const _send = () => {
|
||||||
*/
|
*/
|
||||||
function getDefaultParams() {
|
function getDefaultParams() {
|
||||||
if (!props.selectApi.requestBody) return {};
|
if (!props.selectApi.requestBody) return {};
|
||||||
const schema =
|
if (!refStr.value) return ''; // schema不是Java中的类的话则不进行解析,直接结束
|
||||||
props.selectApi.requestBody.content['application/json'].schema;
|
const schemaName = refStr.value?.split('/').pop() as string;
|
||||||
const schemaName = (schema.$ref || schema.items.$ref)?.split('/').pop();
|
|
||||||
const type = schema.type || '';
|
const type = schema.type || '';
|
||||||
const tableData = findData(schemaName);
|
const tableData = findData(schemaName);
|
||||||
if (type === 'array') {
|
if (type === 'array') {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<template #url="slotProps">
|
<template #url="slotProps">
|
||||||
<span
|
<span
|
||||||
style="color: #1d39c4; cursor: pointer"
|
style="color: #1d39c4; cursor: pointer"
|
||||||
@click="jump(slotProps)"
|
@click="emits('update:clickApi', slotProps)"
|
||||||
>{{ slotProps.url }}</span
|
>{{ slotProps.url }}</span
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
@ -25,18 +25,28 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { addOperations_api, delOperations_api } from '@/api/system/apiPage';
|
import {
|
||||||
|
addOperations_api,
|
||||||
|
delOperations_api,
|
||||||
|
updateOperations_api,
|
||||||
|
} from '@/api/system/apiPage';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
import { modeType } from '../typing';
|
import { modeType } from '../typing';
|
||||||
const emits = defineEmits(['update:clickApi', 'update:selectedRowKeys']);
|
const emits = defineEmits([
|
||||||
|
'refresh',
|
||||||
|
'update:clickApi',
|
||||||
|
'update:selectedRowKeys',
|
||||||
|
'update:changedApis',
|
||||||
|
]);
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tableData: any[];
|
tableData: any[];
|
||||||
clickApi: any;
|
clickApi: any;
|
||||||
selectedRowKeys: string[];
|
selectedRowKeys: string[];
|
||||||
sourceKeys: string[];
|
sourceKeys: string[];
|
||||||
mode: modeType;
|
mode: modeType;
|
||||||
|
changedApis: any; // 产生变化的api项
|
||||||
}>();
|
}>();
|
||||||
|
const code = useRoute().query.code as string;
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'API',
|
title: 'API',
|
||||||
|
@ -52,13 +62,20 @@ const columns = [
|
||||||
];
|
];
|
||||||
const rowSelection = {
|
const rowSelection = {
|
||||||
onSelect: (record: any) => {
|
onSelect: (record: any) => {
|
||||||
|
const targetId = record.id;
|
||||||
let newKeys = [...props.selectedRowKeys];
|
let newKeys = [...props.selectedRowKeys];
|
||||||
|
|
||||||
if (props.selectedRowKeys.includes(record.id)) {
|
if (props.selectedRowKeys.includes(targetId)) {
|
||||||
newKeys = newKeys.filter((id) => id !== record.id);
|
newKeys = newKeys.filter((id) => id !== targetId);
|
||||||
} else newKeys.push(record.id);
|
} else newKeys.push(targetId);
|
||||||
|
|
||||||
emits('update:selectedRowKeys', newKeys);
|
emits('update:selectedRowKeys', newKeys);
|
||||||
|
if (props.mode === 'appManger') {
|
||||||
|
emits('update:changedApis', {
|
||||||
|
...props.changedApis,
|
||||||
|
[record.id]: record,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectedRowKeys: ref<string[]>([]),
|
selectedRowKeys: ref<string[]>([]),
|
||||||
};
|
};
|
||||||
|
@ -73,13 +90,30 @@ const save = () => {
|
||||||
removeKeys.length &&
|
removeKeys.length &&
|
||||||
delOperations_api(removeKeys)
|
delOperations_api(removeKeys)
|
||||||
.finally(() => addOperations_api(addKeys))
|
.finally(() => addOperations_api(addKeys))
|
||||||
.then(() => message.success('操作成功'));
|
.then(() => {
|
||||||
|
message.success('操作成功');
|
||||||
|
emits('refresh')
|
||||||
|
});
|
||||||
|
} else if (props.mode === 'appManger') {
|
||||||
|
const removeItems = removeKeys.map((key) => ({
|
||||||
|
id: key,
|
||||||
|
permissions: props.changedApis[key]?.security,
|
||||||
|
}));
|
||||||
|
const addItems = addKeys.map((key) => ({
|
||||||
|
id: key,
|
||||||
|
permissions: props.changedApis[key]?.security,
|
||||||
|
}));
|
||||||
|
Promise.all([
|
||||||
|
updateOperations_api(code, '_delete', { operations: removeItems }),
|
||||||
|
updateOperations_api(code, '_add', { operations: addItems }),
|
||||||
|
]).then((resps) => {
|
||||||
|
if (resps[0].status === 200 && resps[1].status === 200) {
|
||||||
|
message.success('操作成功');
|
||||||
|
emits('refresh');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const jump = (row: any) => {
|
|
||||||
emits('update:clickApi', row);
|
|
||||||
};
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.selectedRowKeys,
|
() => props.selectedRowKeys,
|
||||||
(n) => {
|
(n) => {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
@select="treeSelect"
|
@select="treeSelect"
|
||||||
:mode="props.mode"
|
:mode="props.mode"
|
||||||
:has-home="props.hasHome"
|
:has-home="props.hasHome"
|
||||||
:filter-array="treeFilter"
|
|
||||||
:code="props.code"
|
:code="props.code"
|
||||||
/>
|
/>
|
||||||
</j-col>
|
</j-col>
|
||||||
|
@ -26,10 +25,12 @@
|
||||||
<ChooseApi
|
<ChooseApi
|
||||||
v-show="!selectedApi.url"
|
v-show="!selectedApi.url"
|
||||||
v-model:click-api="selectedApi"
|
v-model:click-api="selectedApi"
|
||||||
:table-data="tableData"
|
|
||||||
v-model:selectedRowKeys="selectedKeys"
|
v-model:selectedRowKeys="selectedKeys"
|
||||||
|
v-model:changedApis="changedApis"
|
||||||
|
:table-data="tableData"
|
||||||
:source-keys="selectSourceKeys"
|
:source-keys="selectSourceKeys"
|
||||||
:mode="props.mode"
|
:mode="props.mode"
|
||||||
|
@refresh="getSelectKeys"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -82,9 +83,8 @@ const props = defineProps<{
|
||||||
hasHome?: boolean;
|
hasHome?: boolean;
|
||||||
code?: string;
|
code?: string;
|
||||||
}>();
|
}>();
|
||||||
const showHome = ref<boolean>(Boolean(props.hasHome));
|
const showHome = ref<boolean>(Boolean(props.hasHome)); // 是否展示home页面
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const treeFilter = ref([]);
|
|
||||||
const treeSelect = (node: treeNodeTpye, nodeSchemas: object = {}) => {
|
const treeSelect = (node: treeNodeTpye, nodeSchemas: object = {}) => {
|
||||||
if (node.key === 'home') return (showHome.value = true);
|
if (node.key === 'home') return (showHome.value = true);
|
||||||
schemas.value = nodeSchemas;
|
schemas.value = nodeSchemas;
|
||||||
|
@ -109,8 +109,8 @@ const treeSelect = (node: treeNodeTpye, nodeSchemas: object = {}) => {
|
||||||
tableData.value = table;
|
tableData.value = table;
|
||||||
};
|
};
|
||||||
|
|
||||||
const activeKey = ref<'does' | 'test'>('does');
|
const activeKey = ref<'does' | 'test'>('does');
|
||||||
const schemas = ref({});
|
const schemas = ref({}); // 对应一级api相关的类
|
||||||
const initSelectedApi: apiDetailsType = {
|
const initSelectedApi: apiDetailsType = {
|
||||||
url: '',
|
url: '',
|
||||||
method: '',
|
method: '',
|
||||||
|
@ -121,23 +121,14 @@ const initSelectedApi: apiDetailsType = {
|
||||||
};
|
};
|
||||||
const selectedApi = ref<apiDetailsType>(initSelectedApi);
|
const selectedApi = ref<apiDetailsType>(initSelectedApi);
|
||||||
|
|
||||||
const selectedKeys = ref<string[]>([]); // 右侧默认勾选的项
|
const selectedKeys = ref<string[]>([]); // 右侧勾选的项
|
||||||
let selectSourceKeys = ref<string[]>([]);
|
const selectSourceKeys = ref<string[]>([]); // 右侧原本勾选的项
|
||||||
|
const changedApis = ref({}); // 勾选发生变化的项,以对应的id作为key
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// 右侧默认选中初始化
|
getSelectKeys();
|
||||||
if (props.mode === 'appManger') {
|
|
||||||
getApiGranted_api(props.code as string).then((resp) => {
|
|
||||||
selectedKeys.value = resp.result as string[];
|
|
||||||
selectSourceKeys.value = [...(resp.result as string[])];
|
|
||||||
});
|
|
||||||
} else if (props.mode === 'api') {
|
|
||||||
apiOperations_api().then((resp) => {
|
|
||||||
selectedKeys.value = resp.result as string[];
|
|
||||||
selectSourceKeys.value = [...(resp.result as string[])];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
watch(tableData, () => {
|
watch(tableData, () => {
|
||||||
activeKey.value = 'does';
|
activeKey.value = 'does';
|
||||||
selectedApi.value = initSelectedApi;
|
selectedApi.value = initSelectedApi;
|
||||||
|
@ -147,6 +138,24 @@ function init() {
|
||||||
() => (activeKey.value = 'does'),
|
() => (activeKey.value = 'does'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右侧api选中项
|
||||||
|
*/
|
||||||
|
function getSelectKeys() {
|
||||||
|
if (props.mode === 'appManger') {
|
||||||
|
getApiGranted_api(props.code as string).then((resp) => {
|
||||||
|
selectedKeys.value = resp.result as string[];
|
||||||
|
selectSourceKeys.value = [...(resp.result as string[])];
|
||||||
|
changedApis.value = {};
|
||||||
|
});
|
||||||
|
} else if (props.mode === 'api') {
|
||||||
|
apiOperations_api().then((resp) => {
|
||||||
|
selectedKeys.value = resp.result as string[];
|
||||||
|
selectSourceKeys.value = [...(resp.result as string[])];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -24,5 +24,9 @@ export type apiDetailsType = {
|
||||||
responses:object;
|
responses:object;
|
||||||
description?:string;
|
description?:string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* api: api配置
|
||||||
|
* appManger: 应用管理-赋权
|
||||||
|
* home:应用管理-查看菜单,第三方首页
|
||||||
|
*/
|
||||||
export type modeType = 'api'| 'appManger' | 'home'
|
export type modeType = 'api'| 'appManger' | 'home'
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="relationship-container">
|
<div class="relationship-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="role-user-container">
|
<div class="role-user-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,15 @@
|
||||||
@ok="confirm"
|
@ok="confirm"
|
||||||
@cancel="emits('update:visible', false)"
|
@cancel="emits('update:visible', false)"
|
||||||
>
|
>
|
||||||
<j-advanced-search
|
<!-- <j-advanced-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
type="simple"
|
type="simple"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
|
/> -->
|
||||||
|
<pro-search
|
||||||
|
:columns="columns"
|
||||||
|
target="simple"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
|
@ -35,7 +40,7 @@ import { message } from 'ant-design-vue';
|
||||||
const emits = defineEmits(['refresh', 'update:visible']);
|
const emits = defineEmits(['refresh', 'update:visible']);
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
roleId: string
|
roleId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
@ -85,15 +90,13 @@ const confirm = () => {
|
||||||
if (selectedRowKeys.value.length < 1) {
|
if (selectedRowKeys.value.length < 1) {
|
||||||
message.error('请至少选择一项');
|
message.error('请至少选择一项');
|
||||||
} else {
|
} else {
|
||||||
bindUser_api(props.roleId, selectedRowKeys.value).then(
|
bindUser_api(props.roleId, selectedRowKeys.value).then((resp) => {
|
||||||
(resp) => {
|
if (resp.status === 200) {
|
||||||
if (resp.status === 200) {
|
message.success('操作成功');
|
||||||
message.success('操作成功');
|
emits('refresh');
|
||||||
emits('refresh');
|
emits('update:visible', false);
|
||||||
emits('update:visible', false);
|
}
|
||||||
}
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="role-container">
|
<div class="role-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@search="(params:any)=>queryParams = params"
|
target="category"
|
||||||
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<j-pro-table
|
<j-pro-table
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class="user-container">
|
<div class="user-container">
|
||||||
<j-advanced-search
|
<pro-search
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
target="category"
|
||||||
@search="(params:any)=>queryParams = {...params}"
|
@search="(params:any)=>queryParams = {...params}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_APP_BASE_API: string;
|
readonly VITE_APP_BASE_API: string;
|
||||||
readonly VITE_APP_WS_URL: string;
|
readonly VITE_APP_WS_URL: string;
|
||||||
|
readonly MODE: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"layouts/*": ["./src/layouts/*"],
|
"layouts/*": ["./src/layouts/*"],
|
||||||
"store/*": ["./src/store/*"],
|
"store/*": ["./src/store/*"],
|
||||||
"style/*": ["./src/style/*"],
|
"style/*": ["./src/style/*"],
|
||||||
|
"jetlinks-ui-components/es": ["./node_modules/jetlinks-ui-components/es/*"]
|
||||||
},
|
},
|
||||||
"types": ["ant-design-vue/typings/global", "vite/client"],
|
"types": ["ant-design-vue/typings/global", "vite/client"],
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"suppressImplicitAnyIndexErrors": true
|
||||||
|
|
|
@ -12,12 +12,13 @@ import * as path from 'path'
|
||||||
import monacoEditorPlugin from 'vite-plugin-monaco-editor';
|
import monacoEditorPlugin from 'vite-plugin-monaco-editor';
|
||||||
// import { JetlinksVueResolver } from 'jetlinks-ui-components/lib/plugin/resolve'
|
// import { JetlinksVueResolver } from 'jetlinks-ui-components/lib/plugin/resolve'
|
||||||
import { JetlinksVueResolver } from './plugin/jetlinks'
|
import { JetlinksVueResolver } from './plugin/jetlinks'
|
||||||
|
import { optimizeDeps } from './plugin/optimize'
|
||||||
import copy from 'rollup-plugin-copy';
|
import copy from 'rollup-plugin-copy';
|
||||||
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode}) => {
|
export default defineConfig(({ mode}) => {
|
||||||
const env: Partial<ImportMetaEnv> = loadEnv(mode, process.cwd());
|
const env: Partial<ImportMetaEnv> = loadEnv(mode, process.cwd());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
base: './',
|
base: './',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@ -53,6 +54,7 @@ export default defineConfig(({ mode}) => {
|
||||||
vue(),
|
vue(),
|
||||||
monacoEditorPlugin({}),
|
monacoEditorPlugin({}),
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
|
optimizeDeps(),
|
||||||
Components({
|
Components({
|
||||||
resolvers: [JetlinksVueResolver({ importStyle: 'less' }), VueAmapResolver()],
|
resolvers: [JetlinksVueResolver({ importStyle: 'less' }), VueAmapResolver()],
|
||||||
directoryAsNamespace: true
|
directoryAsNamespace: true
|
||||||
|
@ -110,6 +112,9 @@ export default defineConfig(({ mode}) => {
|
||||||
javascriptEnabled: true,
|
javascriptEnabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['pinia', 'vue-router', 'axios', 'lodash-es', '@vueuse/core', 'echarts', 'dayjs'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue