Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
wangshuaiswim 2023-02-23 20:03:51 +08:00
commit 372cf91fbb
23 changed files with 1762 additions and 562 deletions

BIN
public/images/apply/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/images/apply/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/images/apply/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
public/images/apply/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
public/images/apply/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

9
src/api/system/apply.ts Normal file
View File

@ -0,0 +1,9 @@
import server from '@/utils/request';
// 获取应用管理列表
export const getApplyList_api = (data: any) => server.post(`/application/_query/`, data)
// 修改应用状态
export const changeApplyStatus_api = (id:string,data: any) => server.put(`/application/${id}`, data)
// 删除应用
export const delApply_api = (id:string) => server.remove(`/application/${id}`)

View File

@ -0,0 +1,211 @@
<template>
<div class="does-container">
<div v-show="props.type === 'internal-standalone'">
<h1>1.概述</h1>
<div>
内部独立应用适用于将<span>官方开发</span>的其他应用与<span
>物联网平台相互集成</span
>
例如将可视化平台集成至物联网平台或者将物联网平台集成至可视化平台以实现多处访问集中管控的业务场景
</div>
<div>
内部独立应用的<span>后端服务</span>相互<span>独立运行</span>互不影响
</div>
<div class="image">
<a-image width="100%" :src="img1" />
</div>
<h1>2.接入方式说明</h1>
<div>1页面集成</div>
<div>
集成其他应用的<span>前端页面</span>至物联网平台中为实现应用与物联网平台数据互联互通
<span>通常还需要配置API服务</span>
</div>
<div>2API客户端</div>
<div>
<span>物联网平台</span>请求<span>其他应用</span>
的接口以实现将物联网平台集成至其他应用系统如需实现<span
>其他应用</span
>
登录后可以访问<span>物联网平台</span>页面<span>还需要配置单点登录</span>
</div>
<div>3API服务</div>
<div>
<span>外部应用</span
>请求<span>物联网平台</span>的接口实现物联网平台的服务调用能力
<span>通常还需要配置页面集成</span>
</div>
<div>
配置API服务后系统将<span>自动创建</span>对应的<span>第三方应用用户</span>用户的
<span>账号/密码</span>分别对应appid/secureKey
</div>
<div>
第三方用户<span>可调用的API服务</span>在其应用管理卡片的<span
>其他-{'>'}赋权</span
>
页面进行<span>自定义配置</span>
</div>
<div>4单点登录</div>
<div>通过<span>第三方平台账号</span>登录到物联网平台</div>
</div>
<div v-show="props.type === 'internal-integrated'">
<h1>1.概述</h1>
<div>
内部集成应用适用于将<span>官方开发</span>的其他应用与<span
>物联网平台相互集成</span
>
例如将可视化平台集成至物联网平台或者将物联网平台集成至可视化平台以实现多处访问集中管控的业务场景
</div>
<div>内部独立应用的<span>后端服务在同一个环境运行</span></div>
<div class="image">
<a-image width="100%" :src="img2" />
</div>
<h1>2.接入方式说明</h1>
<div>1页面集成</div>
<div>
集成其他应用的<span>前端页面</span>
至物联网平台中集成后系统顶部将新增对应的应用管理菜单
</div>
<div>2API客户端</div>
<div>
<span>物联网平台</span
>去请求其他应用的接口以实现将物联网平台集成至其他应用
</div>
</div>
<div v-show="props.type === 'dingtalk-ent-app'">
<div class="url">
钉钉开放平台
<a
href="https://open-dev.dingtalk.com"
target="_blank"
rel="noopener noreferrer"
>
https://open-dev.dingtalk.com
</a>
</div>
<h1>1.概述</h1>
<div>钉钉企业内部应用适用于通过钉钉登录<span>物联网平台</span></div>
<div class="image">
<a-image width="100%" :src="img4" />
</div>
<h1>2.接入方式说明</h1>
<div>1单点登录</div>
<div>通过钉钉账号登录到物联网平台</div>
</div>
<div v-show="props.type === 'wechat-webapp'">
<div class="url">
微信开放平台
<a
href="https://open.weixin.qq.com"
target="_blank"
rel="noopener noreferrer"
>
https://open.weixin.qq.com
</a>
</div>
<h1>1.概述</h1>
<div>微信网站应用适用于通过微信授权登录<span>物联网平台</span></div>
<div class="image">
<a-image width="100%" :src="img3" />
</div>
<h1>2.接入方式说明</h1>
<div>1单点登录</div>
<div>通过微信账号登录到物联网平台</div>
</div>
<div v-show="props.type === 'third-party'">
<h1>1. 概述</h1>
<div>
第三方应用适用于<span>第三方应用</span><span
>物联网平台相互集成</span
>
例如将公司业务管理系统集成至物联网平台或者将物联网平台集成至业务管理系统以实现多处访问集中管控的业务场景
</div>
<div class="image">
<a-image width="100%" :src="img5" />
</div>
<h1>2.接入方式说明</h1>
<div>1页面集成</div>
<div>
集成其他应用的<span>前端页面</span>至物联网平台中为实现应用与物联网平台数据互联互通
<span>还需要配置API服务</span>
</div>
<div>2API客户端</div>
<div>
<span>物联网平台</span>请求<span>第三方应用</span>
的接口以实现将物联网平台集成至其他应用如需实现<span>第三方应用</span>登录后可以访问
<span>物联网平台</span>页面<span>还需要配置单点登录</span>
</div>
<div>3API服务</div>
<div>
<span>第三方应用</span
>通过API服务配置请求物联网平台接口实现<span
>物联网平台</span
>
的服务调用能力<span>通常还需要配置页面集成</span>
</div>
<div>
配置API服务后系统将<span>自动创建</span>对应的<span>第三方应用用户</span>用户的
<span>账号/密码</span>分别对应appid/secureKey
</div>
<div>
第三方用户<span>可调用的API服务</span>在其应用管理卡片的<span
>其他-{'>'}赋权</span
>
页面进行<span>自定义配置</span>
</div>
<div>4单点登录</div>
<div>通过<span>第三方平台账号</span>登录到物联网平台</div>
</div>
</div>
</template>
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import type { applyType } from '../typing';
const props = defineProps<{
type: applyType;
}>();
const img1 = getImage('/apply/1.png');
const img2 = getImage('/apply/2.png');
const img3 = getImage('/apply/3.png');
const img4 = getImage('/apply/4.png');
const img5 = getImage('/apply/5.png');
</script>
<style lang="less" scoped>
.does-container {
padding: 24px;
overflow-y: auto;
color: rgba(#000, 0.8);
font-size: 14px;
background-color: #fafafa;
.url {
padding: 8px 16px;
color: #2f54eb;
background-color: rgba(#a7bdf7, 0.2);
}
h1 {
margin: 16px 0;
color: rgba(#000, 0.85);
font-weight: bold;
font-size: 14px;
&:first-child {
margin-top: 0;
}
}
h2 {
margin: 6px 0;
color: rgba(0, 0, 0, 0.8);
font-size: 14px;
}
.image {
margin: 16px 0;
}
}
</style>

View File

@ -0,0 +1,34 @@
<template>
<div class="form-label-container">
<span class="text">{{ props.text }}</span>
<span class="required">*</span>
<a-tooltip>
<template #title>{{ props.tooltip }}</template>
<AIcon type="QuestionCircleOutlined" style="color: #00000073;cursor: inherit;" />
</a-tooltip>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
text: string;
tooltip: string;
required?: boolean;
}>();
</script>
<style lang="less" scoped>
.form-label-container {
display: flex;
align-items: center;
.required {
display: inline-block;
margin-right: 4px;
color: #ff4d4f;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
}
}
</style>

View File

@ -0,0 +1,505 @@
<template>
<page-container>
<a-card class="save-container">
<a-row :gutter="24">
<a-col :span="14">
<a-form
ref="formRef"
:model="form.data"
layout="vertical"
class="form"
>
<a-form-item label="名称" name="name">
<a-input
v-model:value="form.data.name"
placeholder="请输入名称"
/>
</a-form-item>
<a-form-item label="应用" name="provider">
<a-radio-group
v-model:value="form.data.provider"
class="radio-container"
@change="form.data.integrationModes = []"
>
<a-radio-button value="internal-standalone">
<div>
<a-image
:preview="false"
:src="
getImage('/apply/provider1.png')
"
width="64px"
height="64px"
/>
<p>内部独立应用</p>
</div>
</a-radio-button>
<a-radio-button value="internal-integrated">
<div>
<a-image
:preview="false"
:src="
getImage('/apply/provider2.png')
"
/>
<p>内部集成应用</p>
</div>
</a-radio-button>
<a-radio-button value="wechat-webapp">
<div>
<a-image
:preview="false"
:src="
getImage('/apply/provider3.png')
"
/>
<p>微信网站应用</p>
</div>
</a-radio-button>
<a-radio-button value="dingtalk-ent-app">
<div>
<a-image
:preview="false"
:src="
getImage('/apply/provider4.png')
"
/>
<p>钉钉企业内部应用</p>
</div>
</a-radio-button>
<a-radio-button value="third-party">
<div>
<a-image
:preview="false"
:src="
getImage('/apply/provider5.png')
"
/>
<p>第三方应用</p>
</div>
</a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="接入方式" name="integrationModes">
<a-checkbox-group
v-model:value="form.data.integrationModes"
:options="joinOptions"
/>
</a-form-item>
<a-collapse
v-model:activeKey="form.integrationModesISO"
>
<a-collapse-panel
key="page"
v-show="
form.data.integrationModes.includes('page')
"
header="页面集成"
>
<a-form-item
:name="['page', 'baseUrl']"
class="resetLabel"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="接入地址"
required
tooltip="填写访问其它平台的地址"
/>
</template>
<a-input
v-model:value="form.data.page.baseUrl"
placeholder="请输入接入地址"
/>
</a-form-item>
<a-form-item
label="路由方式"
:name="['page', 'routeType']"
:rules="[
{
required: true,
},
]"
>
<a-select
v-model:value="form.data.page.routeType"
style="width: 120px"
>
<a-select-option value="hash"
>hash</a-select-option
>
<a-select-option value="history"
>history</a-select-option
>
</a-select>
</a-form-item>
</a-collapse-panel>
<a-collapse-panel
key="apiClient"
v-show="
form.data.integrationModes.includes(
'apiClient',
)
"
header="API客户端"
>
<a-form-item
class="resetLabel"
:name="['apiClient', 'baseUrl']"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="接口地址"
required
tooltip="访问Api服务的地址"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.baseUrl
"
placeholder="请输入接入地址"
/>
</a-form-item>
<a-form-item
class="resetLabel"
:name="[
'apiClient',
'authConfig',
'oauth2',
'authorizationUrl',
]"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="授权地址"
required
tooltip="认证授权地址"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.authConfig
.oauth2.authorizationUrl
"
placeholder="请输入授权地址"
/>
</a-form-item>
<a-form-item
class="resetLabel"
:name="[
'apiClient',
'authConfig',
'oauth2',
'tokenUrl',
]"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="token地址"
required
tooltip="设置token令牌的地址"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.authConfig
.oauth2.tokenUrl
"
placeholder="请输入token地址"
/>
</a-form-item>
<a-form-item
label="回调地址"
:name="[
'apiClient',
'authConfig',
'oauth2',
'redirectUri',
]"
>
<template #label>
<FormLabel
text="回调地址"
tooltip="授权完成后跳转到具体页面的回调地址"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.authConfig
.oauth2.redirectUri
"
placeholder="请输入回调地址"
/>
</a-form-item>
<a-form-item
class="resetLabel"
:name="[
'apiClient',
'authConfig',
'oauth2',
'clientId',
]"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="appId"
required
tooltip="第三方应用唯一标识"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.authConfig
.oauth2.clientId
"
placeholder="请输入appId"
/>
</a-form-item>
<a-form-item
class="resetLabel"
:name="[
'apiClient',
'authConfig',
'oauth2',
'clientSecret',
]"
:rules="[
{
required: true,
},
]"
>
<template #label>
<FormLabel
text="appKey"
required
tooltip="第三方应用唯一标识的密钥"
/>
</template>
<a-input
v-model:value="
form.data.apiClient.authConfig
.oauth2.clientSecret
"
placeholder="请输入appKey"
/>
</a-form-item>
<a-form-item label="请求头"> </a-form-item>
<a-form-item label="参数"> </a-form-item>
</a-collapse-panel>
<a-collapse-panel
key="apiServer"
v-show="
form.data.integrationModes.includes(
'apiServer',
)
"
header="API服务"
>
</a-collapse-panel>
<a-collapse-panel
key="ssoClient"
v-show="
form.data.integrationModes.includes(
'ssoClient',
)
"
header="单点登录"
>
</a-collapse-panel>
</a-collapse>
<a-form-item label="说明" name="description">
<a-textarea
v-model:value="form.data.description"
placeholder="请输入说明"
showCount
:maxlength="200"
:rows="5"
/>
</a-form-item>
</a-form>
<a-button v-if="!routeQuery.view">保存</a-button>
</a-col>
<a-col :span="10"><Does :type="form.data.provider" /></a-col>
</a-row>
</a-card>
</page-container>
</template>
<script setup lang="ts">
import Does from './components/Does.vue';
import FormLabel from './components/FormLabel.vue';
import { getImage } from '@/utils/comm';
import type { applyType, formType } from './typing';
const routeQuery = useRoute().query;
const initForm: formType = {
name: '',
provider: 'internal-standalone',
integrationModes: [],
config: '',
description: '',
page: {
baseUrl: '',
routeType: 'hash',
},
apiClient: {
baseUrl: '',
authConfig: {
type: '',
oauth2: {
authorizationUrl: '',
tokenUrl: '',
redirectUri: '',
clientId: '',
clientSecret: '',
},
},
},
};
const form = reactive({
data: { ...initForm },
integrationModesISO: [] as string[],
});
const joinOptions = computed(() => {
if (form.data.provider === 'internal-standalone')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
{
label: 'API服务',
value: 'apiServer',
},
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'internal-integrated')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
];
else if (form.data.provider === 'wechat-webapp')
return [
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'dingtalk-ent-app')
return [
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'third-party')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
{
label: 'API服务',
value: 'apiServer',
},
{
label: '单点登录',
value: 'ssoClient',
},
];
});
</script>
<style lang="less" scoped>
.save-container {
.form {
.ant-form-item {
&.resetLabel {
:deep(.ant-form-item-required) {
&::before {
display: none;
}
}
}
.ant-select {
width: 100% !important;
}
}
.radio-container {
.ant-radio-button-wrapper {
height: 120px;
width: 120px;
padding: 0 15px;
box-sizing: content-box;
margin-right: 20px;
> :last-child {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
> div {
width: 100%;
text-align: center;
}
:deep(.ant-image) {
width: 64px;
height: 64px;
}
p {
margin: 0;
}
}
}
}
}
}
</style>

