Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
e09eda6b41
|
@ -1,7 +1,7 @@
|
|||
import server from '@/utils/request';
|
||||
|
||||
// 更新全部菜单
|
||||
export const updateMenus = (data: any) => server.path(`/menu/iot/_all`, data)
|
||||
export const updateMenus = (data: any) => server.patch(`/menu/iot/_all`, data)
|
||||
// 添加角色
|
||||
export const addRole = (data: any) => server.post(`/role`, data)
|
||||
|
||||
|
|
|
@ -121,4 +121,16 @@ export const edit = (data: any) => server.put(`/network/card/${data.id}`, data);
|
|||
* 根据id查看详情
|
||||
* @param id
|
||||
*/
|
||||
export const queryDetail = (id: any) => server.get(`/network/card/${id}`);
|
||||
export const queryDetail = (id: any) => server.get(`/network/card/${id}`);
|
||||
|
||||
/**
|
||||
* 查询物联卡充值缴费日志
|
||||
* @param data
|
||||
*/
|
||||
export const queryRechargeList = (data: any) => server.post(`/network/card/recharge/_log`, data)
|
||||
|
||||
/**
|
||||
* 充值
|
||||
* @param data
|
||||
*/
|
||||
export const recharge = (data: any) => server.post(`/network/card/_recharge`, data)
|
|
@ -36,7 +36,7 @@ export const undeploy = (id: string) =>
|
|||
export const deploy = (id: string) =>
|
||||
server.post(`/gateway/device/${id}/_startup`);
|
||||
|
||||
export const del = (id: string) => server.remove(`/gateway/device/${id}`);
|
||||
export const remove = (id: string) => server.remove(`/gateway/device/${id}`);
|
||||
|
||||
export const getResourcesCurrent = () =>
|
||||
server.get(`/network/resources/alive/_current`);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { patch, post, get, remove } from '@/utils/request'
|
||||
import { TemplateFormData } from '@/views/notice/Template/types'
|
||||
import type { TemplateFormData } from '@/views/notice/Template/types'
|
||||
|
||||
export default {
|
||||
// 列表
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { patch, post, get, remove } from '@/utils/request'
|
||||
import { BindConfig } from '@/views/notice/Template/types'
|
||||
import type { BindConfig } from '@/views/notice/Template/types'
|
||||
|
||||
export default {
|
||||
// 列表
|
||||
|
|
|
@ -231,6 +231,13 @@ const handleClick = () => {
|
|||
|
||||
:deep(.card-item-content-title) {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: @primary-color;
|
||||
width: calc(100% - 100px);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.card-item-heard-name) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import { ProLayout } from '@/components/Layout'
|
||||
import DefaultSetting from '../../../config/config'
|
||||
import { useMenuStore } from '@/store/menu'
|
||||
import { clearMenuItem } from 'components/Layout/utils'
|
||||
|
||||
type StateType = {
|
||||
collapsed: boolean
|
||||
|
@ -39,7 +40,7 @@ const layoutConf = reactive({
|
|||
siderWidth: DefaultSetting.layout.siderWidth,
|
||||
logo: DefaultSetting.layout.logo,
|
||||
title: DefaultSetting.layout.title,
|
||||
menuData: menu.menus,
|
||||
menuData: clearMenuItem(menu.siderMenus),
|
||||
});
|
||||
|
||||
const state = reactive<StateType>({
|
||||
|
|
|
@ -32,7 +32,7 @@ export const HeaderView = defineComponent({
|
|||
height: `${headerHeight.value}px`,
|
||||
lineHeight: `${headerHeight.value}px`,
|
||||
width: `100%`,
|
||||
|
||||
background: 'transparent'
|
||||
}}
|
||||
/>
|
||||
<Layout.Header
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.children-full-height {
|
||||
> :nth-child(1) {
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
//.children-full-height {
|
||||
// > :nth-child(1) {
|
||||
// min-height: 100%;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -13,4 +13,8 @@
|
|||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-menu-inline {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,6 +286,7 @@ handleItems()
|
|||
.JSearch-warp {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.JSearch-content {
|
||||
display: flex;
|
||||
|
|
|
@ -10,17 +10,23 @@
|
|||
.jtable-body-header-right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
.jtable-setting-item {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
.jtable-body-header-right-button {
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
gap: 8px;
|
||||
.jtable-setting-item {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color-hover;
|
||||
}
|
||||
&:hover {
|
||||
color: @primary-color-hover;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: @primary-color-active;
|
||||
&.active {
|
||||
color: @primary-color-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ const JTable = defineComponent<JTableProps>({
|
|||
slots: [
|
||||
'headerTitle', // 顶部左边插槽
|
||||
'card', // 卡片内容
|
||||
'rightExtraRender'
|
||||
],
|
||||
emits: [
|
||||
'modelChange', // 切换卡片和表格
|
||||
|
@ -254,16 +255,22 @@ const JTable = defineComponent<JTableProps>({
|
|||
{slots.headerTitle && slots.headerTitle()}
|
||||
</div>
|
||||
<div class={styles["jtable-body-header-right"]}>
|
||||
<div class={[styles["jtable-setting-item"], ModelEnum.CARD === _model.value ? styles['active'] : '']} onClick={() => {
|
||||
_model.value = ModelEnum.CARD
|
||||
}}>
|
||||
<AppstoreOutlined />
|
||||
</div>
|
||||
<div class={[styles["jtable-setting-item"], ModelEnum.TABLE === _model.value ? styles['active'] : '']} onClick={() => {
|
||||
_model.value = ModelEnum.TABLE
|
||||
}}>
|
||||
<UnorderedListOutlined />
|
||||
</div>
|
||||
{/* 顶部右边插槽 */}
|
||||
{slots.rightExtraRender && slots.rightExtraRender()}
|
||||
{
|
||||
!props.model && <div class={styles["jtable-body-header-right-button"]}>
|
||||
<div class={[styles["jtable-setting-item"], ModelEnum.CARD === _model.value ? styles['active'] : '']} onClick={() => {
|
||||
_model.value = ModelEnum.CARD
|
||||
}}>
|
||||
<AppstoreOutlined />
|
||||
</div>
|
||||
<div class={[styles["jtable-setting-item"], ModelEnum.TABLE === _model.value ? styles['active'] : '']} onClick={() => {
|
||||
_model.value = ModelEnum.TABLE
|
||||
}}>
|
||||
<UnorderedListOutlined />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{/* content */}
|
||||
|
|
11
src/main.ts
11
src/main.ts
|
@ -1,17 +1,14 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
import components from './components'
|
||||
import router from './router'
|
||||
import './style.less'
|
||||
import 'ant-design-vue/es/notification/style/css';
|
||||
import Antd from 'ant-design-vue/es'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(store)
|
||||
app.use(router)
|
||||
app.use(components)
|
||||
app.use(Antd)
|
||||
|
||||
app.mount('#app')
|
||||
.use(router)
|
||||
.use(components)
|
||||
.mount('#app')
|
||||
|
|
|
@ -3,6 +3,8 @@ import menus, { LoginPath } from './menu'
|
|||
import { cleanToken, getToken } from '@/utils/comm'
|
||||
import { useUserInfo } from '@/store/userInfo'
|
||||
import { useSystem } from '@/store/system'
|
||||
import NotFindPage from '@/views/404.vue'
|
||||
import { useMenuStore } from 'store/menu'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
|
@ -27,22 +29,23 @@ router.beforeEach((to, from, next) => {
|
|||
} else {
|
||||
const userInfo = useUserInfo()
|
||||
const system = useSystem()
|
||||
const menu = useMenuStore()
|
||||
|
||||
if (!userInfo.userInfos.username) {
|
||||
if (!menu.menuData.length) {
|
||||
userInfo.getUserInfo().then(() => {
|
||||
system.getSystemVersion().then((menuData: any[]) => {
|
||||
menuData.forEach(r => {
|
||||
router.addRoute('main', r)
|
||||
router.addRoute('base', r)
|
||||
})
|
||||
const redirect = decodeURIComponent((from.query.redirect as string) || to.path)
|
||||
if(to.path === redirect) {
|
||||
next({ ...to, replace: true })
|
||||
} else {
|
||||
next({ path: redirect })
|
||||
}
|
||||
router.addRoute('base',{
|
||||
path: '/:pathMatch(.*)',
|
||||
name: 'error',
|
||||
component: () => NotFindPage
|
||||
})
|
||||
|
||||
next({ ...to, replace: true })
|
||||
})
|
||||
}).catch(() => {
|
||||
console.log('userInfo', userInfo)
|
||||
cleanToken()
|
||||
next({ path: LoginPath })
|
||||
})
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
export const LoginPath = '/login'
|
||||
|
||||
export default [
|
||||
// {
|
||||
// path: '/',
|
||||
// redirect: LoginPath
|
||||
// },
|
||||
// {
|
||||
// path: '/init',
|
||||
// component: () => import('@/view/InitPage.vue')
|
||||
// },
|
||||
// {
|
||||
// path: LoginPath,
|
||||
// name: 'login',
|
||||
// component: () => import('@/view/Login/index.vue')
|
||||
// },
|
||||
// {
|
||||
// path: '/initsetting',
|
||||
// component: () => import('@/view/Login/initSet.vue')
|
||||
// }
|
||||
|
||||
{ path: '/*', redirect: '/'},
|
||||
// start: 测试用, 可删除
|
||||
{
|
||||
path: '/login',
|
||||
|
@ -32,10 +15,6 @@ export default [
|
|||
path: '/account/center/bind',
|
||||
component: () => import('@/views/account/Center/bind/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot/home',
|
||||
component: () => import('@/views/home/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/table',
|
||||
component: () => import('@/views/demo/table/index.vue')
|
||||
|
@ -48,129 +27,13 @@ export default [
|
|||
path: '/search',
|
||||
component: () => import('@/views/demo/Search.vue')
|
||||
},
|
||||
{
|
||||
path: '/notice/Config',
|
||||
component: () => import('@/views/notice/Config/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/notice/Config/detail/:id',
|
||||
component: () => import('@/views/notice/Config/Detail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/notice/Template',
|
||||
component: () => import('@/views/notice/Template/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/notice/Template/detail/:id',
|
||||
component: () => import('@/views/notice/Template/Detail/index.vue')
|
||||
},
|
||||
|
||||
// end: 测试用, 可删除
|
||||
|
||||
// 设备管理
|
||||
{
|
||||
path: '/device/instance',
|
||||
component: () => import('@/views/device/Instance/index.vue')
|
||||
},
|
||||
{
|
||||
// path: '/device/Instance/detail/:id',
|
||||
// component: () => import('@/views/device/Instance/detail.vue')
|
||||
path: '/device/instance/detail/:id',
|
||||
component: () => import('@/views/device/Instance/Detail/index.vue')
|
||||
},
|
||||
// link 运维管理
|
||||
{
|
||||
path: '/link/log',
|
||||
component: () => import('@/views/link/Log/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/link/certificate',
|
||||
component: () => import('@/views/link/Certificate/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/link/certificate/detail/:type/:id',
|
||||
component: () => import('@/views/link/Certificate/Detail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/link/accessConfig',
|
||||
component: () => import('@/views/link/AccessConfig/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/link/accessConfig/detail/add',
|
||||
component: () => import('@/views/link/AccessConfig/Detail/index.vue')
|
||||
},
|
||||
// system 系统管理
|
||||
{
|
||||
path:'/system/Basis',
|
||||
component: ()=>import('@/views/system/Basis/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/api',
|
||||
component: ()=>import('@/views/system/apiPage/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/Role',
|
||||
component: ()=>import('@/views/system/Role/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/Role/detail/:id',
|
||||
component: ()=>import('@/views/system/Role/Detail/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/Permission',
|
||||
component: ()=>import('@/views/system/Permission/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/Menu',
|
||||
component: ()=>import('@/views/system/Menu/index.vue')
|
||||
},
|
||||
{
|
||||
path:'/system/Menu/detail/:id',
|
||||
component: ()=>import('@/views/system/Menu/Detail/index.vue')
|
||||
},
|
||||
// 初始化
|
||||
{
|
||||
path: '/init-home',
|
||||
component: () => import('@/views/init-home/index.vue')
|
||||
},
|
||||
// 物联卡 iot-card
|
||||
{
|
||||
path: '/iot-card/Home',
|
||||
component: () => import('@/views/iot-card/Home/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot-card/Dashboard',
|
||||
component: () => import('@/views/iot-card/Dashboard/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot-card/CardManagement',
|
||||
component: () => import('@/views/iot-card/CardManagement/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot-card/CardManagement/Detail',
|
||||
component: () => import('@/views/iot-card/CardManagement/Detail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot-card/Recharge',
|
||||
component: () => import('@/views/iot-card/Recharge/index.vue')
|
||||
},
|
||||
// 北向输出
|
||||
{
|
||||
path: '/northbound/DuerOS',
|
||||
component: () => import('@/views/northbound/DuerOS/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/northbound/AliCloud',
|
||||
component: () => import('@/views/northbound/AliCloud/index.vue')
|
||||
},
|
||||
|
||||
// 产品分类
|
||||
{
|
||||
path: '/iot/device/Category',
|
||||
component: () => import('@/views/device/Category/index.vue')
|
||||
} ,
|
||||
// 产品
|
||||
{
|
||||
path: '/iot/device/Product',
|
||||
component: () => import('@/views/device/Product/index.vue')
|
||||
}
|
||||
]
|
|
@ -1,11 +1,14 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { queryOwnThree } from '@/api/system/menu'
|
||||
import { filterAsnycRouter } from '@/utils/menu'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
export const useMenuStore = defineStore({
|
||||
id: 'menu',
|
||||
state: () => ({
|
||||
menus: {},
|
||||
menuData: [],
|
||||
siderMenus: [],
|
||||
menusKey: []
|
||||
}),
|
||||
getters: {
|
||||
|
@ -51,7 +54,8 @@ export const useMenuStore = defineStore({
|
|||
];
|
||||
const resp = await queryOwnThree({ paging: false, terms: params })
|
||||
if (resp.success) {
|
||||
const menus = filterAsnycRouter(resp.result)
|
||||
const silderMenus = filterAsnycRouter(cloneDeep(resp.result))
|
||||
const menus = filterAsnycRouter(cloneDeep(resp.result))
|
||||
menus.push({
|
||||
path: '/',
|
||||
redirect: menus[0]?.path,
|
||||
|
@ -59,7 +63,9 @@ export const useMenuStore = defineStore({
|
|||
hideInMenu: true
|
||||
}
|
||||
})
|
||||
this.menus = menus
|
||||
this.menuData = menus
|
||||
this.siderMenus = silderMenus
|
||||
console.log('silderMenus', silderMenus)
|
||||
res(menus)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,11 +1,99 @@
|
|||
const pagesComponent = import.meta.glob('../views/system/**/*.vue', { eager: true });
|
||||
const pagesComponent = import.meta.glob('../views/**/*.vue', { eager: true });
|
||||
import { BlankLayoutPage, BasicLayoutPage } from 'components/Layout'
|
||||
|
||||
type ExtraRouteItem = {
|
||||
code: string
|
||||
name: string
|
||||
url?: string
|
||||
}
|
||||
/**
|
||||
* 权限信息
|
||||
*/
|
||||
export type PermissionInfo = {
|
||||
permission: string;
|
||||
actions: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* 按钮信息
|
||||
*/
|
||||
export type MenuButtonInfo = {
|
||||
id: string;
|
||||
name: string;
|
||||
permissions: PermissionInfo;
|
||||
createTime: number;
|
||||
describe?: string;
|
||||
options: Record<string, any>;
|
||||
};
|
||||
|
||||
|
||||
export type MenuItem = {
|
||||
id: string;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* 所属应用
|
||||
*/
|
||||
application: string;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
describe: string;
|
||||
/**
|
||||
* url,路由
|
||||
*/
|
||||
url: string;
|
||||
/**
|
||||
* 图标
|
||||
*/
|
||||
icon: string;
|
||||
/**
|
||||
* 状态, 0为禁用,1为启用
|
||||
*/
|
||||
status: number;
|
||||
/**
|
||||
* 绑定权限信息
|
||||
*/
|
||||
permissions: PermissionInfo[];
|
||||
/**
|
||||
* 按钮定义信息
|
||||
*/
|
||||
buttons: MenuButtonInfo[];
|
||||
/**
|
||||
* 其他配置信息
|
||||
*/
|
||||
options: Record<string, any>;
|
||||
/**
|
||||
* 父级ID
|
||||
*/
|
||||
parentId: string;
|
||||
/**
|
||||
* 树结构路径
|
||||
*/
|
||||
path: string;
|
||||
/**
|
||||
* 排序序号
|
||||
*/
|
||||
sortIndex: number;
|
||||
/**
|
||||
* 树层级
|
||||
*/
|
||||
level: number;
|
||||
createTime: number;
|
||||
redirect?: string;
|
||||
children?: MenuItem[];
|
||||
accessSupport?: { text: string; value: string };
|
||||
appId?: string; //应用id
|
||||
isShow?: boolean;
|
||||
meta?: {
|
||||
title?: string
|
||||
icon?: string
|
||||
[key: string]: any
|
||||
},
|
||||
component?: any
|
||||
};
|
||||
|
||||
// 额外子级路由
|
||||
const extraRouteObj = {
|
||||
'media/Cascade': {
|
||||
|
@ -59,53 +147,83 @@ const extraRouteObj = {
|
|||
|
||||
|
||||
const resolveComponent = (name: any) => {
|
||||
// TODO 暂时用system进行测试
|
||||
const importPage = pagesComponent[`../views/${name}/index.vue`];
|
||||
// if (!importPage) {
|
||||
// throw new Error(`Unknown page ${name}. Is it located under Pages with a .vue extension?`);
|
||||
// }
|
||||
|
||||
if (!importPage) {
|
||||
console.warn(`Unknown page ${name}. Is it located under Pages with a .vue extension?`)
|
||||
}
|
||||
//@ts-ignore
|
||||
return !importPage ? BlankLayoutPage : importPage.default
|
||||
// return importPage.default
|
||||
return !!importPage ? importPage.default : undefined
|
||||
}
|
||||
|
||||
const findChildrenRoute = (code: string, url: string): ExtraRouteItem[] => {
|
||||
const findChildrenRoute = (code: string, url: string): MenuItem[] => {
|
||||
if (extraRouteObj[code]) {
|
||||
return extraRouteObj[code].children.map((route: ExtraRouteItem) => {
|
||||
return extraRouteObj[code].children.map((route: MenuItem) => {
|
||||
return {
|
||||
url: `${url}/${route.code}`,
|
||||
code: route.code,
|
||||
name: route.name
|
||||
name: route.name,
|
||||
isShow: false
|
||||
}
|
||||
})
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
const findDetailRouteItem = (code: string, url: string): Partial<MenuItem> | null => {
|
||||
const detailComponent = resolveComponent(`${code}/Detail`)
|
||||
if (detailComponent) {
|
||||
return {
|
||||
url: `${url}/Detail/:id`,
|
||||
component: detailComponent,
|
||||
name: '详情信息',
|
||||
isShow: false
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const findDetailRoutes = (routes: any[]): any[] => {
|
||||
const newRoutes: any[] = []
|
||||
routes.forEach((route: any) => {
|
||||
newRoutes.push(route)
|
||||
const detail = findDetailRouteItem(route.code, route.url)
|
||||
if (detail) {
|
||||
newRoutes.push(detail)
|
||||
}
|
||||
})
|
||||
return newRoutes
|
||||
}
|
||||
|
||||
export function filterAsnycRouter(asyncRouterMap: any, parentCode = '', level = 1) {
|
||||
|
||||
return asyncRouterMap.map((route: any) => {
|
||||
|
||||
route.path = `${route.url}`
|
||||
route.meta = {
|
||||
icon: route.icon,
|
||||
title: route.name
|
||||
title: route.name,
|
||||
hideInMenu: route.isShow === false
|
||||
}
|
||||
|
||||
// 查看是否有隐藏子路由
|
||||
route.children = route.children && route.children.length ? [...route.children, ...findChildrenRoute(route.code, route.url)] : findChildrenRoute(route.code, route.url)
|
||||
|
||||
// TODO 查看是否具有详情页
|
||||
// route.children = [...route.children, ]
|
||||
|
||||
const extraChildren = findChildrenRoute(route.code, route.url)
|
||||
route.children = route.children && route.children.length ? [...route.children, ...extraChildren] : extraChildren
|
||||
route.children = findDetailRoutes(route.children)
|
||||
if (route.children && route.children.length) {
|
||||
route.component = () => level === 1 ? BasicLayoutPage : BlankLayoutPage
|
||||
// TODO 查看是否具有详情页
|
||||
route.children = filterAsnycRouter(route.children, `${parentCode}/${route.code}`, level + 1)
|
||||
route.redirect = route.children[0].url
|
||||
const showChildren = route.children.some((r: any) => !r.meta.hideInMenu)
|
||||
if (showChildren) {
|
||||
route.component = () => level === 1 ? BasicLayoutPage : BlankLayoutPage
|
||||
route.redirect = route.children[0].url
|
||||
} else {
|
||||
route.component = resolveComponent(route.code) || BlankLayoutPage;
|
||||
}
|
||||
} else {
|
||||
route.component = resolveComponent(route.code);
|
||||
console.log(route.code)
|
||||
route.component = route.component || resolveComponent(route.code) || BlankLayoutPage;
|
||||
}
|
||||
console.log(route.code, route)
|
||||
delete route.name
|
||||
return route
|
||||
})
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<a-result status="404" title="404" sub-title="Sorry, the page you visited does not exist.">
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: '404.vue'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,221 +1,234 @@
|
|||
<template>
|
||||
<JTable
|
||||
ref="instanceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
@cancelSelect="cancelSelect"
|
||||
:params="params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
<a-dropdown>
|
||||
<a-button>批量操作 <AIcon type="DownOutlined" /></a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<a-button @click="exportVisible = true"
|
||||
><AIcon
|
||||
type="ExportOutlined"
|
||||
/>批量导出设备</a-button
|
||||
>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button @click="importVisible = true"
|
||||
><AIcon
|
||||
type="ImportOutlined"
|
||||
/>批量导入设备</a-button
|
||||
>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-popconfirm
|
||||
@confirm="activeAllDevice"
|
||||
title="确认激活全部设备?"
|
||||
>
|
||||
<a-button type="primary" ghost
|
||||
<page-container>
|
||||
<Search :columns="columns" target="device-instance" />
|
||||
<JTable
|
||||
ref="instanceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
@cancelSelect="cancelSelect"
|
||||
:params="params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
<a-dropdown>
|
||||
<a-button
|
||||
>批量操作 <AIcon type="DownOutlined"
|
||||
/></a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<a-button @click="exportVisible = true"
|
||||
><AIcon
|
||||
type="CheckCircleOutlined"
|
||||
/>激活全部设备</a-button
|
||||
type="ExportOutlined"
|
||||
/>批量导出设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button
|
||||
@click="syncDeviceStatus"
|
||||
type="primary"
|
||||
><AIcon
|
||||
type="SyncOutlined"
|
||||
/>同步设备状态</a-button
|
||||
>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm
|
||||
@confirm="delSelectedDevice"
|
||||
title="已启用的设备无法删除,确认删除选中的禁用状态设备?"
|
||||
>
|
||||
<a-button type="primary" danger
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button @click="importVisible = true"
|
||||
><AIcon
|
||||
type="DeleteOutlined"
|
||||
/>删除选中设备</a-button
|
||||
type="ImportOutlined"
|
||||
/>批量导入设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item
|
||||
v-if="_selectedRowKeys.length"
|
||||
title="确认激活选中设备?"
|
||||
>
|
||||
<a-popconfirm @confirm="activeSelectedDevice">
|
||||
<a-button type="primary"
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-popconfirm
|
||||
@confirm="activeAllDevice"
|
||||
title="确认激活全部设备?"
|
||||
>
|
||||
<a-button type="primary" ghost
|
||||
><AIcon
|
||||
type="CheckCircleOutlined"
|
||||
/>激活全部设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button
|
||||
@click="syncDeviceStatus"
|
||||
type="primary"
|
||||
><AIcon
|
||||
type="CheckOutlined"
|
||||
/>激活选中设备</a-button
|
||||
type="SyncOutlined"
|
||||
/>同步设备状态</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm
|
||||
@confirm="disabledSelectedDevice"
|
||||
title="确认禁用选中设备?"
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm
|
||||
@confirm="delSelectedDevice"
|
||||
title="已启用的设备无法删除,确认删除选中的禁用状态设备?"
|
||||
>
|
||||
<a-button type="primary" danger
|
||||
><AIcon
|
||||
type="DeleteOutlined"
|
||||
/>删除选中设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item
|
||||
v-if="_selectedRowKeys.length"
|
||||
title="确认激活选中设备?"
|
||||
>
|
||||
<a-button type="primary" danger
|
||||
><AIcon
|
||||
type="StopOutlined"
|
||||
/>禁用选中设备</a-button
|
||||
<a-popconfirm
|
||||
@confirm="activeSelectedDevice"
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button type="primary"
|
||||
><AIcon
|
||||
type="CheckOutlined"
|
||||
/>激活选中设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="_selectedRowKeys.length">
|
||||
<a-popconfirm
|
||||
@confirm="disabledSelectedDevice"
|
||||
title="确认禁用选中设备?"
|
||||
>
|
||||
<a-button type="primary" danger
|
||||
><AIcon
|
||||
type="StopOutlined"
|
||||
/>禁用选中设备</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img
|
||||
:src="
|
||||
getImage('/device/instance/device-card.png')
|
||||
"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value="slotProps"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img
|
||||
:src="getImage('/device/instance/device-card.png')"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<h3
|
||||
class="card-item-content-title"
|
||||
@click.stop="handleView(slotProps.id)"
|
||||
>
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">设备类型</div>
|
||||
<div>{{ slotProps.deviceType?.text }}</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">产品名称</div>
|
||||
<div>{{ slotProps.productName }}</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<template #content>
|
||||
<h3
|
||||
class="card-item-content-title"
|
||||
@click.stop="handleView(slotProps.id)"
|
||||
>
|
||||
{{ slotProps.name }}
|
||||
</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>{{ slotProps.deviceType?.text }}</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
产品名称
|
||||
</div>
|
||||
<div>{{ slotProps.productName }}</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<a-tooltip
|
||||
v-bind="item.tooltip"
|
||||
:title="item.disabled && item.tooltip.title"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="item.popConfirm"
|
||||
v-bind="item.popConfirm"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<a-button :disabled="item.disabled">
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<template v-else>
|
||||
<a-button
|
||||
:disabled="item.disabled"
|
||||
@click="item.onClick"
|
||||
>
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<a-badge
|
||||
:text="slotProps.state?.text"
|
||||
:status="statusMap.get(slotProps.state?.value)"
|
||||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
v-bind="item.tooltip"
|
||||
:title="item.disabled && item.tooltip.title"
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="item.popConfirm"
|
||||
v-bind="item.popConfirm"
|
||||
:disabled="item.disabled"
|
||||
v-if="i.popConfirm"
|
||||
v-bind="i.popConfirm"
|
||||
:disabled="i.disabled"
|
||||
>
|
||||
<a-button :disabled="item.disabled">
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<template v-else>
|
||||
<a-button
|
||||
:disabled="item.disabled"
|
||||
@click="item.onClick"
|
||||
>
|
||||
<AIcon
|
||||
type="DeleteOutlined"
|
||||
v-if="item.key === 'delete'"
|
||||
/>
|
||||
<template v-else>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<a-badge
|
||||
:text="slotProps.state?.text"
|
||||
:status="statusMap.get(slotProps.state?.value)"
|
||||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="i.popConfirm"
|
||||
v-bind="i.popConfirm"
|
||||
:disabled="i.disabled"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
</page-container>
|
||||
<Import v-if="importVisible" @close="importVisible = false" />
|
||||
<Export
|
||||
v-if="exportVisible"
|
||||
|
@ -228,7 +241,12 @@
|
|||
:api="api"
|
||||
:type="type"
|
||||
/>
|
||||
<Save v-if="visible" :data="current" @close="visible = false" @save="saveBtn" />
|
||||
<Save
|
||||
v-if="visible"
|
||||
:data="current"
|
||||
@close="visible = false"
|
||||
@save="saveBtn"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -367,8 +385,8 @@ const handleAdd = () => {
|
|||
* 查看
|
||||
*/
|
||||
const handleView = (id: string) => {
|
||||
router.push('/device/instance/detail/' + id)
|
||||
}
|
||||
router.push('/device/instance/detail/' + id);
|
||||
};
|
||||
|
||||
const getActions = (
|
||||
data: Partial<Record<string, any>>,
|
||||
|
@ -519,10 +537,10 @@ const disabledSelectedDevice = async () => {
|
|||
_selectedRowKeys.value = [];
|
||||
instanceRef.value?.reload();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const saveBtn = () => {
|
||||
visible.value = false
|
||||
instanceRef.value?.reload()
|
||||
}
|
||||
visible.value = false;
|
||||
instanceRef.value?.reload();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -33,7 +33,7 @@ const BaseColumns: JColumnProps[] = [
|
|||
const EventColumns: JColumnProps[] = BaseColumns.concat([
|
||||
{
|
||||
title: '事件级别',
|
||||
dataIndex: 'expands',
|
||||
dataIndex: 'level',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
@ -59,12 +59,12 @@ const PropertyColumns: JColumnProps[] = BaseColumns.concat([
|
|||
},
|
||||
{
|
||||
title: '属性来源',
|
||||
dataIndex: 'expands',
|
||||
dataIndex: 'source',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '读写类型',
|
||||
dataIndex: 'expands',
|
||||
dataIndex: 'type',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
@ -77,7 +77,7 @@ const TagColumns: JColumnProps[] = BaseColumns.concat([
|
|||
},
|
||||
{
|
||||
title: '读写类型',
|
||||
dataIndex: 'expands',
|
||||
dataIndex: 'type',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<JTable :loading="loading" :data-source="data" size="small" :columns="columns" row-key="id">
|
||||
<JTable :loading="loading" :data-source="data" size="small" :columns="columns" row-key="id" model="TABLE">
|
||||
<template #headerTitle>
|
||||
<a-input-search v-model:value="searchValue" placeholder="请输入名称" @search="handleSearch"></a-input-search>
|
||||
<PermissionButton :has-permission="permission" key="add" @click="handleAddClick"
|
||||
|
@ -11,11 +11,24 @@
|
|||
</template>
|
||||
新增
|
||||
</PermissionButton>
|
||||
<Edit
|
||||
v-if="metadataStore.model.edit"
|
||||
:type="target"
|
||||
:tabs="type"
|
||||
></Edit>
|
||||
<Edit v-if="metadataStore.model.edit" :type="target" :tabs="type"></Edit>
|
||||
</template>
|
||||
<template #level="slotProps">
|
||||
{{ levelMap[slotProps.expands?.level] || '-' }}
|
||||
</template>
|
||||
<template #async="slotProps">
|
||||
{{ slotProps.async ? '是' : '否' }}
|
||||
</template>
|
||||
<template #valueType="slotProps">
|
||||
{{ slotProps.valueType?.type }}
|
||||
</template>
|
||||
<template #source="slotProps">
|
||||
{{ sourceMap[slotProps.expands?.source] }}
|
||||
</template>
|
||||
<template #type="slotProps">
|
||||
<a-tag v-for="item in (slotProps.expands?.type || [])" :key="item">
|
||||
{{ expandsType[item] }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</JTable>
|
||||
</template>
|
||||
|
@ -42,6 +55,21 @@ const productStore = useProductStore()
|
|||
const loading = ref(false)
|
||||
const data = ref<MetadataItem[]>([])
|
||||
const { type, target = 'product' } = props
|
||||
const levelMap = ref({
|
||||
ordinary: '普通',
|
||||
warn: '警告',
|
||||
urgent: '紧急',
|
||||
})
|
||||
const sourceMap = ref({
|
||||
device: '设备',
|
||||
manual: '手动',
|
||||
rule: '规则',
|
||||
});
|
||||
const expandsType = ref({
|
||||
read: '读',
|
||||
write: '写',
|
||||
report: '上报',
|
||||
});
|
||||
const actions: JColumnProps[] = [
|
||||
{
|
||||
title: '操作',
|
||||
|
@ -97,4 +125,5 @@ const operateLimits = (action: 'add' | 'updata', types: MetadataType) => {
|
|||
};
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
|
@ -19,7 +19,7 @@
|
|||
<a-tab-pane v-for="item in codecs" :key="item.id" :tab="item.name">
|
||||
<div class="cat-panel">
|
||||
<!-- TODO 代码编辑器 -->
|
||||
{{ value }}
|
||||
<MonacoEditor v-model="value" theme="vs" style="height: 100%"></MonacoEditor>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<template #addonAfter>
|
||||
<a-upload v-model:file-list="fileList" :before-upload="beforeUpload" accept=".json"
|
||||
:show-upload-list="false" :action="FILE_UPLOAD" @change="fileChange"
|
||||
:headers="{ 'X-Access-Token': token }">
|
||||
:headers="{ 'X-Access-Token': getToken()}">
|
||||
<upload-outlined class="upload-button"/>
|
||||
<!-- <button id="uploadFile" style="display: none;"></button> -->
|
||||
</a-upload>
|
||||
|
@ -45,7 +45,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item label="物模型" v-bind="validateInfos.import" v-if="formModel.metadataType === 'script'">
|
||||
<!-- TODO代码编辑器 -->
|
||||
<a-textarea v-model:value="formModel.import"></a-textarea>
|
||||
<MonacoEditor v-model="formModel.import" theme="vs" style="height: 300px"></MonacoEditor>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
@ -64,8 +64,8 @@ import { useInstanceStore } from '@/store/instance'
|
|||
import { useProductStore } from '@/store/product';
|
||||
import { UploadOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { LocalStore, getToken } from '@/utils/comm';
|
||||
import MonacoEditor from '@/components/MonacoEditor/index.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const instanceStore = useInstanceStore()
|
||||
|
@ -147,7 +147,6 @@ const onSubmit = () => {
|
|||
})
|
||||
}
|
||||
const fileList = ref<UploadFile[]>([])
|
||||
const token = ref(LocalStore.get(TOKEN_KEY));
|
||||
|
||||
const productList = ref<DefaultOptionType[]>([])
|
||||
|
||||
|
|
|
@ -32,16 +32,16 @@
|
|||
</template>
|
||||
|
||||
<a-tab-pane tab="属性定义" key="properties">
|
||||
<BaseMetadata target={props.type} type="properties" :permission="permission" />
|
||||
<BaseMetadata :target="type" type="properties" :permission="permission" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="功能定义" key="functions">
|
||||
<BaseMetadata target={props.type} type="functions" :permission="permission" />
|
||||
<BaseMetadata :target="type" type="functions" :permission="permission" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="事件定义" key="events">
|
||||
<BaseMetadata target={props.type} type="events" :permission="permission" />
|
||||
<BaseMetadata :target="type" type="events" :permission="permission" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="标签定义" key="tags">
|
||||
<BaseMetadata target={props.type} type="tags" :permission="permission" />
|
||||
<BaseMetadata :target="type" type="tags" :permission="permission" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<Import v-model:visible="visible" :type="type" @close="visible = false" />
|
||||
|
@ -58,6 +58,7 @@ import { SystemConst } from '@/utils/consts'
|
|||
import { useInstanceStore } from '@/store/instance'
|
||||
import Import from './Import/index.vue'
|
||||
import Cat from './Cat/index.vue'
|
||||
import BaseMetadata from './Base/index.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const instanceStore = useInstanceStore()
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
ref="bindDeviceRef"
|
||||
:columns="columns"
|
||||
:request="queryUnbounded"
|
||||
model="TABLE"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
}"
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<a-modal
|
||||
:maskClosable="false"
|
||||
width="1000px"
|
||||
:visible="true"
|
||||
title="详情"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
@ok="handleCancel"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div style="margin-top: 10px">
|
||||
<a-descriptions
|
||||
:column="2"
|
||||
bordered
|
||||
:contentStyle="{ minWidth: '300px' }"
|
||||
:labelStyle="{ minWidth: '120px' }"
|
||||
>
|
||||
<a-descriptions-item label="充值金额">{{
|
||||
data.chargeMoney
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item label="账户id">{{
|
||||
data?.rechargeId
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item label="平台对接">{{
|
||||
data.configName
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item label="订单号">{{
|
||||
data.orderNumber
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item label="支付方式">{{
|
||||
data.paymentType
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item label="支付URL">
|
||||
<div style="height: 100px; overflow: auto">
|
||||
{{ data.url ? data.url : '' }}
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="订单时间">{{
|
||||
data.createTime
|
||||
? moment(data.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
: '-'
|
||||
}}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import moment from 'moment';
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('close');
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,191 @@
|
|||
<template>
|
||||
<a-modal
|
||||
:maskClosable="false"
|
||||
width="600px"
|
||||
:visible="true"
|
||||
title="充值"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:confirmLoading="btnLoading"
|
||||
>
|
||||
<div>
|
||||
<div class="modal-info">
|
||||
<AIcon
|
||||
type="ExclamationCircleOutlined"
|
||||
style="margin-right: 6px"
|
||||
/>暂只支持移动OneLink平台
|
||||
</div>
|
||||
<a-form
|
||||
layout="vertical"
|
||||
ref="formRef"
|
||||
:rules="rules"
|
||||
:model="modelRef"
|
||||
>
|
||||
<a-form-item label="平台对接" name="configId">
|
||||
<a-select
|
||||
v-model:value="modelRef.configId"
|
||||
:options="configList"
|
||||
allowClear
|
||||
show-search
|
||||
style="width: 100%"
|
||||
placeholder="请选择平台对接"
|
||||
>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="账户id" name="rechargeId">
|
||||
<a-input
|
||||
v-model:value="modelRef.rechargeId"
|
||||
placeholder="请输入账户id"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值金额" name="chargeMoney">
|
||||
<a-input-number
|
||||
allowClear
|
||||
:precision="2"
|
||||
style="width: 100%"
|
||||
v-model:value="modelRef.chargeMoney"
|
||||
:min="1"
|
||||
:max="500"
|
||||
placeholder="请输入1~500之间的金额"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="支付方式" name="paymentType">
|
||||
<a-select
|
||||
allowClear
|
||||
:options="PaymentMethod"
|
||||
v-model:value="modelRef.paymentType"
|
||||
placeholder="请选择支付方式"
|
||||
>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryPlatformNoPage, recharge } from '@/api/iot-card/cardManagement';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { PaymentMethod } from '@/views/iot-card/data';
|
||||
|
||||
const emit = defineEmits(['change']);
|
||||
|
||||
const btnLoading = ref<boolean>(false);
|
||||
const configList = ref<Record<string, any>[]>([]);
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
const modelRef = reactive({
|
||||
configId: undefined,
|
||||
rechargeId: '',
|
||||
chargeMoney: undefined,
|
||||
paymentType: undefined,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
configId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择平台对接',
|
||||
},
|
||||
{
|
||||
max: 64,
|
||||
message: '最多输入64个字符',
|
||||
},
|
||||
],
|
||||
rechargeId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入账户id',
|
||||
},
|
||||
{
|
||||
max: 64,
|
||||
message: '最多输入64个字符',
|
||||
},
|
||||
],
|
||||
chargeMoney: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入充值金额',
|
||||
},
|
||||
// {
|
||||
// min: 1,
|
||||
// max: 500,
|
||||
// message: '请输入1~500之间的数字',
|
||||
// },
|
||||
],
|
||||
paymentType: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择支付方式',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const queryProvidersList = () => {
|
||||
queryPlatformNoPage({
|
||||
paging: false,
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'operatorName',
|
||||
termType: 'eq',
|
||||
value: 'onelink',
|
||||
},
|
||||
{
|
||||
column: 'state',
|
||||
termType: 'eq',
|
||||
value: 'enabled',
|
||||
type: 'and',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}).then((res: any) => {
|
||||
configList.value = res.result.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('change');
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
btnLoading.value = true;
|
||||
const resp: any = await recharge(toRaw(modelRef));
|
||||
btnLoading.value = false;
|
||||
if (resp.status === 200) {
|
||||
if (resp.result === '失败') {
|
||||
message.error('缴费失败');
|
||||
} else {
|
||||
window.open(resp.result);
|
||||
}
|
||||
emit('change');
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.log('error', err);
|
||||
});
|
||||
};
|
||||
|
||||
queryProvidersList();
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.modal-info {
|
||||
color: rgba(0, 0, 0, 0.55);
|
||||
background-color: #f6f6f6;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
|
@ -1,8 +1,184 @@
|
|||
<!-- 充值管理 -->
|
||||
<template>
|
||||
<div class="page-container">充值管理</div>
|
||||
<div class="page-container">
|
||||
<Search
|
||||
:columns="columns"
|
||||
target="iot-card-management-search"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<JTable
|
||||
ref="rechargeRef"
|
||||
:columns="columns"
|
||||
:request="queryRechargeList"
|
||||
model="TABLE"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
:params="params"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="visible = true">
|
||||
充值
|
||||
</a-button>
|
||||
<div class="tips-text">
|
||||
<span style="margin-right: 8px; font-size: 16px">
|
||||
<AIcon type="ExclamationCircleOutlined"></AIcon>
|
||||
</span>
|
||||
本平台仅提供充值入口,具体充值结果需以运营商的充值结果为准
|
||||
</div>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #createTime="slotProps">
|
||||
{{
|
||||
slotProps.createTime
|
||||
? moment(slotProps.createTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
v-for="i in getActions(slotProps)"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
<!-- 充值 -->
|
||||
<Save v-if="visible" @change="saveChange" />
|
||||
<Detail v-if="detailVisible" :data="current" @close="close" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import moment from 'moment';
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import { queryRechargeList } from '@/api/iot-card/cardManagement';
|
||||
import Save from './Save.vue';
|
||||
import Detail from './Detail.vue';
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
const rechargeRef = ref<Record<string, any>>({});
|
||||
const params = ref<Record<string, any>>({});
|
||||
const visible = ref<boolean>(false);
|
||||
const detailVisible = ref<boolean>(false);
|
||||
const current = ref<Record<string, any>>({});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '充值金额',
|
||||
dataIndex: 'chargeMoney',
|
||||
key: 'chargeMoney',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
dataIndex: 'paymentType',
|
||||
key: 'paymentType',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
dataIndex: 'orderNumber',
|
||||
key: 'orderNumber',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '支付URL',
|
||||
dataIndex: 'url',
|
||||
key: 'url',
|
||||
},
|
||||
{
|
||||
title: '订单时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
scopedSlots: true,
|
||||
search: {
|
||||
type: 'date',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
scopedSlots: true,
|
||||
},
|
||||
];
|
||||
|
||||
const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
||||
if (!data) return [];
|
||||
return [
|
||||
{
|
||||
key: 'view',
|
||||
text: '查看',
|
||||
tooltip: {
|
||||
title: '查看',
|
||||
},
|
||||
icon: 'EyeOutlined',
|
||||
onClick: () => {
|
||||
detailVisible.value = true;
|
||||
current.value = data;
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const handleSearch = (params: any) => {
|
||||
console.log(params);
|
||||
params.value = params;
|
||||
};
|
||||
|
||||
/**
|
||||
* 充值关闭弹窗
|
||||
* @param val 加载表格
|
||||
*/
|
||||
const saveChange = (val: any) => {
|
||||
visible.value = false;
|
||||
if (val) {
|
||||
rechargeRef.value?.reload();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看详情弹窗关闭
|
||||
*/
|
||||
const close = () => {
|
||||
detailVisible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.tips-text {
|
||||
padding-left: 24px;
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<a-spin :spinning="loading">
|
||||
<a-card :bordered="false">
|
||||
<div v-if="type">
|
||||
<div v-if="type && modeType === 'add'">
|
||||
<Provider
|
||||
@onClick="goProviders"
|
||||
:dataSource="dataSource"
|
||||
|
@ -14,9 +14,21 @@
|
|||
:provider="provider"
|
||||
:data="data"
|
||||
/>
|
||||
<Media v-if="showType === 'media'" :provider="provider" />
|
||||
<Channel v-if="showType === 'channel'" :provider="provider" />
|
||||
<Edge v-if="showType === 'edge'" :provider="provider" />
|
||||
<Media
|
||||
v-if="showType === 'media'"
|
||||
:provider="provider"
|
||||
:data="data"
|
||||
/>
|
||||
<Channel
|
||||
v-if="showType === 'channel'"
|
||||
:provider="provider"
|
||||
:data="data"
|
||||
/>
|
||||
<Edge
|
||||
v-if="showType === 'edge'"
|
||||
:provider="provider"
|
||||
:data="data"
|
||||
/>
|
||||
<Cloud
|
||||
v-if="showType === 'cloud'"
|
||||
:provider="provider"
|
||||
|
@ -37,10 +49,10 @@ import Channel from '../components/Channel/index.vue';
|
|||
import Edge from '../components/Edge/index.vue';
|
||||
import Cloud from '../components/Cloud/index.vue';
|
||||
|
||||
// const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const dataSource = ref([]);
|
||||
const type = ref(false);
|
||||
|
@ -53,7 +65,6 @@ const goProviders = (param: object) => {
|
|||
showType.value = param.type;
|
||||
provider.value = param;
|
||||
type.value = false;
|
||||
console.log(1123, showType.value, param);
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
|
@ -61,80 +72,77 @@ const goBack = () => {
|
|||
type.value = true;
|
||||
};
|
||||
|
||||
const getTypeList = (result: any[]) => {
|
||||
const list = [];
|
||||
const media: any[] = [];
|
||||
const network: any[] = [];
|
||||
const cloud: any[] = [];
|
||||
const channel: any[] = [];
|
||||
const edge: any[] = [];
|
||||
result.map((item) => {
|
||||
if (item.id === 'fixed-media' || item.id === 'gb28181-2016') {
|
||||
item.type = 'media';
|
||||
media.push(item);
|
||||
} else if (item.id === 'OneNet' || item.id === 'Ctwing') {
|
||||
item.type = 'cloud';
|
||||
cloud.push(item);
|
||||
} else if (item.id === 'modbus-tcp' || item.id === 'opc-ua') {
|
||||
item.type = 'channel';
|
||||
channel.push(item);
|
||||
} else if (
|
||||
item.id === 'official-edge-gateway' ||
|
||||
item.id === 'edge-child-device'
|
||||
) {
|
||||
item.type = 'edge';
|
||||
edge.push(item);
|
||||
} else {
|
||||
item.type = 'network';
|
||||
network.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
network.length &&
|
||||
list.push({
|
||||
list: [...network],
|
||||
title: '自定义设备接入',
|
||||
});
|
||||
media.length &&
|
||||
list.push({
|
||||
list: [...media],
|
||||
title: '视频类设备接入',
|
||||
});
|
||||
cloud.length &&
|
||||
list.push({
|
||||
list: [...cloud],
|
||||
title: '云平台接入',
|
||||
});
|
||||
channel.length &&
|
||||
list.push({
|
||||
list: [...channel],
|
||||
title: '通道类设备接入',
|
||||
});
|
||||
edge.length &&
|
||||
list.push({
|
||||
list: [...edge],
|
||||
title: '官方接入',
|
||||
});
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
const queryProviders = async () => {
|
||||
const resp = await getProviders();
|
||||
if (resp.status === 200) {
|
||||
const media: any[] = [];
|
||||
const network: any[] = [];
|
||||
const cloud: any[] = [];
|
||||
const channel: any[] = [];
|
||||
const edge: any[] = [];
|
||||
resp.result.map((item) => {
|
||||
if (item.id === 'fixed-media' || item.id === 'gb28181-2016') {
|
||||
item.type = 'media';
|
||||
media.push(item);
|
||||
} else if (item.id === 'OneNet' || item.id === 'Ctwing') {
|
||||
item.type = 'cloud';
|
||||
cloud.push(item);
|
||||
} else if (item.id === 'modbus-tcp' || item.id === 'opc-ua') {
|
||||
item.type = 'channel';
|
||||
channel.push(item);
|
||||
} else if (
|
||||
item.id === 'official-edge-gateway' ||
|
||||
item.id === 'edge-child-device'
|
||||
) {
|
||||
item.type = 'edge';
|
||||
edge.push(item);
|
||||
} else {
|
||||
item.type = 'network';
|
||||
network.push(item);
|
||||
}
|
||||
});
|
||||
const list = [];
|
||||
if (network.length) {
|
||||
list.push({
|
||||
// type: 'network',
|
||||
list: [...network],
|
||||
title: '自定义设备接入',
|
||||
});
|
||||
}
|
||||
if (media.length) {
|
||||
list.push({
|
||||
// type: 'media',
|
||||
list: [...media],
|
||||
title: '视频类设备接入',
|
||||
});
|
||||
}
|
||||
if (cloud.length) {
|
||||
list.push({
|
||||
// type: 'cloud',
|
||||
list: [...cloud],
|
||||
title: '云平台接入',
|
||||
});
|
||||
}
|
||||
if (channel.length) {
|
||||
list.push({
|
||||
// type: 'channel',
|
||||
list: [...channel],
|
||||
title: '通道类设备接入',
|
||||
});
|
||||
}
|
||||
if (edge.length) {
|
||||
list.push({
|
||||
// type: 'edge',
|
||||
list: [...edge],
|
||||
title: '官方接入',
|
||||
});
|
||||
}
|
||||
dataSource.value = list;
|
||||
dataSource.value = getTypeList(resp.result);
|
||||
}
|
||||
};
|
||||
|
||||
const getProvidersData = async () => {
|
||||
if (id) {
|
||||
if (id && modeType !== 'add') {
|
||||
getProviders().then((response) => {
|
||||
if (response.status === 200) {
|
||||
dataSource.value = response.result.filter(
|
||||
const list = getTypeList(response.result);
|
||||
dataSource.value = list.filter(
|
||||
(item) =>
|
||||
item.channel === 'network' ||
|
||||
item.channel === 'child-device',
|
||||
|
@ -144,15 +152,21 @@ const getProvidersData = async () => {
|
|||
const dt = response.result.find(
|
||||
(item) => item?.id === resp.result.provider,
|
||||
);
|
||||
|
||||
response.result.forEach((item) => {
|
||||
if (item.id === resp.result.provider) {
|
||||
resp.result.type = item.type;
|
||||
showType.value = item.type;
|
||||
}
|
||||
});
|
||||
|
||||
provider.value = dt;
|
||||
data.value = resp.result;
|
||||
type.value = false;
|
||||
}
|
||||
});
|
||||
loading.value = false;
|
||||
} else {
|
||||
loading.value = false;
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
type.value = true;
|
||||
|
|
|
@ -39,7 +39,10 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" html-type="submit"
|
||||
<a-button
|
||||
v-if="modeType !== 'view'"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>保存</a-button
|
||||
>
|
||||
</a-form-item>
|
||||
|
@ -93,18 +96,23 @@ interface FormState {
|
|||
description: string;
|
||||
}
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const type = ref(props.provider.type);
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
const formState = ref<FormState>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
@ -117,7 +125,10 @@ const onFinish = async (values: any) => {
|
|||
transport: ProtocolMapping.get(providerId),
|
||||
channel: providerId === 'modbus-tcp' ? 'modbus' : 'opc-ua',
|
||||
};
|
||||
const resp = !!id ? await update({ ...params, id }) : await save(params);
|
||||
const resp =
|
||||
!!id && modeType !== 'add'
|
||||
? await update({ ...params, id })
|
||||
: await save(params);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
// if (params.get('save')) {
|
||||
|
@ -132,6 +143,15 @@ const onFinish = async (values: any) => {
|
|||
// }
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (modeType !== 'add') {
|
||||
formState.value = {
|
||||
name: props.data.name,
|
||||
description: props.data?.description || '',
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -199,7 +199,7 @@
|
|||
<title-component data="基本信息" />
|
||||
<div>
|
||||
<a-form
|
||||
:model="form"
|
||||
:model="formData"
|
||||
name="basic"
|
||||
autocomplete="off"
|
||||
layout="vertical"
|
||||
|
@ -219,14 +219,14 @@
|
|||
>
|
||||
<a-input
|
||||
placeholder="请输入名称"
|
||||
v-model:value="form.name"
|
||||
v-model:value="formData.name"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="说明" name="description">
|
||||
<a-textarea
|
||||
placeholder="请输入说明"
|
||||
:rows="4"
|
||||
v-model:value="form.description"
|
||||
v-model:value="formData.description"
|
||||
show-count
|
||||
:maxlength="200"
|
||||
/>
|
||||
|
@ -277,16 +277,20 @@
|
|||
<a-button
|
||||
v-if="[0, 1].includes(current)"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="next"
|
||||
>
|
||||
下一步
|
||||
</a-button>
|
||||
<a-button v-if="current === 2" type="primary" @click="saveData">
|
||||
<a-button
|
||||
v-if="current === 2 && modeType !== 'view'"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="saveData"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" style="margin-left: 8px" @click="prev">
|
||||
上一步
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" @click="prev"> 上一步 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -379,7 +383,8 @@ interface Form {
|
|||
description: string;
|
||||
}
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
|
@ -396,13 +401,13 @@ const channel = ref(props.provider.channel);
|
|||
const formRef1 = ref<FormInstance>();
|
||||
const formRef2 = ref<FormInstance>();
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
const formState = ref<FormState>({
|
||||
apiAddress: 'https://ag-api.ctwing.cn/',
|
||||
appKey: '',
|
||||
appSecret: '',
|
||||
description: '',
|
||||
});
|
||||
const form = reactive<Form>({
|
||||
const formData = ref<Form>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
@ -415,9 +420,7 @@ const allProcotolList = ref([]);
|
|||
const procotolCurrent = ref('');
|
||||
|
||||
const procotolChange = (id: string) => {
|
||||
if (!props.data?.id) {
|
||||
procotolCurrent.value = id;
|
||||
}
|
||||
procotolCurrent.value = id;
|
||||
};
|
||||
|
||||
const procotolSearch = (value: string) => {
|
||||
|
@ -439,7 +442,7 @@ const saveData = async () => {
|
|||
const params = {
|
||||
...data,
|
||||
configuration: {
|
||||
...formState,
|
||||
...formState.value,
|
||||
protocol: procotolCurrent.value,
|
||||
},
|
||||
protocol: procotolCurrent.value,
|
||||
|
@ -447,7 +450,7 @@ const saveData = async () => {
|
|||
transport: 'HTTP_SERVER',
|
||||
};
|
||||
const resp =
|
||||
props.data && props.data.id
|
||||
!!id && modeType !== 'add'
|
||||
? await update({
|
||||
...props.data,
|
||||
...params,
|
||||
|
@ -514,7 +517,16 @@ const next = async () => {
|
|||
const prev = () => {
|
||||
current.value = current.value - 1;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (modeType !== 'add') {
|
||||
formState.value = props.data.configuration;
|
||||
procotolCurrent.value = props.data.protocol;
|
||||
formData.value = {
|
||||
name: props.data.name,
|
||||
description: props.data.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
watch(
|
||||
current,
|
||||
(v) => {
|
||||
|
|
|
@ -292,7 +292,7 @@
|
|||
<title-component data="基本信息" />
|
||||
<div>
|
||||
<a-form
|
||||
:model="form"
|
||||
:model="formData"
|
||||
name="basic"
|
||||
autocomplete="off"
|
||||
layout="vertical"
|
||||
|
@ -312,26 +312,18 @@
|
|||
>
|
||||
<a-input
|
||||
placeholder="请输入名称"
|
||||
v-model:value="form.name"
|
||||
v-model:value="formData.name"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="说明" name="description">
|
||||
<a-textarea
|
||||
placeholder="请输入说明"
|
||||
:rows="4"
|
||||
v-model:value="form.description"
|
||||
v-model:value="formData.description"
|
||||
show-count
|
||||
:maxlength="200"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- <a-form-item>
|
||||
<a-button
|
||||
v-if="current !== 1"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>保存</a-button
|
||||
>
|
||||
</a-form-item> -->
|
||||
</a-form>
|
||||
</div>
|
||||
</a-col>
|
||||
|
@ -378,16 +370,20 @@
|
|||
<a-button
|
||||
v-if="[0, 1].includes(current)"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="next"
|
||||
>
|
||||
下一步
|
||||
</a-button>
|
||||
<a-button v-if="current === 2" type="primary" @click="saveData">
|
||||
<a-button
|
||||
style="margin-right: 8px"
|
||||
v-if="current === 2 && modeType !== 'view'"
|
||||
type="primary"
|
||||
@click="saveData"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" style="margin-left: 8px" @click="prev">
|
||||
上一步
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" @click="prev"> 上一步 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -483,7 +479,8 @@ interface Form {
|
|||
description: string;
|
||||
}
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
|
@ -500,14 +497,14 @@ const channel = ref(props.provider.channel);
|
|||
const formRef1 = ref<FormInstance>();
|
||||
const formRef2 = ref<FormInstance>();
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
const formState = ref<FormState>({
|
||||
apiAddress: 'https://api.heclouds.com/',
|
||||
apiKey: '',
|
||||
validateToken: '',
|
||||
aesKey: '',
|
||||
description: '',
|
||||
});
|
||||
const form = reactive<Form>({
|
||||
const formData = ref<Form>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
@ -520,9 +517,7 @@ const allProcotolList = ref([]);
|
|||
const procotolCurrent = ref('');
|
||||
|
||||
const procotolChange = (id: string) => {
|
||||
if (!props.data?.id) {
|
||||
procotolCurrent.value = id;
|
||||
}
|
||||
procotolCurrent.value = id;
|
||||
};
|
||||
|
||||
const procotolSearch = (value: string) => {
|
||||
|
@ -544,7 +539,7 @@ const saveData = async () => {
|
|||
const params = {
|
||||
...data,
|
||||
configuration: {
|
||||
...formState,
|
||||
...formState.value,
|
||||
protocol: procotolCurrent.value,
|
||||
},
|
||||
protocol: procotolCurrent.value,
|
||||
|
@ -552,7 +547,7 @@ const saveData = async () => {
|
|||
transport: 'HTTP_SERVER',
|
||||
};
|
||||
const resp =
|
||||
props.data && props.data.id
|
||||
!!id && modeType !== 'add'
|
||||
? await update({
|
||||
...props.data,
|
||||
...params,
|
||||
|
@ -619,6 +614,17 @@ const prev = () => {
|
|||
current.value = current.value - 1;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (modeType !== 'add') {
|
||||
formState.value = props.data.configuration;
|
||||
procotolCurrent.value = props.data.protocol;
|
||||
formData.value = {
|
||||
name: props.data.name,
|
||||
description: props.data.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
current,
|
||||
(v) => {
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
import Ctwing from './Ctwing.vue';
|
||||
import OneNet from './OneNet.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
type: Object,
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
v-if="current !== 1"
|
||||
v-if="current !== 1 && modeType !== 'view'"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>保存</a-button
|
||||
|
@ -171,15 +171,22 @@
|
|||
v-if="channel !== 'edge-child-device'"
|
||||
:class="current !== 1 ? 'steps-action' : 'steps-action-save'"
|
||||
>
|
||||
<a-button v-if="[0].includes(current)" @click="next">
|
||||
<a-button
|
||||
v-if="[0].includes(current)"
|
||||
style="margin-right: 8px"
|
||||
@click="next"
|
||||
>
|
||||
下一步
|
||||
</a-button>
|
||||
<a-button v-if="current === 1" type="primary" @click="saveData">
|
||||
<a-button
|
||||
v-if="current === 1 && modeType !== 'view'"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="saveData"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" style="margin-left: 8px" @click="prev">
|
||||
上一步
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" @click="prev"> 上一步 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -290,19 +297,25 @@ interface FormState {
|
|||
description: string;
|
||||
}
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const type = ref(props.provider.type);
|
||||
const type = props.provider.type;
|
||||
|
||||
const channel = ref(props.provider.channel);
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
const formState = ref<FormState>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
@ -324,9 +337,10 @@ const onFinish = async (values: any) => {
|
|||
transport: ProtocolMapping.get(providerId),
|
||||
};
|
||||
if (networkCurrent.value) params.channelId = networkCurrent.value;
|
||||
console.log(1112, networkCurrent.value, params);
|
||||
|
||||
const resp = !!id ? await update({ ...params, id }) : await save(params);
|
||||
const resp =
|
||||
!!id && modeType !== 'add'
|
||||
? await update({ ...params, id })
|
||||
: await save(params);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
// if (params.get('save')) {
|
||||
|
@ -407,6 +421,13 @@ onMounted(() => {
|
|||
if (props.provider.id === 'official-edge-gateway') {
|
||||
queryNetworkList(props.provider.id, '');
|
||||
}
|
||||
if (modeType !== 'add') {
|
||||
formState.value = {
|
||||
name: props.data.name,
|
||||
description: props.data?.description || '',
|
||||
};
|
||||
networkCurrent.value = props.data.channelId;
|
||||
}
|
||||
}),
|
||||
watch(
|
||||
current,
|
||||
|
|
|
@ -436,17 +436,18 @@
|
|||
<a-col :span="12">
|
||||
<title-component data="基本信息" />
|
||||
<div>
|
||||
<a-form :model="form" layout="vertical">
|
||||
<a-form :model="formData" layout="vertical">
|
||||
<a-form-item
|
||||
label="名称"
|
||||
v-bind="validateInfos.name"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
v-model:value="formData.name"
|
||||
allowClear
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="说明"
|
||||
v-bind="validateInfos.description"
|
||||
|
@ -454,7 +455,7 @@
|
|||
<a-textarea
|
||||
placeholder="请输入说明"
|
||||
:rows="4"
|
||||
v-model:value="form.description"
|
||||
v-model:value="formData.description"
|
||||
show-count
|
||||
:maxlength="200"
|
||||
/>
|
||||
|
@ -494,15 +495,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="steps-action">
|
||||
<a-button v-if="[0].includes(current)" @click="next">
|
||||
<a-button
|
||||
v-if="[0].includes(current)"
|
||||
style="margin-right: 8px"
|
||||
@click="next"
|
||||
>
|
||||
下一步
|
||||
</a-button>
|
||||
<a-button v-if="current === 1" type="primary" @click="saveData">
|
||||
<a-button
|
||||
v-if="current === 1 && modeType !== 'view'"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="saveData"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" style="margin-left: 8px" @click="prev">
|
||||
上一步
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" @click="prev"> 上一步 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -544,10 +552,15 @@ const props = defineProps({
|
|||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const activeKey: any = ref([]);
|
||||
const clientHeight = document.body.clientHeight;
|
||||
|
@ -559,11 +572,11 @@ const useForm = Form.useForm;
|
|||
const current = ref(0);
|
||||
const stepCurrent = ref(0);
|
||||
const steps = ref(['信令配置', '完成']);
|
||||
const form = reactive({
|
||||
const formData = ref({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
const formState = reactive<FormState>({
|
||||
let formState = ref<FormState>({
|
||||
domain: '',
|
||||
sipId: '',
|
||||
shareCluster: true,
|
||||
|
@ -574,6 +587,7 @@ const formState = reactive<FormState>({
|
|||
publicHost: '',
|
||||
},
|
||||
});
|
||||
|
||||
let params = {
|
||||
configuration: {},
|
||||
};
|
||||
|
@ -628,12 +642,13 @@ const handleChangeForm2Sip = (index: number) => {
|
|||
};
|
||||
|
||||
const { resetFields, validate, validateInfos } = useForm(
|
||||
form,
|
||||
formData,
|
||||
reactive({
|
||||
name: [
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -646,9 +661,11 @@ const saveData = () => {
|
|||
transport: 'SIP',
|
||||
channel: 'gb28181',
|
||||
};
|
||||
const resp = !!id
|
||||
? await update({ ...params, id })
|
||||
: await save(params);
|
||||
|
||||
const resp =
|
||||
!!id && modeType !== 'add'
|
||||
? await update({ ...params, id })
|
||||
: await save(params);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
// if (params.get('save')) {
|
||||
|
@ -723,6 +740,14 @@ onMounted(() => {
|
|||
clustersList.value = list;
|
||||
}
|
||||
});
|
||||
|
||||
if (modeType !== 'add') {
|
||||
formState.value = props.data.configuration;
|
||||
formData.value = {
|
||||
name: props.data.name,
|
||||
description: props.data?.description || '',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
|
|
|
@ -39,7 +39,10 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" html-type="submit"
|
||||
<a-button
|
||||
v-if="modeType !== 'view'"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>保存</a-button
|
||||
>
|
||||
</a-form-item>
|
||||
|
@ -72,7 +75,7 @@
|
|||
</a-row>
|
||||
</div>
|
||||
<div v-else-if="channel === 'gb28181'">
|
||||
<GB28181 :provider="props.provider"></GB28181>
|
||||
<GB28181 :provider="props.provider" :data="props.data"></GB28181>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -88,18 +91,23 @@ interface FormState {
|
|||
description: string;
|
||||
}
|
||||
const route = useRoute();
|
||||
const id = route.query.id;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const channel = ref(props.provider.channel);
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
const formState = ref<FormState>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
@ -110,7 +118,10 @@ const onFinish = async (values: any) => {
|
|||
transport: 'URL',
|
||||
channel: 'fixed-media',
|
||||
};
|
||||
const resp = !!id ? await update({ ...params, id }) : await save(params);
|
||||
const resp =
|
||||
!!id && modeType !== 'add'
|
||||
? await update({ ...params, id })
|
||||
: await save(params);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
// if (params.get('save')) {
|
||||
|
@ -125,6 +136,15 @@ const onFinish = async (values: any) => {
|
|||
// }
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (modeType !== 'add') {
|
||||
formState.value = {
|
||||
name: props.data.name,
|
||||
description: props.data?.description || '',
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
<div>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:model="formData"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-item
|
||||
|
@ -146,7 +146,7 @@
|
|||
v-bind="validateInfos.name"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
v-model:value="formData.name"
|
||||
allowClear
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
|
@ -158,7 +158,7 @@
|
|||
<a-textarea
|
||||
placeholder="请输入说明"
|
||||
:rows="4"
|
||||
v-model:value="form.description"
|
||||
v-model:value="formData.description"
|
||||
show-count
|
||||
:maxlength="200"
|
||||
/>
|
||||
|
@ -295,13 +295,26 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="steps-action">
|
||||
<a-button v-if="[0, 1].includes(current)" @click="next">
|
||||
<a-button
|
||||
v-if="[0, 1].includes(current)"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="next"
|
||||
>
|
||||
下一步
|
||||
</a-button>
|
||||
<a-button v-if="current === 2" type="primary" @click="saveData">
|
||||
<a-button
|
||||
v-if="current === 2 && modeType !== 'view'"
|
||||
type="primary"
|
||||
style="margin-right: 8px"
|
||||
@click="saveData"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button v-if="current > 0" style="margin-left: 8px" @click="prev">
|
||||
<a-button
|
||||
v-if="type === 'child-device' ? current > 1 : current > 0"
|
||||
@click="prev"
|
||||
>
|
||||
上一步
|
||||
</a-button>
|
||||
</div>
|
||||
|
@ -524,7 +537,204 @@ const result2 = {
|
|||
'### 认证说明\r\n\r\nCONNECT报文:\r\n```text\r\nclientId: 设备ID\r\nusername: secureId+"|"+timestamp\r\npassword: md5(secureId+"|"+timestamp+"|"+secureKey)\r\n ```\r\n\r\n说明: secureId以及secureKey在创建设备产品或设备实例时进行配置. \r\ntimestamp为当前时间戳(毫秒),与服务器时间不能相差5分钟.\r\nmd5为32位,不区分大小写.',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
//测试数据
|
||||
const networkData = {
|
||||
COAP_SERVER: [
|
||||
{
|
||||
id: '1620352949679960064',
|
||||
name: '前端测试1',
|
||||
description: '前端测试1',
|
||||
addresses: [
|
||||
{
|
||||
address: 'coap://111.0.0:88',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1613071630619607040',
|
||||
name: '1',
|
||||
addresses: [
|
||||
{
|
||||
address: 'coap://120.77.179.54:9000',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
UDP: [
|
||||
{
|
||||
id: '1590553821093437440',
|
||||
name: '194',
|
||||
addresses: [
|
||||
{
|
||||
address: 'udp://139.217.130.194:1883',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1585831257204301824',
|
||||
name: '测试隐藏集群',
|
||||
description: '111',
|
||||
addresses: [
|
||||
{
|
||||
address: 'udp://127.0.0.1:8080',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1584825665263149056',
|
||||
name: '1',
|
||||
addresses: [
|
||||
{
|
||||
address: 'udp://120.77.179.54:9000',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1551761481741672448',
|
||||
name: '0726UDP',
|
||||
description: '测试',
|
||||
addresses: [
|
||||
{
|
||||
address: 'udp://120.77.179.54:8088',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
TCP_SERVER: [
|
||||
{
|
||||
id: '1603206069979918336',
|
||||
name: '测试A',
|
||||
addresses: [
|
||||
{
|
||||
address: 'tcp://120.77.179.54:8106',
|
||||
health: -1,
|
||||
ok: false,
|
||||
bad: false,
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1603206069979918330',
|
||||
name: '测试AA',
|
||||
addresses: [
|
||||
{
|
||||
address: 'tcp://120.77.179.54:8106',
|
||||
health: -1,
|
||||
ok: false,
|
||||
bad: false,
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
MQTT_SERVER: [
|
||||
{
|
||||
id: '1585192878304051200',
|
||||
name: 'MQTT网络组件',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://120.77.179.54:8101',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1583268266806009856',
|
||||
name: '我的第一个MQTT服务组件',
|
||||
description: '',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://120.77.179.54:8100',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1570335308902912000',
|
||||
name: '0915MQTT网络组件_勿动',
|
||||
description: '测试,勿动!',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://120.77.179.54:8083',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1567062350140858368',
|
||||
name: '网络组件20220906160907',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://120.77.179.54:8083',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1556563257890742272',
|
||||
name: 'MQTT网络组件',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://0.0.0.0:8104',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1534774770408108032',
|
||||
name: 'MQTT',
|
||||
addresses: [
|
||||
{
|
||||
address: 'mqtt://120.77.179.54:8088',
|
||||
health: 1,
|
||||
ok: true,
|
||||
bad: false,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
function generateUUID() {
|
||||
var d = new Date().getTime();
|
||||
if (
|
||||
|
@ -555,6 +765,10 @@ const props = defineProps({
|
|||
});
|
||||
|
||||
const clientHeight = document.body.clientHeight;
|
||||
const type = props.provider.channel;
|
||||
const route = useRoute();
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const useForm = Form.useForm;
|
||||
|
@ -569,29 +783,40 @@ const networkCurrent = ref('');
|
|||
const procotolCurrent = ref('');
|
||||
let config = ref({});
|
||||
let columnsMQTT = ref(<TableColumnType>[]);
|
||||
const form = reactive({
|
||||
const formData = ref({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
|
||||
const { resetFields, validate, validateInfos } = useForm(
|
||||
form,
|
||||
formData,
|
||||
reactive({
|
||||
name: [
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
],
|
||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
}),
|
||||
);
|
||||
|
||||
const queryNetworkList = async (id: string, include: string, data = {}) => {
|
||||
if (NetworkTypeMapping.get(id) === 'MQTT_SERVER') {
|
||||
//使用测试数据
|
||||
networkList.value = networkData[NetworkTypeMapping.get(id)];
|
||||
// return;
|
||||
}
|
||||
const resp = await getNetworkList(
|
||||
NetworkTypeMapping.get(id),
|
||||
include,
|
||||
data,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
networkList.value = resp.result;
|
||||
//使用测试数据
|
||||
// networkList.value = resp.result;
|
||||
networkList.value =
|
||||
resp.result.length === 0
|
||||
? networkData[NetworkTypeMapping.get(id)]
|
||||
: resp.result;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -686,7 +911,7 @@ const saveData = () => {
|
|||
channel: 'network', // 网络组件
|
||||
channelId: networkCurrent.value,
|
||||
};
|
||||
if (props.data && props.data.id) {
|
||||
if (!!id && modeType !== 'add') {
|
||||
resp = await update(params);
|
||||
} else {
|
||||
params = {
|
||||
|
@ -702,12 +927,13 @@ const saveData = () => {
|
|||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
// 回到列表页面
|
||||
if (window.onTabSaveSuccess) {
|
||||
window.onTabSaveSuccess(resp);
|
||||
setTimeout(() => window.close(), 300);
|
||||
} else {
|
||||
// this.$store.dispatch('jumpPathByKey', { key: MenuKeys['Link/AccessConfig'] })
|
||||
}
|
||||
// if (window.onTabSaveSuccess) {
|
||||
// window.onTabSaveSuccess(resp);
|
||||
// setTimeout(() => window.close(), 300);
|
||||
// } else {
|
||||
// // this.$store.dispatch('jumpPathByKey', { key: MenuKeys['Link/AccessConfig'] })
|
||||
// }
|
||||
history.back();
|
||||
}
|
||||
})
|
||||
.catch((err) => {});
|
||||
|
@ -781,7 +1007,7 @@ const next = async () => {
|
|||
];
|
||||
|
||||
// const resp =
|
||||
// props.provider.channel !== 'child-device'
|
||||
// type !== 'child-device'
|
||||
// ? await getConfigView(
|
||||
// procotolCurrent.value,
|
||||
// ProtocolMapping.get(props.provider.id),
|
||||
|
@ -864,7 +1090,7 @@ onMounted(() => {
|
|||
}
|
||||
} else {
|
||||
if (props.provider?.id) {
|
||||
if (props.provider.channel !== 'child-device') {
|
||||
if (type !== 'child-device') {
|
||||
queryNetworkList(props.provider.id, '');
|
||||
steps.value = ['网络组件', '消息协议', '完成'];
|
||||
current.value = 0;
|
||||
|
@ -877,14 +1103,20 @@ onMounted(() => {
|
|||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (modeType !== 'add') {
|
||||
procotolCurrent.value = props.data.protocol;
|
||||
formData.value = {
|
||||
name: props.data.name,
|
||||
description: props.data.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
current,
|
||||
(v) => {
|
||||
if (props.provider.channel !== 'child-device') {
|
||||
stepCurrent.value = v;
|
||||
} else {
|
||||
stepCurrent.value = v - 1;
|
||||
}
|
||||
stepCurrent.value = type === 'child-device' ? v - 1 : v;
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
|
|
|
@ -44,8 +44,13 @@
|
|||
</template>
|
||||
<template #content>
|
||||
<div class="card-item-content">
|
||||
<h3 class="card-item-content-title">
|
||||
<a href="">{{ slotProps.name }}</a>
|
||||
<h3
|
||||
@click="handlEye(slotProps.id)"
|
||||
class="card-item-content-title"
|
||||
>
|
||||
<a class="card-item-content-title-a">{{
|
||||
slotProps.name
|
||||
}}</a>
|
||||
</h3>
|
||||
<a-row class="card-item-content-box">
|
||||
<a-col
|
||||
|
@ -110,19 +115,23 @@
|
|||
<a-tooltip>
|
||||
<template #title>
|
||||
{{
|
||||
providersList.find(
|
||||
(item) =>
|
||||
item.id ===
|
||||
slotProps.provider,
|
||||
)?.description
|
||||
}}</template
|
||||
>
|
||||
slotProps.description
|
||||
? slotProps.description
|
||||
: providersList.find(
|
||||
(item) =>
|
||||
item.id ===
|
||||
slotProps.provider,
|
||||
)?.description
|
||||
}}
|
||||
</template>
|
||||
{{
|
||||
providersList.find(
|
||||
(item) =>
|
||||
item.id ===
|
||||
slotProps.provider,
|
||||
)?.description
|
||||
slotProps.description
|
||||
? slotProps.description
|
||||
: providersList.find(
|
||||
(item) =>
|
||||
item.id ===
|
||||
slotProps.provider,
|
||||
)?.description
|
||||
}}
|
||||
</a-tooltip>
|
||||
</div>
|
||||
|
@ -184,7 +193,13 @@
|
|||
<script lang="ts" setup name="AccessConfigPage">
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { list, getProviders } from '@/api/link/accessConfig';
|
||||
import {
|
||||
list,
|
||||
getProviders,
|
||||
remove,
|
||||
undeploy,
|
||||
deploy,
|
||||
} from '@/api/link/accessConfig';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const tableRef = ref<Record<string, any>>({});
|
||||
|
@ -261,9 +276,8 @@ const columns = [
|
|||
];
|
||||
|
||||
const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
if (!data) return [];
|
||||
const state = data.state.value;
|
||||
return [
|
||||
{
|
||||
key: 'edit',
|
||||
|
@ -276,15 +290,47 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
|||
handlEdit(data.id);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
text: state === 'enabled' ? '禁用' : '启用',
|
||||
tooltip: {
|
||||
title: state === 'enabled' ? '禁用' : '启用',
|
||||
},
|
||||
icon: state === 'enabled' ? 'StopOutlined' : 'CheckCircleOutlined',
|
||||
popConfirm: {
|
||||
title: `确认${state === 'enabled' ? '禁用' : '启用'}?`,
|
||||
onConfirm: async () => {
|
||||
let res =
|
||||
state === 'enabled'
|
||||
? await undeploy(data.id)
|
||||
: await deploy(data.id);
|
||||
|
||||
if (res.success) {
|
||||
message.success('操作成功');
|
||||
tableRef.value?.reload();
|
||||
} else {
|
||||
message.error('操作失败!');
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
text: '删除',
|
||||
disabled: state === 'enabled',
|
||||
tooltip: {
|
||||
title: state === 'enabled' ? '已启用的设备不能删除' : '删除',
|
||||
},
|
||||
popConfirm: {
|
||||
title: '确认删除?',
|
||||
okText: ' 确定',
|
||||
cancelText: '取消',
|
||||
onConfirm: async () => {
|
||||
handlDelete(data.id);
|
||||
const res = await remove(data.id);
|
||||
if (res.success) {
|
||||
message.success('操作成功');
|
||||
tableRef.value.reload();
|
||||
} else {
|
||||
message.error('操作失败!');
|
||||
}
|
||||
},
|
||||
},
|
||||
icon: 'DeleteOutlined',
|
||||
|
@ -299,21 +345,13 @@ const getProvidersList = async () => {
|
|||
getProvidersList();
|
||||
|
||||
const handlAdd = () => {
|
||||
router.push('/link/accessConfig/detail/add');
|
||||
|
||||
// router.push('/link/certificate/detail/add/new');
|
||||
router.push('/link/accessConfig/detail/add/new');
|
||||
};
|
||||
|
||||
const handlEdit = (id: string) => {
|
||||
router.push(`/link/certificate/detail/edit/${id}`);
|
||||
router.push(`/link/accessConfig/detail/edit/${id}`);
|
||||
};
|
||||
|
||||
const handlDelete = async (id: string) => {
|
||||
const res = await remove(id);
|
||||
if (res.success) {
|
||||
message.success('操作成功');
|
||||
tableRef.value.reload();
|
||||
}
|
||||
const handlEye = (id: string) => {
|
||||
router.push(`/link/accessConfig/detail/view/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -356,6 +394,14 @@ const handleSearch = (e: any) => {
|
|||
.card-item-content {
|
||||
min-height: 100px;
|
||||
|
||||
.card-item-content-title-a {
|
||||
// color: #000 !important;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
overflow: hidden; //超出的文本隐藏
|
||||
text-overflow: ellipsis; //溢出用省略号显示
|
||||
white-space: nowrap; //溢出不换行
|
||||
}
|
||||
.card-item-content-box {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
<a-form-item>
|
||||
<a-button
|
||||
v-if="type !== 'view'"
|
||||
v-if="modeType !== 'view'"
|
||||
class="form-submit"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
|
@ -103,7 +103,7 @@ import { FormDataType, TypeObjType } from '../type';
|
|||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const type = route.params.type as string;
|
||||
const modeType = route.params.type as string;
|
||||
const id = route.params.id as string;
|
||||
|
||||
const useForm = Form.useForm;
|
||||
|
@ -145,7 +145,7 @@ const onSubmit = () => {
|
|||
const params = toRaw(formData.value);
|
||||
loading.value = true;
|
||||
const response =
|
||||
type === 'edit' ? await update(params) : await save(params);
|
||||
modeType === 'edit' ? await update(params) : await save(params);
|
||||
if (response.status === 200) {
|
||||
message.success('操作成功');
|
||||
router.push('/link/certificate');
|
||||
|
@ -168,7 +168,7 @@ const handleChange = (info: UploadChangeParam) => {
|
|||
};
|
||||
|
||||
const detail = async (id: string) => {
|
||||
if (type !== 'add') {
|
||||
if (modeType !== 'add') {
|
||||
loading.value = true;
|
||||
const res = await queryDetail(id);
|
||||
if (res.success) {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
123
|
||||
</template>
|
|
@ -148,7 +148,7 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
|||
}
|
||||
|
||||
const add = () => {
|
||||
message.warn('123')
|
||||
// router.push(`/northbound/DuerOS/detail/:id`)
|
||||
}
|
||||
|
||||
</script>
|
|
@ -64,7 +64,7 @@
|
|||
import { Form } from 'ant-design-vue';
|
||||
import { PropType } from 'vue';
|
||||
import ConfigApi from '@/api/notice/config';
|
||||
import {
|
||||
import type {
|
||||
TemplateFormData,
|
||||
IVariableDefinitions,
|
||||
} from '@/views/notice/Template/types';
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<script setup lang="ts">
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
||||
import { PropType } from 'vue';
|
||||
import { IHeaders } from '../../types';
|
||||
import type { IHeaders } from '../../types';
|
||||
|
||||
type Emits = {
|
||||
(e: 'update:headers', data: IHeaders[]): void;
|
||||
|
|
|
@ -279,7 +279,7 @@
|
|||
import { getImage } from '@/utils/comm';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { ConfigFormData } from '../types';
|
||||
import type { ConfigFormData } from '../types';
|
||||
import {
|
||||
NOTICE_METHOD,
|
||||
CONFIG_FIELD_MAP,
|
||||
|
|
|
@ -91,7 +91,10 @@
|
|||
v-for="(o, i) in item.children"
|
||||
:key="i"
|
||||
>
|
||||
<a-button type="link" @click="o.onClick">
|
||||
<a-button
|
||||
type="link"
|
||||
@click="o.onClick"
|
||||
>
|
||||
<AIcon :type="o.icon" />
|
||||
<span>{{ o.text }}</span>
|
||||
</a-button>
|
||||
|
@ -167,9 +170,8 @@
|
|||
<script setup lang="ts">
|
||||
import ConfigApi from '@/api/notice/config';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { getImage, LocalStore } from '@/utils/comm';
|
||||
|
||||
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 SyncUser from './SyncUser/index.vue';
|
||||
|
@ -266,7 +268,7 @@ const getMethodTxt = (type: string) => {
|
|||
* 新增
|
||||
*/
|
||||
const handleAdd = () => {
|
||||
router.push(`/notice/Config/detail/:id`);
|
||||
router.push(`/iot/notice/Config/detail/:id`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -306,13 +308,6 @@ const handleExport = () => {
|
|||
downloadObject(configRef.value.dataSource, `通知配置`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
const handleView = (id: string) => {
|
||||
message.warn(id + '暂未开发');
|
||||
};
|
||||
|
||||
const syncVis = ref(false);
|
||||
const debugVis = ref(false);
|
||||
const logVis = ref(false);
|
||||
|
@ -333,7 +328,7 @@ const getActions = (
|
|||
onClick: () => {
|
||||
// visible.value = true;
|
||||
// current.value = data;
|
||||
router.push(`/notice/Config/detail/${data.id}`);
|
||||
router.push(`/iot/notice/Config/detail/${data.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -360,35 +355,6 @@ const getActions = (
|
|||
currentConfig.value = data;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// key: 'others',
|
||||
// text: '其他',
|
||||
// children: [
|
||||
// {
|
||||
// key: 'debug',
|
||||
// text: '导出',
|
||||
// tooltip: {
|
||||
// title: '导出',
|
||||
// },
|
||||
// icon: 'ArrowDownOutlined',
|
||||
// onClick: () => {
|
||||
// downloadObject(data, `通知配置`);
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// key: 'sync',
|
||||
// text: '同步用户',
|
||||
// tooltip: {
|
||||
// title: '同步用户',
|
||||
// },
|
||||
// icon: 'TeamOutlined',
|
||||
// onClick: () => {
|
||||
// syncVis.value = true;
|
||||
// currentConfig.value = data;
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
key: 'delete',
|
||||
text: '删除',
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
import { Form } from 'ant-design-vue';
|
||||
import { PropType } from 'vue';
|
||||
import TemplateApi from '@/api/notice/template';
|
||||
import {
|
||||
import type {
|
||||
TemplateFormData,
|
||||
IVariableDefinitions,
|
||||
BindConfig,
|
||||
|
|
|
@ -47,7 +47,7 @@ import {
|
|||
UploadOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { PropType } from 'vue';
|
||||
import { IAttachments } from '../../types';
|
||||
import type { IAttachments } from '../../types';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
|
|
|
@ -477,7 +477,7 @@
|
|||
import { getImage } from '@/utils/comm';
|
||||
import { Form, UploadChangeParam } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { IVariableDefinitions, TemplateFormData } from '../types';
|
||||
import type { IVariableDefinitions, TemplateFormData } from '../types';
|
||||
import {
|
||||
NOTICE_METHOD,
|
||||
TEMPLATE_FIELD_MAP,
|
||||
|
|
|
@ -256,7 +256,7 @@ const getMethodTxt = (type: string) => {
|
|||
* 新增
|
||||
*/
|
||||
const handleAdd = () => {
|
||||
router.push(`/notice/Template/detail/:id`);
|
||||
router.push(`/iot/notice/Template/detail/:id`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -323,7 +323,7 @@ const getActions = (
|
|||
onClick: () => {
|
||||
// visible.value = true;
|
||||
// current.value = data;
|
||||
router.push(`/notice/Template/detail/${data.id}`);
|
||||
router.push(`/iot/notice/Template/detail/${data.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -170,22 +170,18 @@
|
|||
placeholder="请选择关联菜单"
|
||||
multiple
|
||||
show-search
|
||||
tree-default-expand-all
|
||||
:tree-data="form.treeData"
|
||||
:field-names="{
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
}"
|
||||
>
|
||||
<template #title="{ value: val, title }">
|
||||
<b
|
||||
v-if="val === 'parent 1-1'"
|
||||
style="color: #08c"
|
||||
>{{ val }}</b
|
||||
>
|
||||
<template v-else>{{ title }}</template>
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item label="权限">
|
||||
<PermissChoose v-model:value="form.data.permissions" />
|
||||
<PermissChoose :first-width="3" max-height="350px" v-model:value="form.data.permissions" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
|
@ -245,17 +241,16 @@ const form = reactive({
|
|||
|
||||
treeData: [], // 关联菜单
|
||||
assetsType: [] as assetType[], // 资产类型
|
||||
premissonList: [], // 权限列表
|
||||
|
||||
init: () => {
|
||||
// 获取菜单详情
|
||||
routeParams.id &&
|
||||
getMenuInfo_api(routeParams.id).then((resp) => {
|
||||
console.log('菜单详情', resp);
|
||||
form.data = resp.result as formType
|
||||
});
|
||||
// 获取关联菜单
|
||||
getMenuTree_api({ paging: false }).then((resp) => {
|
||||
console.log('关联菜单', resp);
|
||||
getMenuTree_api({ paging: false }).then((resp: any) => {
|
||||
form.treeData = resp.result;
|
||||
});
|
||||
// 获取资产类型
|
||||
getAssetsType_api().then((resp: any) => {
|
||||
|
|
|
@ -1,18 +1,134 @@
|
|||
<template>
|
||||
<div class="button-mange-container">
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
model="TABLE"
|
||||
:dataSource="table.data"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-button
|
||||
type="primary"
|
||||
style="margin-right: 10px"
|
||||
@click="() => dialog.openDialog()"
|
||||
><plus-outlined />新增</a-button
|
||||
>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip>
|
||||
<template #title>编辑</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
@click="() => dialog.openDialog(slotProps)"
|
||||
>
|
||||
<edit-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>查看</template>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
@click="() => dialog.openDialog(slotProps)"
|
||||
>
|
||||
<edit-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
<a-popconfirm
|
||||
title="确认删除"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<a-tooltip>
|
||||
<template #title>删除</template>
|
||||
<a-button style="padding: 0" type="link">
|
||||
<delete-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialog">
|
||||
<ButtonAddDialog ref="dialogRef" @confirm="dialog.confirm" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import ButtonAddDialog from '../components/ButtonAddDialog.vue';
|
||||
|
||||
import { getMenuInfo_api } from '@/api/system/menu';
|
||||
|
||||
// 路由
|
||||
const route = useRoute();
|
||||
const routeParams = {
|
||||
id: route.params.id === ':id' ? '' : route.params.id,
|
||||
id: route.params.id === ':id' ? '' : (route.params.id as string),
|
||||
...route.query,
|
||||
};
|
||||
|
||||
// 弹窗相关
|
||||
const dialogRef = ref<any>(null);
|
||||
const dialog = {
|
||||
// 打开弹窗
|
||||
openDialog: (row?: object) => {
|
||||
dialogRef.value && dialogRef.value.openDialog(row);
|
||||
},
|
||||
confirm: () => {},
|
||||
};
|
||||
// 表格相关
|
||||
const table = reactive({
|
||||
columns: [
|
||||
{
|
||||
title: '编码',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 220,
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
scopedSlots: true,
|
||||
width: 240,
|
||||
},
|
||||
],
|
||||
data: [] as tableDataItem[],
|
||||
getList: () => {
|
||||
routeParams.id &&
|
||||
getMenuInfo_api(routeParams.id).then((resp: any) => {
|
||||
table.data = resp.result.buttons as tableDataItem[];
|
||||
});
|
||||
},
|
||||
});
|
||||
table.getList();
|
||||
type tableDataItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
permissions: object[];
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="dialog.visible"
|
||||
title="新增"
|
||||
width="660px"
|
||||
@ok="dialog.handleOk"
|
||||
>
|
||||
<a-form :model="form.data" class="basic-form">
|
||||
<a-form-item
|
||||
label="编码"
|
||||
name="id"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入编码' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]"
|
||||
>
|
||||
<a-input v-model:value="form.data.id" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="名称"
|
||||
name="name"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]"
|
||||
>
|
||||
<a-input v-model:value="form.data.name" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限">
|
||||
<PermissChoose
|
||||
:first-width="8"
|
||||
max-height="350px"
|
||||
v-model:value="form.data.permissions"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="说明" name="describe">
|
||||
<a-textarea
|
||||
v-model:value="form.data.describe"
|
||||
:rows="4"
|
||||
placeholder="请输入说明"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PermissChoose from '../components/PermissChoose.vue';
|
||||
|
||||
const emits = defineEmits(['confirm']);
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
handleOk: () => {
|
||||
dialog.changeVisible();
|
||||
},
|
||||
changeVisible: (formValue?: formType, show?: boolean) => {
|
||||
dialog.visible = show === undefined ? !dialog.visible : show;
|
||||
form.data = formValue || { ...initForm };
|
||||
console.log(1111111111, form.data);
|
||||
},
|
||||
});
|
||||
const initForm = {
|
||||
name: '',
|
||||
id: '',
|
||||
permissions: [],
|
||||
describe: '',
|
||||
} as formType;
|
||||
const form = reactive({
|
||||
data: { ...initForm },
|
||||
});
|
||||
|
||||
// 将打开弹窗的操作暴露给父组件
|
||||
defineExpose({
|
||||
openDialog: dialog.changeVisible,
|
||||
});
|
||||
|
||||
type formType = {
|
||||
name: string;
|
||||
id: string;
|
||||
permissions: any[];
|
||||
describe: string;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.basic-form {
|
||||
.ant-form-item {
|
||||
display: block;
|
||||
:deep(.ant-form-item-label) {
|
||||
overflow: inherit;
|
||||
label::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -5,43 +5,207 @@
|
|||
style="width: 300px"
|
||||
allowClear
|
||||
placeholder="请输入权限名称"
|
||||
@input="search.search"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<div class="permission-table">
|
||||
<a-row :gutter="24" class="table-head">
|
||||
<a-col :span="props.firstWidth">权限名称</a-col
|
||||
><a-col :span="24 - props.firstWidth">权限操作</a-col>
|
||||
</a-row>
|
||||
<div class="table-body" :style="{ 'max-height': props.maxHeight }">
|
||||
<a-row
|
||||
:gutter="24"
|
||||
class="row"
|
||||
v-for="rowItem in permission.list"
|
||||
>
|
||||
<a-col :span="props.firstWidth" class="item-name">
|
||||
<a-checkbox
|
||||
v-model:checked="rowItem.checkAll"
|
||||
:indeterminate="rowItem.indeterminate"
|
||||
@change="() => permission.selectAllOpions(rowItem)"
|
||||
>
|
||||
{{ rowItem.name }}
|
||||
</a-checkbox>
|
||||
</a-col>
|
||||
<a-col :span="24 - props.firstWidth">
|
||||
<a-checkbox-group
|
||||
v-model:value="rowItem.checkedList"
|
||||
:options="rowItem.options"
|
||||
@change="((checkValue:string[])=>permission.selectOption(rowItem, checkValue))"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { exportPermission_api } from '@/api/system/permission';
|
||||
|
||||
const props = defineProps({
|
||||
value: Array,
|
||||
});
|
||||
const props = defineProps<{
|
||||
value: any[];
|
||||
firstWidth: number;
|
||||
maxHeight: string;
|
||||
}>();
|
||||
const emits = defineEmits(['update:value']);
|
||||
const searchValue = ref<string>('');
|
||||
|
||||
const search = reactive({
|
||||
value: '',
|
||||
searchTimer: null as null | number,
|
||||
search: () => {
|
||||
if (search.searchTimer) {
|
||||
clearTimeout(search.searchTimer);
|
||||
}
|
||||
search.searchTimer = setTimeout(() => {
|
||||
nextTick(() => permission.getList());
|
||||
search.searchTimer = null;
|
||||
}, 1000);
|
||||
},
|
||||
});
|
||||
const permission = reactive({
|
||||
list: [] as permissionType[],
|
||||
// 获取权限列表
|
||||
getList: () => {
|
||||
|
||||
exportPermission_api({ paging: false }).then((resp) => {
|
||||
permission.list = resp.result as permissionType[]
|
||||
const params: paramsType = {
|
||||
paging: false,
|
||||
};
|
||||
if (search.value) {
|
||||
params.terms = [
|
||||
{ column: 'name$like', value: `%${search.value}%` },
|
||||
];
|
||||
}
|
||||
exportPermission_api(params).then((resp) => {
|
||||
permission.list = permission.makeList(
|
||||
props.value,
|
||||
resp.result as any[],
|
||||
);
|
||||
});
|
||||
},
|
||||
// 全选/取消全选
|
||||
selectAllOpions: (row: permissionType) => {
|
||||
const newValue = props.value.filter(
|
||||
(item) => item.permission !== row.id,
|
||||
);
|
||||
row = toRaw(row);
|
||||
if (row.checkAll) {
|
||||
row.checkedList = row.options.map((item) => item.value);
|
||||
|
||||
newValue.push({
|
||||
permission: row.id,
|
||||
actions: row.checkedList,
|
||||
});
|
||||
} else {
|
||||
row.checkedList = [];
|
||||
}
|
||||
emits('update:value', newValue);
|
||||
},
|
||||
// 单选
|
||||
selectOption: (row: permissionType, newValue: string[]) => {
|
||||
const newProp = props.value.filter(
|
||||
(item) => item.permission !== row.id,
|
||||
);
|
||||
|
||||
if (newValue.length === row.options.length) {
|
||||
row.checkAll = true;
|
||||
row.indeterminate = false;
|
||||
newProp.push({
|
||||
permission: row.id,
|
||||
actions: newValue,
|
||||
});
|
||||
} else if (newValue.length > 0) {
|
||||
row.checkAll = false;
|
||||
row.indeterminate = true;
|
||||
newProp.push({
|
||||
permission: row.id,
|
||||
actions: newValue,
|
||||
});
|
||||
}
|
||||
|
||||
emits('update:value', newProp);
|
||||
},
|
||||
makeList: (checkedValue: any[], sourceList: any[]): permissionType[] => {
|
||||
console.log(checkedValue);
|
||||
|
||||
const result = sourceList.map((item) => {
|
||||
const checked = checkedValue.find(
|
||||
(checkedItem) => checkedItem.permission === item.id,
|
||||
);
|
||||
const options = item.actions.map((actionItem: any) => ({
|
||||
label: actionItem.name,
|
||||
value: actionItem.action,
|
||||
}));
|
||||
console.log(item, checked);
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
checkedList: (checked && checked.actions) || [],
|
||||
checkAll:
|
||||
(checked &&
|
||||
item.actions &&
|
||||
checked?.actions.length === item.actions.length) ||
|
||||
false,
|
||||
indeterminate:
|
||||
(checked &&
|
||||
item.actions &&
|
||||
checked.actions.length < item.actions.length) ||
|
||||
false,
|
||||
options,
|
||||
};
|
||||
}) as permissionType[];
|
||||
|
||||
return result;
|
||||
},
|
||||
});
|
||||
|
||||
permission.getList()
|
||||
|
||||
|
||||
|
||||
permission.getList();
|
||||
|
||||
type permissionType = {
|
||||
id: string;
|
||||
name: string;
|
||||
actions: object[]
|
||||
}
|
||||
|
||||
checkedList: string[];
|
||||
checkAll: boolean;
|
||||
indeterminate: boolean;
|
||||
options: any[];
|
||||
};
|
||||
type paramsType = {
|
||||
paging: boolean;
|
||||
terms?: object[];
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style lang="less" scoped>
|
||||
.permission-choose-container {
|
||||
.permission-table {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #d9d9d9;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
.table-head {
|
||||
padding: 12px;
|
||||
background-color: #d9d9d9;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.table-body {
|
||||
overflow: auto;
|
||||
.row {
|
||||
margin: 0 !important;
|
||||
|
||||
border-bottom: 1px solid #d9d9d9;
|
||||
|
||||
> div {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
.item-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-right: 1px solid #d9d9d9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<a-button>菜单实例</a-button>
|
||||
</template>
|
||||
<template #createTime="slotProps">
|
||||
{{ slotProps.createTime }}
|
||||
{{ moment(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
|
@ -30,7 +30,7 @@
|
|||
type="link"
|
||||
@click="table.toDetails(slotProps)"
|
||||
>
|
||||
<edit-outlined />
|
||||
<search-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
|
@ -40,7 +40,7 @@
|
|||
type="link"
|
||||
@click="table.toDetails(slotProps)"
|
||||
>
|
||||
<edit-outlined />
|
||||
<plus-circle-outlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
|
@ -66,6 +66,13 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { getMenuTree_api } from '@/api/system/menu';
|
||||
import {
|
||||
SearchOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
PlusCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import moment from 'moment';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
|
Loading…
Reference in New Issue