30
src/views/system/Apply/Save/typing.d.ts vendored Normal file
View File

@ -0,0 +1,30 @@
export type applyType = 'internal-standalone'
| 'wechat-webapp'
| 'internal-integrated'
| 'dingtalk-ent-app'
| 'third-party'
export type formType = {
name: string;
provider: applyType;
integrationModes: string[];
config: string;
description: string;
page: {
baseUrl:string,
routeType:'hash' | 'history'
},
apiClient: {
baseUrl: string,
authConfig: {
type:string,
oauth2 :{
authorizationUrl:string,
tokenUrl: string,
redirectUri:string,
clientId:string,
clientSecret:string
}
}
}
}

View File

@ -1,13 +1,399 @@
<template>
<div>
应用管理
</div>
<page-container class="apply-container">
<div class="apply-container">
<Search :columns="columns" @search="search" />
<JTable
ref="tableRef"
:columns="columns"
:request="getApplyList_api"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
:gridColumn="3"
>
<template #headerTitle>
<div style="display: flex; align-items: center">
<PermissionButton
:uhasPermission="`${permission}:add`"
type="primary"
@click="() => table.toSave()"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<p style="margin: 0 0 0 30px; color: #0000008c">
<AIcon
type="ExclamationCircleOutlined"
style="margin-right: 12px"
/>
应用管理将多个应用系统的登录简化为一次登录实现多处访问集中管控的业务场景
</p>
</div>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="table.getActions(slotProps, 'card')"
v-bind="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'success',
disabled: 'error',
}"
>
<template #img>
<slot name="img">
<img :src="getImage('/apply.png')" />
</slot>
</template>
<template #content>
<h3 class="card-item-content-title">
{{ slotProps.name }}
</h3>
<a-row>
<a-col :span="12">
<div class="card-item-content-text">
类型
</div>
<div>
{{
table.getTypeLabel(
slotProps.provider,
)
}}
</div>
</a-col>
<a-col :span="12">
<div class="card-item-content-text">
说明
</div>
<div>{{ slotProps.description }}</div>
</a-col>
</a-row>
</template>
<template #actions="item">
<a-tooltip
v-bind="item.tooltip"
:title="item.disabled && item.tooltip.title"
>
<a-dropdown
placement="bottomRight"
v-if="item.key === 'others'"
>
<a-button>
<AIcon :type="item.icon" />
<span>{{ item.text }}</span>
</a-button>
<template #overlay>
<a-menu>
<a-menu-item
v-for="(o, i) in item.children"
:key="i"
>
<a-button
type="link"
@click="o.onClick"
>
<AIcon :type="o.icon" />
<span>{{ o.text }}</span>
</a-button>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<PermissionButton
v-else
:uhasPermission="item.permission"
:tooltip="item.tooltip"
:pop-confirm="item.popConfirm"
@click="item.onClick"
:disabled="item.disabled"
>
<AIcon :type="item.icon" />
<span v-if="item.key !== 'delete'">{{
item.text
}}</span>
</PermissionButton>
</a-tooltip>
</template>
</CardBox>
</template>
<template #provider="slotProps">
{{ table.getTypeLabel(slotProps.provider) }}
</template>
<template #status="slotProps">
<BadgeStatus
:status="slotProps.state.value"
:text="slotProps.state.text"
:statusNames="{
enabled: 'success',
disabled: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
v-for="i in table.getActions(slotProps, 'table')"
:uhasPermission="i.permission"
type="link"
:tooltip="i.tooltip"
:pop-confirm="i.popConfirm"
@click="i.onClick"
:disabled="i.disabled"
>
<AIcon :type="i.icon" />
</PermissionButton>
</a-space>
</template>
</JTable>
</div>
</page-container>
</template>
<script setup lang="ts">
<script setup lang="ts" name="Apply">
import PermissionButton from '@/components/PermissionButton/index.vue';
import {
getApplyList_api,
changeApplyStatus_api,
delApply_api,
} from '@/api/system/apply';
import { ActionsType } from '@/components/Table';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import { message } from 'ant-design-vue';
const menuStory = useMenuStore();
const permission = 'system/User';
const typeOptions = [
{
label: '内部独立应用',
value: 'internal-standalone',
},
{
label: '微信网站应用',
value: 'wechat-webapp',
},
{
label: '内部集成应用',
value: 'internal-integrated',
},
{
label: '钉钉企业内部应用',
value: 'dingtalk-ent-app',
},
{
label: '第三方应用',
value: 'third-party',
},
];
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '类型',
dataIndex: 'provider',
key: 'provider',
ellipsis: true,
fixed: 'left',
search: {
type: 'select',
options: typeOptions,
},
scopedSlots: true,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
ellipsis: true,
search: {
rename: 'status',
type: 'select',
options: [
{
label: '正常',
value: 'enabled',
},
{
label: '禁用',
value: 'disabled',
},
],
},
scopedSlots: true,
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
scopedSlots: true,
},
];
const params = ref({});
const search = (newParams: any) => (params.value = {...newParams});
const tableRef = ref();
const table = {
refresh: () => {
tableRef.value.reload();
},
toSave: (id?: string, view = false) => {
if (id) menuStory.jumpPage('system/Apply/Save', {}, { id, view });
else menuStory.jumpPage('system/Apply/Save');
},
changeStatus: (row: any) => {
const state = row.state.value === 'enabled' ? 'disabled' : 'enabled';
changeApplyStatus_api(row.id, { state }).then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功');
table.refresh();
}
});
},
clickDel: (row: any) => {
delApply_api(row.id).then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功');
table.refresh();
}
});
},
getActions: (
data: Partial<Record<string, any>>,
type: 'card' | 'table',
) => {
if (!data) return [];
const disabled = data.state.value === 'enabled';
const result = [
{
permission: true,
key: 'edit',
text: '编辑',
tooltip: {
title: '编辑',
},
icon: 'EditOutlined',
onClick: () => table.toSave(data.id),
},
{
permission: true,
key: 'action',
text: disabled ? '禁用' : '启用',
tooltip: {
title: disabled ? '禁用' : '启用',
},
popConfirm: {
title: `确认${disabled ? '禁用' : '启用'}`,
onConfirm: () => table.changeStatus(data),
},
icon: disabled ? 'StopOutlined' : 'PlayCircleOutlined',
},
{
permission: true,
key: 'delete',
text: '删除',
tooltip: {
title: disabled ? '请先禁用再删除' : '删除',
},
popConfirm: {
title: '确认删除?',
onConfirm: () => table.clickDel(data),
},
disabled,
icon: 'DeleteOutlined',
},
] as ActionsType[];
const otherServers = data.integrationModes.map(
(item: any) => item.value as string,
);
const others = {
key: 'others',
text: '其他',
icon: 'EllipsisOutlined',
children: [] as ActionsType[],
};
//
if (otherServers.includes('page'))
others.children?.push({
permission: true,
key: 'page',
text: '集成菜单',
tooltip: {
title: '集成菜单',
},
icon: 'MenuUnfoldOutlined',
onClick: () => {},
});
// api
if (otherServers.includes('apiServer'))
others.children?.push(
{
permission: true,
key: 'empowerment',
text: '赋权',
tooltip: {
title: '赋权',
},
icon: 'icon-fuquan',
onClick: () => {},
},
{
permission: true,
key: 'viewApi',
text: '查看API',
tooltip: {
title: '查看API',
},
icon: 'icon-chakanAPI',
onClick: () => {},
},
);
//
if (others.children.length > 0) {
if (type === 'card') {
result.splice(result.length - 1, 0, others);
} else {
result.splice(result.length - 1, 0, ...others.children);
}
}
return result;
},
getTypeLabel: (val: string) => {
if (!val) return '';
return typeOptions.find((item) => item.value === val)?.label;
},
};
</script>
<style scoped>
</style>
<style lang="less" scoped>
.apply-container {
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0;
}
}
}
</style>

View File

@ -1,124 +1,134 @@
<template>
<div class="data-source-container">
<Search :columns="query.columns" @search="query.search" />
<page-container>
<div class="data-source-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="getDataSourceList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog({})"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'success',
disabled: 'error',
}"
>
</BadgeStatus>
</template>
<template #typeId="slotProps">
{{
(table.typeOptions.value.length &&
table.getTypeLabel(slotProps.typeId)) ||
''
}}
</template>
<template #action="slotProps">
<a-space :size="16">
<JTable
ref="tableRef"
:columns="table.columns"
:request="getDataSourceList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
>
<template #headerTitle>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog({})"
>
<AIcon type="EditOutlined" />
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:manage`"
type="link"
:tooltip="{
title:
slotProps?.typeId === 'rabbitmq'
? '暂不支持管理功能'
: table.getRowStatus(slotProps)
? '管理'
: '请先启用数据源',
}"
@click="
() =>
router.push(
`/system/DataSource/Management?id=${slotProps.id}`,
)
"
:disabled="slotProps?.typeId === 'rabbitmq' || !table.getRowStatus(slotProps)"
>
<AIcon type="icon-ziyuankuguanli" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:popConfirm="{
title: `确定要${
table.getRowStatus(slotProps) ? '禁用' : '启用'
}`,
onConfirm: () => table.clickChangeStatus(slotProps),
}"
:tooltip="{
title: table.getRowStatus(slotProps)
? '禁用'
: '启用',
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'success',
disabled: 'error',
}"
>
<AIcon
:type="
table.getRowStatus(slotProps)
? 'StopOutlined'
: 'PlayCircleOutlined'
</BadgeStatus>
</template>
<template #typeId="slotProps">
{{
(table.typeOptions.value.length &&
table.getTypeLabel(slotProps.typeId)) ||
''
}}
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:manage`"
type="link"
:tooltip="{
title:
slotProps?.typeId === 'rabbitmq'
? '暂不支持管理功能'
: table.getRowStatus(slotProps)
? '管理'
: '请先启用数据源',
}"
@click="
() =>
router.push(
`/system/DataSource/Management?id=${slotProps.id}`,
)
"
/>
<!-- <AIcon type="PlayCircleOutlined" /> -->
</PermissionButton>
:disabled="
slotProps?.typeId === 'rabbitmq' ||
!table.getRowStatus(slotProps)
"
>
<AIcon type="icon-ziyuankuguanli" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:popConfirm="{
title: `确定要${
table.getRowStatus(slotProps)
? '禁用'
: '启用'
}`,
onConfirm: () =>
table.clickChangeStatus(slotProps),
}"
:tooltip="{
title: table.getRowStatus(slotProps)
? '禁用'
: '启用',
}"
>
<AIcon
:type="
table.getRowStatus(slotProps)
? 'StopOutlined'
: 'PlayCircleOutlined'
"
/>
<!-- <AIcon type="PlayCircleOutlined" /> -->
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{
title: table.getRowStatus(slotProps)
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="table.getRowStatus(slotProps)"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{
title: table.getRowStatus(slotProps)
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="table.getRowStatus(slotProps)"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<div class="dialogs">
<EditDialog ref="editDialogRef" @confirm="table.refresh" />
<div class="dialogs">
<EditDialog ref="editDialogRef" @confirm="table.refresh" />
</div>
</div>
</div>
</page-container>
</template>
<script setup lang="ts" name="DataSource">
@ -132,7 +142,7 @@ import {
getDataSourceList_api,
getDataTypeDict_api,
changeStatus_api,
delDataSource_api
delDataSource_api,
} from '@/api/system/dataSource';
import { message } from 'ant-design-vue';
@ -243,7 +253,7 @@ const table = {
key: 'action',
scopedSlots: true,
width: '200px',
fixed:'right'
fixed: 'right',
},
],
@ -298,7 +308,6 @@ table.getTypeOption();
<style lang="less" scoped>
.data-source-container {
padding: 24px;
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0;

View File

@ -1,30 +1,32 @@
<template>
<div class="department-container">
<a-card class="department-content">
<div class="left">
<LeftTree @change="(id) => (departmentId = id)" />
</div>
<div class="right">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="product" tab="产品">
<Product
:parentId="departmentId"
@open-device-bind="openDeviceBind"
/>
</a-tab-pane>
<a-tab-pane key="device" tab="设备">
<Device
:parentId="departmentId"
v-model:bindBool="bindBool"
/>
</a-tab-pane>
<a-tab-pane key="user" tab="用户">
<User :parentId="departmentId" />
</a-tab-pane>
</a-tabs>
</div>
</a-card>
</div>
<page-container>
<div class="department-container">
<a-card class="department-content">
<div class="left">
<LeftTree @change="(id) => (departmentId = id)" />
</div>
<div class="right">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="product" tab="产品">
<Product
:parentId="departmentId"
@open-device-bind="openDeviceBind"
/>
</a-tab-pane>
<a-tab-pane key="device" tab="设备">
<Device
:parentId="departmentId"
v-model:bindBool="bindBool"
/>
</a-tab-pane>
<a-tab-pane key="user" tab="用户">
<User :parentId="departmentId" />
</a-tab-pane>
</a-tabs>
</div>
</a-card>
</div>
</page-container>
</template>
<script setup lang="ts" name="Department">
@ -46,7 +48,6 @@ const openDeviceBind = () => {
<style lang="less" scoped>
.department-container {
padding: 24px;
.department-content {
:deep(.ant-card-body) {
display: flex;

View File

@ -1,12 +1,16 @@
<template>
<div class="menu-detail-container">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="basic" tab="基本信息"> <BasicInfo /> </a-tab-pane>
<a-tab-pane key="button" tab="按钮管理">
<ButtonMange />
</a-tab-pane>
</a-tabs>
</div>
<page-container>
<div class="menu-detail-container">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="basic" tab="基本信息">
<BasicInfo />
</a-tab-pane>
<a-tab-pane key="button" tab="按钮管理">
<ButtonMange />
</a-tab-pane>
</a-tabs>
</div>
</page-container>
</template>
<script setup lang="ts">
@ -24,7 +28,7 @@ const activeKey = ref('basic');
}
.ant-tabs-tabpane {
background-color: #f0f2f5;
padding: 24px;
padding-top: 24px;
}
}
</style>

View File

@ -1,73 +1,79 @@
<template>
<div class="menu-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="table.getList"
model="TABLE"
:params="query.params"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.toDetails({})"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<a-button
style="margin-left: 12px"
@click="router.push('/system/Menu/Setting')"
>菜单配置</a-button
>
<!-- <PermissionButton
:uhasPermission="true"
@click="router.push('/system/Menu/Setting')"
>
菜单配置
</PermissionButton> -->
</template>
<template #createTime="slotProps">
{{ moment(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip>
<template #title>查看</template>
<a-button
style="padding: 0"
type="link"
@click="table.toDetails(slotProps)"
>
<search-outlined />
</a-button>
</a-tooltip>
<page-container>
<div class="menu-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="table.getList"
model="TABLE"
:params="query.params"
>
<template #headerTitle>
<PermissionButton
type="link"
type="primary"
:uhasPermission="`${permission}:add`"
:tooltip="{ title: '新增子菜单' }"
@click="table.addChildren(slotProps)"
@click="table.toDetails({})"
>
<AIcon type="PlusCircleOutlined" />
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `是否删除该菜单`,
onConfirm: () => table.clickDel(slotProps),
}"
<a-button
style="margin-left: 12px"
@click="router.push('/system/Menu/Setting')"
>菜单配置</a-button
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
</div>
<!-- <PermissionButton
:uhasPermission="true"
@click="router.push('/system/Menu/Setting')"
>
菜单配置
</PermissionButton> -->
</template>
<template #createTime="slotProps">
{{
moment(slotProps.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip>
<template #title>查看</template>
<a-button
style="padding: 0"
type="link"
@click="table.toDetails(slotProps)"
>
<search-outlined />
</a-button>
</a-tooltip>
<PermissionButton
type="link"
:uhasPermission="`${permission}:add`"
:tooltip="{ title: '新增子菜单' }"
@click="table.addChildren(slotProps)"
>
<AIcon type="PlusCircleOutlined" />
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `是否删除该菜单`,
onConfirm: () => table.clickDel(slotProps),
}"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
</div>
</page-container>
</template>
<script setup lang="ts">
@ -269,8 +275,6 @@ const table = reactive({
<style lang="less" scoped>
.menu-container {
padding: 24px;
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0;

View File

@ -1,120 +1,127 @@
<template>
<div class="permission-container">
<Search :columns="query.columns" @search="query.search" />
<page-container>
<div class="permission-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="getPermission_api"
model="TABLE"
:params="query.params"
:defaultParams="{ sorts: [{ name: 'id', order: 'asc' }] }"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog(undefined)"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<a-dropdown trigger="hover">
<a-button>批量操作</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<a-upload
name="file"
action="#"
accept=".json"
:showUploadList="false"
:before-upload="table.clickImport"
:disabled="
!hasPermission(`${permission}:import`)
"
>
<PermissionButton
:hasPermission="`${permission}:import`"
<JTable
ref="tableRef"
:columns="table.columns"
:request="getPermission_api"
model="TABLE"
:params="query.params"
:defaultParams="{ sorts: [{ name: 'id', order: 'asc' }] }"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog(undefined)"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<a-dropdown trigger="hover">
<a-button>批量操作</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<a-upload
name="file"
action="#"
accept=".json"
:showUploadList="false"
:before-upload="table.clickImport"
:disabled="
!hasPermission(
`${permission}:import`,
)
"
>
导入
<PermissionButton
:hasPermission="`${permission}:import`"
>
导入
</PermissionButton>
</a-upload>
</a-menu-item>
<a-menu-item>
<PermissionButton
:uhasPermission="`${permission}:export`"
:popConfirm="{
title: `确认导出?`,
onConfirm: () =>
table.clickExport(),
}"
>
导出
</PermissionButton>
</a-upload>
</a-menu-item>
<a-menu-item>
<PermissionButton
:uhasPermission="`${permission}:export`"
:popConfirm="{
title: `确认导出?`,
onConfirm: () => table.clickExport(),
}"
>
导出
</PermissionButton>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<template #status="slotProps">
<StatusLabel :status-value="slotProps.status" />
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<template #status="slotProps">
<StatusLabel :status-value="slotProps.status" />
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:popConfirm="{
title: `确定要${
slotProps.status ? '禁用' : '启用'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
:tooltip="{ title: slotProps.status ? '禁用' : '启用' }"
>
<AIcon
:type="
slotProps.status
? 'StopOutlined'
: 'PlayCircleOutlined '
"
/>
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:popConfirm="{
title: `确定要${
slotProps.status ? '禁用' : '启用'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
:tooltip="{
title: slotProps.status ? '禁用' : '启用',
}"
>
<AIcon
:type="
slotProps.status
? 'StopOutlined'
: 'PlayCircleOutlined '
"
/>
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{
title: slotProps.status
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{
title: slotProps.status
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<div class="dialogs">
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
<div class="dialogs">
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
</div>
</div>
</div>
</page-container>
</template>
<script setup lang="ts">
@ -281,7 +288,6 @@ const table = reactive({
<style lang="less" scoped>
.permission-container {
padding: 24px;
.ant-dropdown-trigger {
margin-left: 12px;

View File

@ -1,5 +1,8 @@
<template>
<a-card class="api-page-container">
<p>
<AIcon type="ExclamationCircleOutlined" style="margin-right: 12px;" />配置系统支持API赋权的范围
</p>
<a-row :gutter="24">
<a-col :span="5">
<LeftTree @select="treeSelect" :mode="props.mode" />
@ -117,7 +120,6 @@ function init() {
<style scoped>
.api-page-container {
padding: 24px;
height: 100%;
background-color: transparent;
}

View File

@ -1,7 +1,7 @@
<template>
<div>
<page-container>
<Api mode="api" />
</div>
</page-container>
</template>
<script setup lang="ts" name="Platforms">

View File

@ -1,55 +1,59 @@
<template>
<div class="relationship-container">
<Search :columns="query.columns" @search="query.search" />
<page-container>
<div class="relationship-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="getRelationshipList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog(undefined)"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #action="slotProps">
<a-space :size="16">
<JTable
ref="tableRef"
:columns="table.columns"
:request="getRelationshipList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
>
<template #headerTitle>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.openDialog(undefined)"
>
<AIcon type="EditOutlined" />
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<PermissionButton
:uhasPermission="`${permission}:delete`"
type="link"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
</div>
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
</div>
</page-container>
</template>
<script setup lang="ts" name="Relationship">
@ -181,7 +185,6 @@ const table = {
<style lang="less" scoped>
.relationship-container {
padding: 24px;
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0;

View File

@ -1,10 +1,12 @@
<template>
<div class="details-container">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="权限分配"><Permiss /></a-tab-pane>
<a-tab-pane key="2" tab="用户管理"><User /></a-tab-pane>
</a-tabs>
</div>
<page-container>
<div class="details-container">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="权限分配"><Permiss /></a-tab-pane>
<a-tab-pane key="2" tab="用户管理"><User /></a-tab-pane>
</a-tabs>
</div>
</page-container>
</template>
<script setup lang="ts" name="Detail">
@ -17,17 +19,9 @@ const activeKey = ref('1');
<style lang="less" scoped>
.details-container {
:deep(.ant-tabs-nav-wrap) {
background-color: #fff;
padding: 24px 0 0 24px;
}
:deep(.ant-tabs-content-holder) {
padding: 24px;
padding-left: 24px;
}
}
</style>

View File

@ -1,55 +1,57 @@
<template>
<a-card class="role-container">
<Search :columns="query.columns" />
<page-container>
<a-card class="role-container">
<Search :columns="query.columns" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="getRoleList_api"
model="TABLE"
:params="query.params"
>
<template #headerTitle>
<PermissionButton
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.clickAdd"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #action="slotProps">
<a-space :size="16">
<JTable
ref="tableRef"
:columns="table.columns"
:request="getRoleList_api"
model="TABLE"
:params="query.params"
>
<template #headerTitle>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.clickEdit(slotProps)"
type="primary"
:uhasPermission="`${permission}:add`"
@click="table.clickAdd"
>
<AIcon type="EditOutlined" />
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `确定要删除吗`,
onConfirm: () => table.clickDel(slotProps),
}"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
</template>
<div class="dialogs">
<AddDialog ref="addDialogRef" />
</div>
</a-card>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.clickEdit(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{ title: '删除' }"
:popConfirm="{
title: `确定要删除吗`,
onConfirm: () => table.clickDel(slotProps),
}"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<div class="dialogs">
<AddDialog ref="addDialogRef" />
</div>
</a-card>
</page-container>
</template>
<script setup lang="ts" name="Role">
@ -146,12 +148,10 @@ nextTick(() => {
<style lang="less" scoped>
.role-container {
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0;
}
}
}
</style>

View File

@ -1,46 +1,49 @@
<template>
<div class="user-container">
<Search :columns="query.columns" @search="query.search" />
<page-container>
<div class="user-container">
<Search :columns="query.columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="getUserList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
>
<template #headerTitle>
<!-- <a-button
<JTable
ref="tableRef"
:columns="table.columns"
:request="getUserList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
>
<template #headerTitle>
<!-- <a-button
type="primary"
@click="table.openDialog('add')"
style="margin-right: 10px"
><AIcon type="PlusOutlined" />新增</a-button
> -->
<PermissionButton
:uhasPermission="`${permission}:add`"
type="primary"
@click="table.openDialog('add')"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #type="slotProps">
{{ slotProps.type.name }}
</template>
<template #status="slotProps">
<BadgeStatus
:status="slotProps.status"
:text="slotProps.status ? '正常' : '禁用'"
:statusNames="{
1: 'success',
0: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<!-- <a-tooltip>
<PermissionButton
:uhasPermission="`${permission}:add`"
type="primary"
@click="table.openDialog('add')"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #type="slotProps">
{{ slotProps.type.name }}
</template>
<template #status="slotProps">
<BadgeStatus
:status="slotProps.status"
:text="slotProps.status ? '正常' : '禁用'"
:statusNames="{
1: 'success',
0: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<!-- <a-tooltip>
<template #title>编辑</template>
<a-button
style="padding: 0"
@ -50,7 +53,7 @@
<AIcon type="EditOutlined" />
</a-button>
</a-tooltip> -->
<!-- <a-popconfirm
<!-- <a-popconfirm
:title="`确定${slotProps.status ? '禁用' : '启用'}吗?`"
ok-text="确定"
cancel-text="取消"
@ -66,7 +69,7 @@
</a-button>
</a-tooltip>
</a-popconfirm> -->
<!-- <a-tooltip>
<!-- <a-tooltip>
<template #title>重置密码</template>
<a-button
style="padding: 0"
@ -76,7 +79,7 @@
<AIcon type="icon-zhongzhimima" />
</a-button>
</a-tooltip> -->
<!-- <a-popconfirm
<!-- <a-popconfirm
title="确认删除"
ok-text="确定"
cancel-text="取消"
@ -97,66 +100,67 @@
</a-tooltip>
</a-popconfirm> -->
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog('edit')"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:tooltip="{
title: `${slotProps.status ? '禁用' : '启用'}`,
}"
:popConfirm="{
title: `确定${
slotProps.status ? '禁用' : '启用'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
>
<stop-outlined v-if="slotProps.status" />
<play-circle-outlined v-else />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '重置密码',
}"
@click="table.openDialog('reset', slotProps)"
>
<AIcon type="icon-zhongzhimima" />
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{
title: slotProps.status
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.openDialog('edit')"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:action`"
type="link"
:tooltip="{
title: `${slotProps.status ? '禁用' : '启用'}`,
}"
:popConfirm="{
title: `确定${
slotProps.status ? '禁用' : '启用'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
>
<stop-outlined v-if="slotProps.status" />
<play-circle-outlined v-else />
</PermissionButton>
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
:tooltip="{
title: '重置密码',
}"
@click="table.openDialog('reset', slotProps)"
>
<AIcon type="icon-zhongzhimima" />
</PermissionButton>
<PermissionButton
type="link"
:uhasPermission="`${permission}:delete`"
:tooltip="{
title: slotProps.status
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除`,
onConfirm: () => table.clickDel(slotProps),
}"
:disabled="slotProps.status"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<div class="dialogs">
<EditUserDialog ref="editDialogRef" @confirm="table.refresh" />
<div class="dialogs">
<EditUserDialog ref="editDialogRef" @confirm="table.refresh" />
</div>
</div>
</div>
</page-container>
</template>
<script setup lang="ts" name="UserMange">
@ -354,8 +358,6 @@ type modalType = '' | 'add' | 'edit' | 'reset';
<style lang="less" scoped>
.user-container {
padding: 24px;
:deep(.ant-table-tbody) {
.ant-table-cell {
.ant-space-item {

View File

@ -703,10 +703,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@npmcli/arborist@*", "@npmcli/arborist@^6.2.2":
version "6.2.2"
resolved "https://registry.jetlinks.cn/@npmcli%2farborist/-/arborist-6.2.2.tgz#3ea668e7d368376a8477bd7bc3389bf634603b5b"
integrity sha512-cjK9CuA1cEovr4E1ljdgYU1UBdKJb4KvvULAEYOM1/qU0Que2X4DKyjIDBEy8MSWRY6PyaQ8oLGhwYIh8gUEEA==
"@npmcli/arborist@*", "@npmcli/arborist@^6.2.3":
version "6.2.3"
resolved "https://registry.jetlinks.cn/@npmcli%2farborist/-/arborist-6.2.3.tgz#31f8aed2588341864d3811151d929c01308f8e71"
integrity sha512-lpGOC2ilSJXcc2zfW9QtukcCTcMbl3fVI0z4wvFB2AFIl0C+Q6Wv7ccrpdrQa8rvJ1ZVuc6qkX7HVTyKlzGqKA==
dependencies:
"@isaacs/string-locale-compare" "^1.1.0"
"@npmcli/fs" "^3.1.0"
@ -3894,11 +3894,11 @@ libnpmaccess@*:
npm-registry-fetch "^14.0.3"
libnpmdiff@*:
version "5.0.10"
resolved "https://registry.jetlinks.cn/libnpmdiff/-/libnpmdiff-5.0.10.tgz#1813cc63b0370fdd41187ca0ce39df655536d648"
integrity sha512-FZdlnoPkj8w4RM3j5eLYhYzf5q416Tpl2aO3fc77gJ9ZeJFS8cVQAR6gK5+pSAaiRJGSlef4/em0uKBOTQjXXA==
version "5.0.11"
resolved "https://registry.jetlinks.cn/libnpmdiff/-/libnpmdiff-5.0.11.tgz#a8d3b9ff61e55f5cb377efc4ef06c7987236f5a1"
integrity sha512-oF+BCE8LwfSZaUkmIEKmfX4WmvE6puZhYKnRayynHrh6f1qMRqoutqIXlPS6wCF8IRV6sgAhXYOsBUYC6PTPCA==
dependencies:
"@npmcli/arborist" "^6.2.2"
"@npmcli/arborist" "^6.2.3"
"@npmcli/disparity-colors" "^3.0.0"
"@npmcli/installed-package-contents" "^2.0.0"
binary-extensions "^2.2.0"
@ -3909,11 +3909,11 @@ libnpmdiff@*:
tar "^6.1.13"
libnpmexec@*:
version "5.0.10"
resolved "https://registry.jetlinks.cn/libnpmexec/-/libnpmexec-5.0.10.tgz#281585adbf22935400f3c0456f88add4c69e4e74"
integrity sha512-m7Hqi2xXbzIjVbb+4PbOwkBvHLgG0tnQwCvzW7iTA8pL6FsnKSWfgTpWLiDLoPGCdO2q0D766ikvdknziomKzg==
version "5.0.11"
resolved "https://registry.jetlinks.cn/libnpmexec/-/libnpmexec-5.0.11.tgz#ac579b6ac1bd20c0ea191386129ba5cc5051ef61"
integrity sha512-4Ec55gMBgGiJmaFjSVNc8s9iu6xBuqGJubtrWrK+5uCHbSoQd8Fng/cLE63hyZQTwyj0LTvHn0j/UEr0bTPTvw==
dependencies:
"@npmcli/arborist" "^6.2.2"
"@npmcli/arborist" "^6.2.3"
"@npmcli/run-script" "^6.0.0"
chalk "^4.1.0"
ci-info "^3.7.1"
@ -3927,11 +3927,11 @@ libnpmexec@*:
walk-up-path "^1.0.0"
libnpmfund@*:
version "4.0.10"
resolved "https://registry.jetlinks.cn/libnpmfund/-/libnpmfund-4.0.10.tgz#b6228e4fcf91ed2064d59c4f7af701c1313d10e0"
integrity sha512-fPR3Y01Mditp/FNT4BUsilHCHgvzZRwxpQBbaUYBRG0lxBdO+AT8pHta9SmCSLwUn60bwmw2SDBxDv6bMWUi5Q==
version "4.0.11"
resolved "https://registry.jetlinks.cn/libnpmfund/-/libnpmfund-4.0.11.tgz#201aa162af6062387b3e505a732e0de101e2846e"
integrity sha512-tDJqNcTAEQURma4UXBVIpyw1CrL5RPla0rnx5dBK2jt+zPa6i62RwcYLNa9vHUYdGBoN993fZtl77ddEFj72xQ==
dependencies:
"@npmcli/arborist" "^6.2.2"
"@npmcli/arborist" "^6.2.3"
libnpmhook@*:
version "9.0.3"
@ -3950,11 +3950,11 @@ libnpmorg@*:
npm-registry-fetch "^14.0.3"
libnpmpack@*:
version "5.0.10"
resolved "https://registry.jetlinks.cn/libnpmpack/-/libnpmpack-5.0.10.tgz#9c84139f80d34068ffc66d09313931fb6e9c4554"
integrity sha512-yCkyi+XS7WS0XXXdCnt+/b6zEdXqhanIvS6sw8yzZ5lHElJruggDodZRBQR9HYewa1xeq5Lr11eOpEODenEpjA==
version "5.0.11"
resolved "https://registry.jetlinks.cn/libnpmpack/-/libnpmpack-5.0.11.tgz#b054a62e0c553b5685b02266a4a5036d9828ebdf"
integrity sha512-Ke2URk4d96SkxTEEUdW7TOWb0DLFrDWAdBEc1SPF/JrhebhS3/Rm1kazWOZ6JhK6PQBIsVPGmBq5MwboAtSR4w==
dependencies:
"@npmcli/arborist" "^6.2.2"
"@npmcli/arborist" "^6.2.3"
"@npmcli/run-script" "^6.0.0"
npm-package-arg "^10.1.0"
pacote "^15.0.8"