mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-11-30 02:58:31 +08:00
feat(全局): 路由切换取消未完成请求&icon 更新&ms-tree 树组件&ms-split-box 分割组件&ms-empty 全局空状态&部分样式调整
This commit is contained in:
parent
d6d1724f45
commit
5f6bf18411
@ -37,7 +37,7 @@
|
||||
"dependencies": {
|
||||
"@7polo/kity": "2.0.8",
|
||||
"@7polo/kityminder-core": "1.4.53",
|
||||
"@arco-design/web-vue": "^2.49.2",
|
||||
"@arco-design/web-vue": "^2.51.0",
|
||||
"@arco-themes/vue-ms-theme-default": "^0.0.28",
|
||||
"@form-create/arco-design": "^3.1.22",
|
||||
"@types/color": "^3.0.3",
|
||||
|
@ -1,25 +1,29 @@
|
||||
<template>
|
||||
<a-config-provider :locale="locale">
|
||||
<router-view />
|
||||
<global-setting />
|
||||
<template #empty>
|
||||
<MsEmpty />
|
||||
</template>
|
||||
<!-- <global-setting /> -->
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeMount, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import enUS from '@arco-design/web-vue/es/locale/lang/en-us';
|
||||
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
|
||||
import GlobalSetting from '@/components/pure/global-setting/index.vue';
|
||||
// import GlobalSetting from '@/components/pure/global-setting/index.vue';
|
||||
import useLocale from '@/locale/useLocale';
|
||||
import { saveBaseInfo } from '@/api/modules/setting/config';
|
||||
import { getLocalStorage, setLocalStorage } from '@/utils/local-storage';
|
||||
import { useUserStore } from '@/store';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { watchStyle, watchTheme, setFavicon } from '@/utils/theme';
|
||||
import { saveBaseInfo } from '@/api/modules/setting/config';
|
||||
import { GetPlatformIconUrl } from '@/api/requrls/setting/config';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getLocalStorage, setLocalStorage } from '@/utils/local-storage';
|
||||
import { watchStyle, watchTheme, setFavicon } from '@/utils/theme';
|
||||
import { WorkbenchRouteEnum } from './enums/routeEnum';
|
||||
import MsEmpty from '@/components/pure/ms-empty/index.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
|
@ -42,13 +42,9 @@ export class MSAxios {
|
||||
const axiosCanceler = new AxiosCanceler();
|
||||
|
||||
// 请求拦截器
|
||||
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
|
||||
this.axiosInstance.interceptors.request.use((config: CreateAxiosOptions) => {
|
||||
// 如果ignoreCancelToken为true,则不添加到pending中
|
||||
const {
|
||||
// @ts-ignore
|
||||
headers: { ignoreCancelToken },
|
||||
} = config;
|
||||
|
||||
const ignoreCancelToken = config.requestOptions?.ignoreCancelToken;
|
||||
const ignoreCancel =
|
||||
ignoreCancelToken !== undefined ? ignoreCancelToken : this.options.requestOptions?.ignoreCancelToken;
|
||||
|
||||
@ -107,7 +103,7 @@ export class MSAxios {
|
||||
headers: {
|
||||
'Content-type': ContentTypeEnum.FORM_DATA,
|
||||
// @ts-ignore
|
||||
'ignoreCancelToken': true, // 文件上传请求不需要添加到pending中
|
||||
'ignoreCancelToken': true, // 文件上传请求不需要添加到pending中,以免路由切换导致文件上传请求被取消
|
||||
},
|
||||
})
|
||||
.then((res: AxiosResponse<Result>) => {
|
||||
|
@ -199,8 +199,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||
errorMessageMode: 'message',
|
||||
// 是否加入时间戳
|
||||
joinTime: true,
|
||||
// 忽略重复请求
|
||||
ignoreCancelToken: true,
|
||||
// 忽略取消请求的token
|
||||
ignoreCancelToken: false,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ import { getLicenseUrl, addLicenseUrl } from '@/api/requrls/setting/authorizedMa
|
||||
import type { LicenseInfo } from '@/models/setting/authorizedManagement';
|
||||
// 获取当前信息
|
||||
export function getLicenseInfo() {
|
||||
return MSR.get<LicenseInfo>({ url: getLicenseUrl });
|
||||
return MSR.get<LicenseInfo>({ url: getLicenseUrl }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 添加License
|
||||
export function addLicense(data: string) {
|
||||
|
@ -39,7 +39,7 @@ export function testEmail(data: TestEmailParams) {
|
||||
|
||||
// 保存基础信息
|
||||
export function saveBaseInfo(data: SaveInfoParams) {
|
||||
return MSR.post({ url: SaveBaseInfoUrl, data });
|
||||
return MSR.post({ url: SaveBaseInfoUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 获取基础信息
|
||||
@ -64,7 +64,7 @@ export function savePageConfig(data: SavePageConfigParams) {
|
||||
|
||||
// 获取界面配置
|
||||
export function getPageConfig() {
|
||||
return MSR.get<PageConfigReturns>({ url: GetPageConfigUrl });
|
||||
return MSR.get<PageConfigReturns>({ url: GetPageConfigUrl }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 获取认证源列表
|
||||
|
@ -4,7 +4,7 @@ import { GetVersionUrl } from '@/api/requrls/system';
|
||||
|
||||
// 获取系统版本
|
||||
export function getSystemVersion() {
|
||||
return MSR.get<string>({ url: GetVersionUrl });
|
||||
return MSR.get<string>({ url: GetVersionUrl }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
export default { getSystemVersion };
|
||||
|
@ -8,7 +8,7 @@ export function login(data: LoginData) {
|
||||
}
|
||||
|
||||
export function isLogin() {
|
||||
return MSR.get<LoginRes>({ url: isLoginUrl });
|
||||
return MSR.get<LoginRes>({ url: isLoginUrl }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
@font-face {
|
||||
font-family: iconfont; /* Project id 3462279 */
|
||||
src: url('iconfont.woff2?t=1693190889145') format('woff2'), url('iconfont.woff?t=1693190889145') format('woff'),
|
||||
url('iconfont.ttf?t=1693190889145') format('truetype'), url('iconfont.svg?t=1693190889145#iconfont') format('svg');
|
||||
src: url('iconfont.woff2?t=1693381191489') format('woff2'), url('iconfont.woff?t=1693381191489') format('woff'),
|
||||
url('iconfont.ttf?t=1693381191489') format('truetype'), url('iconfont.svg?t=1693381191489#iconfont') format('svg');
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 16px;
|
||||
@ -10,6 +10,15 @@
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.icon-icon_folder_collapse1::before {
|
||||
content: '\e756';
|
||||
}
|
||||
.icon-icon_folder_filled1::before {
|
||||
content: '\e755';
|
||||
}
|
||||
.icon-icon_copy_filled::before {
|
||||
content: '\e754';
|
||||
}
|
||||
.icon-a-icon_file-jar_colorful_ash::before {
|
||||
content: '\e753';
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -5,6 +5,27 @@
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "DE、MS项目icon管理",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "37159110",
|
||||
"name": "icon_folder_collapse",
|
||||
"font_class": "icon_folder_collapse1",
|
||||
"unicode": "e756",
|
||||
"unicode_decimal": 59222
|
||||
},
|
||||
{
|
||||
"icon_id": "37157216",
|
||||
"name": "icon_folder_filled",
|
||||
"font_class": "icon_folder_filled1",
|
||||
"unicode": "e755",
|
||||
"unicode_decimal": 59221
|
||||
},
|
||||
{
|
||||
"icon_id": "37147506",
|
||||
"name": "icon_copy_filled",
|
||||
"font_class": "icon_copy_filled",
|
||||
"unicode": "e754",
|
||||
"unicode_decimal": 59220
|
||||
},
|
||||
{
|
||||
"icon_id": "37085019",
|
||||
"name": "icon_file- jar_colorful_ash",
|
||||
|
@ -14,6 +14,12 @@
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="icon_folder_collapse1" unicode="" d="M42.666667 725.333333c0 47.146667 40.021333 85.333333 89.386666 85.333334h268.202667c13.226667 0 25.856-5.632 34.346667-15.36L532.906667 682.666667h358.997333C941.312 682.666667 981.333333 644.48 981.333333 597.333333v-554.666666c0-47.146667-40.021333-85.333333-89.386666-85.333334H132.053333C82.688-42.666667 42.666667-4.48 42.666667 42.666667V725.333333z m336.64 0H132.053333v-682.666666h759.893334V597.333333H512c-13.226667 0-25.856 5.632-34.346667 15.36L379.306667 725.333333z m190.464-268.501333c17.493333 16.64 45.781333 16.64 63.232 0l111.786666-106.666667a41.301333 41.301333 0 0 0 0-60.330666l-111.786666-106.666667c-17.493333-16.64-45.738667-16.64-63.232 0a41.301333 41.301333 0 0 0 0 60.330667l80.170666 76.501333-80.170666 76.501333a41.301333 41.301333 0 0 0 0 60.330667z m-115.541334-60.330667a41.301333 41.301333 0 0 1 0 60.330667 46.208 46.208 0 0 1-63.232 0l-111.786666-106.666667a41.301333 41.301333 0 0 1 0-60.330666l111.786666-106.666667c17.493333-16.64 45.738667-16.64 63.232 0a41.301333 41.301333 0 0 1 0 60.330667L374.058667 320l80.170666 76.501333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_folder_filled1" unicode="" d="M42.666667 725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h357.632a42.666667 42.666667 0 0 0 38.144-23.594667L512 682.666667h426.666667a42.666667 42.666667 0 0 0 42.666666-42.666667v-597.333333a42.666667 42.666667 0 0 0-42.666666-42.666667H85.333333a42.666667 42.666667 0 0 0-42.666666 42.666667V725.333333z m106.666666-128a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h725.333334a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333h-725.333334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_copy_filled" unicode="" d="M725.333333 597.333333v-602.069333c0-20.949333-17.834667-37.930667-39.808-37.930667H167.808C145.834667-42.666667 128-25.685333 128-4.736V602.026667C128 623.018667 145.834667 640 167.808 640H682.666667a42.666667 42.666667 0 0 0 42.666666-42.666667z m158.165334 200.832A42.538667 42.538667 0 0 0 896 768v-533.333333a21.333333 21.333333 0 0 0-21.333333-21.333334h-42.666667a21.333333 21.333333 0 0 0-21.333333 21.333334V725.333333H405.333333a21.333333 21.333333 0 0 0-21.333333 21.333334v42.666666a21.333333 21.333333 0 0 0 21.333333 21.333334H853.333333c11.776 0 22.442667-4.778667 30.165334-12.501334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="a-icon_file-jar_colorful_ash" unicode="" d="M648.533333 853.333333a42.666667 42.666667 0 0 0 33.322667-16l170.666667-213.333333 2.730666-3.925333 1.152-1.877334a40.021333 40.021333 0 0 0 4.053334-9.941333 41.258667 41.258667 0 0 0 1.109333-5.973333L861.866667 597.333333v-85.333333h42.666666a85.333333 85.333333 0 0 0 85.333334-85.333333v-298.666667a85.333333 85.333333 0 0 0-85.333334-85.333333h-42.666666v-85.333334a42.666667 42.666667 0 0 0-42.666667-42.666666h-597.333333a42.666667 42.666667 0 0 0-42.666667 42.666666v85.333334h-42.666667a85.333333 85.333333 0 0 0-85.333333 85.333333v298.666667a85.333333 85.333333 0 0 0 85.333333 85.333333h42.666667V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h426.666666z m128-810.666666h-512v-42.666667h512v42.666667z m128 384h-768v-298.666667h768v298.666667z m-556.8-42.24v-116.181334c0-24.405333-2.176-43.008-6.528-55.722666-4.309333-12.757333-13.013333-23.509333-26.112-32.384-13.056-8.832-29.781333-13.226667-50.218666-13.226667-21.589333 0-38.314667 2.858667-50.176 8.704a63.104 63.104 0 0 0-27.477334 25.6c-6.485333 11.221333-10.282667 25.130667-11.434666 41.642667l63.146666 8.618666c0.085333-9.429333 0.896-16.469333 2.474667-21.034666a22.869333 22.869333 0 0 1 7.850667-11.093334c2.56-1.834667 6.144-2.730667 10.794666-2.730666 7.381333 0 12.8 2.730667 16.256 8.234666 3.456 5.504 5.205333 14.762667 5.205334 27.733334v131.84h66.176z m174.848 0L602.88 170.666667h-69.12l-10.496 35.285333H448l-10.368-35.285333H370.176l80.341333 213.76h72.064z m212.48 0c20.394667 0 36.010667-1.706667 46.805334-5.205334 10.794667-3.498667 19.498667-9.984 26.112-19.498666 6.570667-9.472 9.898667-20.992 9.898666-34.602667 0-11.861333-2.56-22.101333-7.594666-30.72a59.306667 59.306667 0 0 0-20.864-20.906667c-5.632-3.413333-13.354667-6.229333-23.168-8.490666 7.893333-2.602667 13.610667-5.248 17.194666-7.850667 2.432-1.749333 5.973333-5.504 10.581334-11.221333 4.608-5.76 7.68-10.154667 9.258666-13.269334L835.242667 170.666667h-74.666667l-35.285333 65.322666c-4.48 8.448-8.490667 13.952-11.946667 16.469334a27.733333 27.733333 0 0 1-16.213333 4.992h-5.845334V170.666667h-66.346666v213.76h110.08z m-249.258666-55.381334l-23.466667-76.842666h47.104l-23.637333 76.8z m234.496 12.245334h-29.013334v-43.477334h27.861334c2.986667 0 8.832 0.981333 17.493333 2.944a17.493333 17.493333 0 0 1 10.709333 6.698667 19.754667 19.754667 0 0 1 4.181334 12.373333c0 6.912-2.218667 12.245333-6.570667 15.914667-4.394667 3.712-12.586667 5.546667-24.661333 5.546667zM563.2 768h-298.666667v-256h512V554.666667h-170.666666a42.666667 42.666667 0 0 0-42.666667 42.666666V768z m85.333333-25.6V640h81.92L648.533333 742.4z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_git" unicode="" d="M974.506667 398.592L526.805333 847.829333c-7.338667 7.338667-20.565333 7.338667-29.354666 0l-123.306667-123.306666 114.474667-114.517334a65.706667 65.706667 0 0 0 29.397333 5.845334 74.24 74.24 0 0 0 74.837333-74.837334c0-10.282667-1.450667-20.565333-5.845333-29.354666l91.008-91.050667a65.706667 65.706667 0 0 0 29.354667 5.888 74.24 74.24 0 0 0 74.88-74.88 74.24 74.24 0 0 0-74.88-74.88 74.24 74.24 0 0 0-74.88 74.88c0 10.24 1.493333 20.565333 5.888 29.354667l-91.008 91.008h-1.493334v-173.226667a75.52 75.52 0 0 0 46.976-70.442667 74.24 74.24 0 0 0-74.837333-74.88 74.24 74.24 0 0 0-74.88 74.88 75.52 75.52 0 0 0 46.933333 70.442667v170.325333a75.52 75.52 0 0 0-46.933333 70.442667c0 10.282667 1.450667 20.565333 5.845333 29.354667L334.506667 684.885333l-286.293334-286.293333c-7.338667-7.338667-7.338667-20.565333 0-29.354667l449.237334-449.237333c7.338667-7.338667 20.565333-7.338667 29.354666 0l449.237334 449.237333a20.906667 20.906667 0 0 1-1.450667 29.354667z" horiz-adv-x="1024" />
|
||||
|
Before Width: | Height: | Size: 351 KiB After Width: | Height: | Size: 353 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -130,11 +130,16 @@
|
||||
}
|
||||
|
||||
/** 气泡确认框 **/
|
||||
.ms-pop-confirm {
|
||||
.ms-pop-confirm--hidden-cancel {
|
||||
.arco-btn-secondary {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
.ms-pop-confirm--hidden-icon {
|
||||
.arco-popconfirm-icon {
|
||||
@apply !hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/** 按钮 **/
|
||||
.arco-btn-primary {
|
||||
@ -180,6 +185,11 @@
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
}
|
||||
.arco-input-clear-btn {
|
||||
.arco-icon-close {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.arco-input-wrapper,
|
||||
.arco-textarea-wrapper,
|
||||
.arco-input-tag,
|
||||
@ -200,7 +210,7 @@
|
||||
.arco-input-tag {
|
||||
.arco-icon {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-4);
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
}
|
||||
.arco-select-view-inner,
|
||||
@ -209,6 +219,11 @@
|
||||
background-color: var(--color-text-n8) !important;
|
||||
}
|
||||
}
|
||||
.arco-select-view-icon svg,
|
||||
.arco-select-view-clear-btn svg {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
.arco-input-error,
|
||||
.arco-select-view-error,
|
||||
.arco-input-tag-error {
|
||||
@ -250,6 +265,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** form-item **/
|
||||
.arco-form-item-content-flex {
|
||||
@apply flex-wrap;
|
||||
}
|
||||
.arco-form-item-status-success .arco-input-wrapper:not(.arco-input-disabled).arco-input-focus {
|
||||
border: 1px solid rgb(var(--primary-5)) !important;
|
||||
background: none;
|
||||
@ -258,11 +278,6 @@
|
||||
.arco-form-item-status-success .arco-input-wrapper:not(.arco-input-disabled) {
|
||||
border-color: var(--color-text-input-border);
|
||||
}
|
||||
|
||||
/** form-item **/
|
||||
.arco-form-item-content-flex {
|
||||
@apply flex-wrap;
|
||||
}
|
||||
.arco-form-item-message {
|
||||
width: 100%;
|
||||
}
|
||||
@ -629,18 +644,6 @@
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
}
|
||||
|
||||
/** 标签样式 **/
|
||||
.arco-tag {
|
||||
.arco-icon {
|
||||
font-size: 14px !important;
|
||||
color: var(--color-text-4) !important;
|
||||
&:hover {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-1) !important;
|
||||
}
|
||||
}
|
||||
.arco-icon-hover.arco-tag-icon-hover::before {
|
||||
background: none !important;
|
||||
}
|
||||
.arco-picker-input-active input {
|
||||
border-radius: var(--border-radius-mini);
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
@import url('./arco-reset.less');
|
||||
:root {
|
||||
--border-radius-mini: 2px;
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
@ -1,5 +1,4 @@
|
||||
/** 主题变量覆盖 **/
|
||||
@border-radius-mini: 2px;
|
||||
@border-radius-small: 4px;
|
||||
@border-radius-medium: 6px;
|
||||
@border-radius-large: 12px;
|
||||
|
@ -261,6 +261,9 @@
|
||||
margin: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.arco-cascader-option-active {
|
||||
background-color: rgb(var(--primary-1));
|
||||
}
|
||||
}
|
||||
.arco-cascader-panel-column:first-child {
|
||||
.arco-checkbox {
|
||||
|
376
frontend/src/components/business/ms-tree/index.vue
Normal file
376
frontend/src/components/business/ms-tree/index.vue
Normal file
@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<a-tree
|
||||
v-bind="props"
|
||||
ref="treeRef"
|
||||
v-model:expanded-keys="expandedKeys"
|
||||
:data="treeData"
|
||||
class="ms-tree"
|
||||
@drop="onDrop"
|
||||
@select="select"
|
||||
>
|
||||
<template v-if="$slots['title']" #title="_props">
|
||||
<slot name="title" v-bind="_props"></slot>
|
||||
</template>
|
||||
<template v-if="$slots['extra']" #extra="_props">
|
||||
<div
|
||||
:class="[
|
||||
'ms-tree-node-extra',
|
||||
innerFocusNodeKey === _props[props.fieldNames.key] ? 'ms-tree-node-extra--focus' : '',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
class="ml-[-4px] flex h-[32px] items-center rounded-[var(--border-radius-small)] bg-[rgb(var(--primary-1))]"
|
||||
>
|
||||
<slot name="extra" v-bind="_props"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="props.nodeMoreActions"
|
||||
:list="props.nodeMoreActions"
|
||||
trigger="click"
|
||||
@select="handleNodeMoreSelect($event, _props)"
|
||||
@close="moreActionsClose"
|
||||
>
|
||||
<MsButton
|
||||
type="text"
|
||||
size="mini"
|
||||
class="ms-tree-node-extra__more"
|
||||
@click="innerFocusNodeKey = _props[props.fieldNames.key]"
|
||||
>
|
||||
<MsIcon type="icon-icon_more_outlined" size="14" class="text-[var(--color-text-4)]" />
|
||||
</MsButton>
|
||||
</MsTableMoreAction>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount, ref, h, watch, Ref, watchEffect } from 'vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { mapTree } from '@/utils/index';
|
||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
|
||||
import type { MsTreeNodeData, MsTreeFieldNames, MsTreeSelectedData } from './types';
|
||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
data: MsTreeNodeData[];
|
||||
keyword?: string; // 搜索关键字
|
||||
searchDebounce?: number; // 搜索防抖 ms 数
|
||||
draggable?: boolean; // 是否可拖拽
|
||||
blockNode?: boolean; // 是否块级节点
|
||||
showLine?: boolean; // 是否展示连接线
|
||||
defaultExpandAll?: boolean; // 是否默认展开所有节点
|
||||
selectable?: boolean; // 是否可选中
|
||||
fieldNames?: MsTreeFieldNames; // 自定义字段名
|
||||
focusNodeKey?: string | number; // 聚焦的节点 key
|
||||
nodeMoreActions?: ActionsItem[]; // 节点展示在省略号按钮内的更多操作
|
||||
expandAll?: boolean; // 是否展开/折叠所有节点,true 为全部展开,false 为全部折叠
|
||||
}>(),
|
||||
{
|
||||
searchDebounce: 300,
|
||||
defaultExpandAll: false,
|
||||
selectable: true,
|
||||
fieldNames: () => ({
|
||||
key: 'key',
|
||||
title: 'title',
|
||||
children: 'children',
|
||||
isLeaf: 'isLeaf',
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'select', selectedKeys: Array<string | number>, node: MsTreeNodeData): void;
|
||||
(
|
||||
e: 'dragOver',
|
||||
tree: MsTreeNodeData[],
|
||||
dragNode: MsTreeNodeData, // 被拖拽的节点
|
||||
dropNode: MsTreeNodeData, // 放入的节点
|
||||
dropPosition: number // 放入的位置,-1 为放入节点前,1 为放入节点后,0 为放入节点内
|
||||
): void;
|
||||
(e: 'moreActionSelect', item: ActionsItem, node: MsTreeNodeData): void;
|
||||
(e: 'update:focusNodeKey', val: string | number): void;
|
||||
(e: 'moreActionsClose'): void;
|
||||
}>();
|
||||
|
||||
const treeRef: Ref = ref(null);
|
||||
const originalTreeData = ref<MsTreeNodeData[]>([]);
|
||||
|
||||
function init() {
|
||||
originalTreeData.value = mapTree<MsTreeNodeData>(props.data, (node: MsTreeNodeData) => {
|
||||
if (!props.showLine) {
|
||||
// 不展示连接线时才设置节点图标,因为展示连接线时非叶子节点会展示默认的折叠图标。它不会覆盖 switcherIcon,但是会被 switcherIcon 覆盖
|
||||
node.icon = () => h('span', { class: 'hidden' });
|
||||
}
|
||||
if (
|
||||
node[props.fieldNames.isLeaf] ||
|
||||
!node[props.fieldNames.children] ||
|
||||
node[props.fieldNames.children]?.length === 0
|
||||
) {
|
||||
// 设置子节点图标,会覆盖 icon。当展示连接线时,需要设置 switcherIcon 以覆盖组件的默认图标;不展示连接线则是 icon
|
||||
node[props.showLine ? 'switcherIcon' : 'icon'] = () => h('span', { class: 'hidden' });
|
||||
}
|
||||
node.disabled = false;
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
init();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
() => {
|
||||
init();
|
||||
}
|
||||
);
|
||||
|
||||
const expandedKeys = ref<(string | number)[]>([]);
|
||||
|
||||
/**
|
||||
* 根据关键字过滤树节点
|
||||
* @param keyword 搜索关键字
|
||||
*/
|
||||
function searchData(keyword: string) {
|
||||
const search = (data: MsTreeNodeData[]) => {
|
||||
const result: MsTreeNodeData[] = [];
|
||||
data.forEach((item) => {
|
||||
if (item[props.fieldNames.title].toLowerCase().indexOf(keyword.toLowerCase()) > -1) {
|
||||
result.push({ ...item });
|
||||
} else if (item[props.fieldNames.children]) {
|
||||
const filterData = search(item[props.fieldNames.children]);
|
||||
if (filterData.length) {
|
||||
result.push({
|
||||
...item,
|
||||
[props.fieldNames.children]: filterData,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
expandedKeys.value = result.map((item) => item[props.fieldNames.key]); // 搜索时,匹配的节点需要自动展开
|
||||
return result;
|
||||
};
|
||||
|
||||
return search(originalTreeData.value);
|
||||
}
|
||||
|
||||
const treeData = ref<MsTreeNodeData[]>([]);
|
||||
|
||||
// 防抖搜索
|
||||
const updateDebouncedSearch = debounce(() => {
|
||||
if (props.keyword) {
|
||||
treeData.value = searchData(props.keyword);
|
||||
}
|
||||
}, props.searchDebounce);
|
||||
|
||||
watchEffect(() => {
|
||||
if (!props.keyword) {
|
||||
treeData.value = originalTreeData.value;
|
||||
} else {
|
||||
updateDebouncedSearch();
|
||||
}
|
||||
});
|
||||
|
||||
function loop(
|
||||
_data: MsTreeNodeData[],
|
||||
key: string | number | undefined,
|
||||
callback: (item: MsTreeNodeData, index: number, arr: MsTreeNodeData[]) => void
|
||||
) {
|
||||
_data.some((item, index, arr) => {
|
||||
if (item[props.fieldNames.key] === key) {
|
||||
callback(item, index, arr);
|
||||
return true;
|
||||
}
|
||||
if (item[props.fieldNames.children]) {
|
||||
return loop(item[props.fieldNames.children], key, callback);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理拖拽结束
|
||||
*/
|
||||
function onDrop({
|
||||
dragNode,
|
||||
dropNode,
|
||||
dropPosition,
|
||||
}: {
|
||||
dragNode: MsTreeNodeData; // 被拖拽的节点
|
||||
dropNode: MsTreeNodeData; // 放入的节点
|
||||
dropPosition: number; // 放入的位置,-1 为放入节点前,1 为放入节点后,0 为放入节点内
|
||||
}) {
|
||||
loop(originalTreeData.value, dragNode.key, (item, index, arr) => {
|
||||
arr.splice(index, 1);
|
||||
});
|
||||
|
||||
if (dropPosition === 0) {
|
||||
// 放入节点内
|
||||
loop(originalTreeData.value, dropNode.key, (item) => {
|
||||
item.children = item.children || [];
|
||||
item.children.push(dragNode);
|
||||
});
|
||||
dropNode.isLeaf = false;
|
||||
if (props.showLine) {
|
||||
delete dropNode.switcherIcon; // 放入的节点的 children 放入了被拖拽的节点,需要删除 switcherIcon 以展示默认的折叠图标
|
||||
}
|
||||
} else {
|
||||
// 放入节点前或后
|
||||
loop(originalTreeData.value, dropNode.key, (item, index, arr) => {
|
||||
arr.splice(dropPosition < 0 ? index : index + 1, 0, dragNode);
|
||||
});
|
||||
}
|
||||
emit('dragOver', originalTreeData.value, dragNode, dropNode, dropPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理树节点选中(非复选框)
|
||||
*/
|
||||
function select(selectedKeys: Array<string | number>, data: MsTreeSelectedData) {
|
||||
emit('select', selectedKeys, data.selectedNodes);
|
||||
}
|
||||
|
||||
const innerFocusNodeKey = ref(props.focusNodeKey || ''); // 聚焦的节点,一般用于在操作扩展按钮时,高亮当前节点,保持扩展按钮持续显示
|
||||
|
||||
watch(
|
||||
() => props.focusNodeKey,
|
||||
(val) => {
|
||||
innerFocusNodeKey.value = val || '';
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => innerFocusNodeKey.value,
|
||||
(val) => {
|
||||
emit('update:focusNodeKey', val);
|
||||
}
|
||||
);
|
||||
|
||||
const focusEl = ref<HTMLElement | null>(); // 存储聚焦的节点元素
|
||||
|
||||
watch(
|
||||
() => innerFocusNodeKey.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
focusEl.value = treeRef.value?.$el.querySelector(`[data-key=${val}]`);
|
||||
if (focusEl.value) {
|
||||
focusEl.value.style.backgroundColor = 'rgb(var(--primary-1))';
|
||||
}
|
||||
} else if (focusEl.value) {
|
||||
focusEl.value.style.backgroundColor = '';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 处理树节点更多按钮事件
|
||||
* @param item
|
||||
*/
|
||||
function handleNodeMoreSelect(item: ActionsItem, node: MsTreeNodeData) {
|
||||
emit('moreActionSelect', item, node);
|
||||
}
|
||||
|
||||
function moreActionsClose() {
|
||||
emit('moreActionsClose');
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.expandAll,
|
||||
(val) => {
|
||||
if (typeof val === 'boolean') {
|
||||
treeRef.value?.expandAll(val);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ms-tree {
|
||||
.arco-tree-node {
|
||||
border-radius: var(--border-radius-small);
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-1));
|
||||
}
|
||||
.arco-tree-node-minus-icon,
|
||||
.arco-tree-node-plus-icon {
|
||||
border: 1px solid var(--color-text-4);
|
||||
border-radius: var(--border-radius-mini);
|
||||
background-color: white;
|
||||
&::after,
|
||||
&::before {
|
||||
background-color: var(--color-text-4);
|
||||
}
|
||||
}
|
||||
.arco-tree-node-switcher {
|
||||
.arco-tree-node-switcher-icon {
|
||||
@apply flex;
|
||||
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
}
|
||||
.arco-tree-node-title {
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-1));
|
||||
+ .ms-tree-node-extra {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
.arco-tree-node-drag-icon {
|
||||
.arco-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ms-tree-node-extra {
|
||||
@apply relative hidden;
|
||||
&:hover {
|
||||
@apply block;
|
||||
}
|
||||
.ms-tree-node-extra__btn,
|
||||
.ms-tree-node-extra__more {
|
||||
padding: 4px;
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-9));
|
||||
.arco-icon {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
.ms-tree-node-extra__more {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
.ms-tree-node-extra--focus {
|
||||
@apply block;
|
||||
}
|
||||
.arco-tree-node-custom-icon {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
.arco-tree-node-selected {
|
||||
.arco-tree-node-minus-icon,
|
||||
.arco-tree-node-plus-icon {
|
||||
border: 1px solid rgb(var(--primary-5));
|
||||
border-radius: var(--border-radius-mini);
|
||||
background-color: white;
|
||||
&::after,
|
||||
&::before {
|
||||
background-color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
.arco-tree-node-switcher-icon .arco-icon,
|
||||
.arco-tree-node-title {
|
||||
font-weight: 500 !important;
|
||||
color: rgb(var(--primary-5));
|
||||
* {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
28
frontend/src/components/business/ms-tree/types.ts
Normal file
28
frontend/src/components/business/ms-tree/types.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import type { TreeNodeData, TreeFieldNames } from '@arco-design/web-vue';
|
||||
|
||||
export interface MsTreeFieldNames extends TreeFieldNames {
|
||||
key: string;
|
||||
title: string;
|
||||
children: string;
|
||||
isLeaf: string;
|
||||
}
|
||||
|
||||
export type MsTreeNodeData = {
|
||||
[key: string]: any;
|
||||
} & TreeNodeData;
|
||||
|
||||
export interface MsTreeNodeStatus {
|
||||
loading: boolean;
|
||||
checked: boolean;
|
||||
selected: boolean;
|
||||
indeterminate: boolean;
|
||||
expanded: boolean;
|
||||
isLeaf: boolean;
|
||||
}
|
||||
|
||||
export interface MsTreeSelectedData {
|
||||
selected?: boolean;
|
||||
selectedNodes: MsTreeNodeData[];
|
||||
node?: MsTreeNodeData;
|
||||
e?: Event;
|
||||
}
|
@ -68,7 +68,9 @@
|
||||
return currentOptions.value.filter((item) => props.value.includes(item.id)) || [];
|
||||
});
|
||||
|
||||
const change = (value: string | number | Record<string, any> | (string | number | Record<string, any>)[]) => {
|
||||
const change = (
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) => {
|
||||
const tmpArr = Array.isArray(value) ? value : [value];
|
||||
const { valueKey } = props;
|
||||
emit(
|
||||
|
@ -225,7 +225,7 @@
|
||||
});
|
||||
|
||||
function execCommandFontFamily(
|
||||
value: string | number | Record<string, any> | (string | number | Record<string, any>)[]
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
if (value === t('minder.menu.font.font')) {
|
||||
return;
|
||||
@ -234,7 +234,7 @@
|
||||
}
|
||||
|
||||
function execCommandFontSize(
|
||||
value: string | number | Record<string, any> | (string | number | Record<string, any>)[]
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
if (typeof value !== 'number') {
|
||||
return;
|
||||
|
24
frontend/src/components/pure/ms-empty/index.vue
Normal file
24
frontend/src/components/pure/ms-empty/index.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<a-empty :description="t('common.noData')" :in-config-provider="props.inConfigProvider">
|
||||
<template #image>
|
||||
<span class="hidden"></span>
|
||||
</template>
|
||||
</a-empty>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
inConfigProvider?: boolean;
|
||||
}>(),
|
||||
{
|
||||
inConfigProvider: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
@ -38,7 +38,9 @@
|
||||
|
||||
const props = defineProps<PageOptionsProps>();
|
||||
|
||||
const handleChange = (value: string | number | Record<string, any> | (string | number | Record<string, any>)[]) => {
|
||||
const handleChange = (
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) => {
|
||||
emit('change', value as number);
|
||||
};
|
||||
|
||||
|
120
frontend/src/components/pure/ms-split-box/index.vue
Normal file
120
frontend/src/components/pure/ms-split-box/index.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<a-split
|
||||
v-model:size="innerWidth"
|
||||
:min="props.min"
|
||||
:max="props.max"
|
||||
:class="['h-full', isExpandedLeft ? '' : 'expanded-panel', isExpandAnimating ? 'animating' : '']"
|
||||
>
|
||||
<template #first>
|
||||
<div class="ms-split-box ms-split-box--left">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
</template>
|
||||
<template #second>
|
||||
<div class="ms-split-box ms-split-box--right">
|
||||
<div class="expand-icon" @click="changeFolderExpand">
|
||||
<MsIcon
|
||||
:type="isExpandedLeft ? 'icon-icon_up-left_outlined' : 'icon-icon_down-right_outlined'"
|
||||
class="text-[var(--color-text-brand)]"
|
||||
size="12"
|
||||
/>
|
||||
</div>
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</template>
|
||||
</a-split>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
width?: number | string;
|
||||
min?: number | string;
|
||||
max?: number | string;
|
||||
}>(),
|
||||
{
|
||||
width: '300px',
|
||||
min: '250px',
|
||||
max: 0.5,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:width']);
|
||||
|
||||
const innerWidth = ref(props.width || '300px');
|
||||
|
||||
watch(
|
||||
() => props.width,
|
||||
(val) => {
|
||||
if (val !== undefined) {
|
||||
innerWidth.value = val;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => innerWidth.value,
|
||||
(val) => {
|
||||
emit('update:width', val);
|
||||
}
|
||||
);
|
||||
|
||||
const isExpandedLeft = ref(true);
|
||||
const isExpandAnimating = ref(false); // 控制动画类
|
||||
|
||||
function changeFolderExpand() {
|
||||
isExpandAnimating.value = true;
|
||||
isExpandedLeft.value = !isExpandedLeft.value;
|
||||
if (isExpandedLeft.value) {
|
||||
innerWidth.value = props.width || '300px';
|
||||
} else {
|
||||
innerWidth.value = '0px';
|
||||
}
|
||||
// 动画结束,去掉动画类
|
||||
setTimeout(() => {
|
||||
isExpandAnimating.value = false;
|
||||
}, 300);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/* stylelint-disable value-keyword-case */
|
||||
.expanded-panel {
|
||||
:deep(.arco-split-trigger) {
|
||||
@apply hidden;
|
||||
}
|
||||
:deep(.arco-split-pane) {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.animating {
|
||||
:deep(.arco-split-pane) {
|
||||
overflow: hidden;
|
||||
transition: flex 0.3s ease;
|
||||
}
|
||||
}
|
||||
.ms-split-box {
|
||||
@apply relative h-full overflow-auto;
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
.ms-split-box--left {
|
||||
width: calc(v-bind(innerWidth) - 4px);
|
||||
}
|
||||
.ms-split-box--right {
|
||||
@apply w-full;
|
||||
.expand-icon {
|
||||
@apply absolute cursor-pointer;
|
||||
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 8px 2px;
|
||||
border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
|
||||
background-color: var(--color-text-n8);
|
||||
}
|
||||
}
|
||||
:deep(.arco-split-trigger-icon) {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<a-dropdown trigger="hover" @select="selectHandler">
|
||||
<MsButton>
|
||||
<slot><icon-more /></slot>
|
||||
</MsButton>
|
||||
<a-dropdown :trigger="props.trigger || 'hover'" @select="selectHandler" @popup-visible-change="visibleChange">
|
||||
<slot>
|
||||
<MsButton><icon-more /></MsButton>
|
||||
</slot>
|
||||
<template #content>
|
||||
<template v-for="item of props.list">
|
||||
<a-divider v-if="item.isDivider" :key="`${item.label}-divider`" class="ms-dropdown-divider" />
|
||||
@ -21,14 +21,21 @@
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
list: ActionsItem[];
|
||||
trigger?: 'click' | 'hover' | 'focus' | 'contextMenu' | ('click' | 'hover' | 'focus' | 'contextMenu')[] | undefined;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
const emit = defineEmits(['select', 'close']);
|
||||
|
||||
function selectHandler(value: SelectedValue) {
|
||||
const item = props.list.find((e: ActionsItem) => t(e.label || '') === value);
|
||||
emit('select', item);
|
||||
}
|
||||
|
||||
function visibleChange(val: boolean) {
|
||||
if (!val) {
|
||||
emit('close');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -124,9 +124,11 @@
|
||||
</template>
|
||||
|
||||
<template #empty>
|
||||
<div class="flex h-[20px] flex-col items-center justify-center">
|
||||
<span class="text-[14px] text-[var(--color-text-4)]">{{ t('msTable.empty') }}</span>
|
||||
</div>
|
||||
<slot name="empty">
|
||||
<div class="flex h-[20px] flex-col items-center justify-center">
|
||||
<span class="text-[14px] text-[var(--color-text-4)]">{{ t('msTable.empty') }}</span>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
</a-table>
|
||||
<div
|
||||
|
@ -220,7 +220,9 @@
|
||||
return !NOT_SHOW_PROJECT_SELECT_MODULE.includes(route.fullPath.split('/')[1]);
|
||||
});
|
||||
|
||||
function selectProject(value: string | number | Record<string, any> | undefined) {
|
||||
function selectProject(
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
appStore.setCurrentProjectId(value as string);
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,13 @@ export const pathMap = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_MEMBER', // 项目管理-文件管理
|
||||
locale: 'menu.projectManagement.fileManagement',
|
||||
route: RouteEnum.PROJECT_MANAGEMENT_FILE_MANAGEMENT,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -16,7 +16,7 @@ export enum PerformanceTestRouteEnum {
|
||||
|
||||
export enum ProjectManagementRouteEnum {
|
||||
PROJECT_MANAGEMENT = 'projectManagement',
|
||||
PROJECT_MANAGEMENT_INDEX = 'projectManagementIndex',
|
||||
PROJECT_MANAGEMENT_FILE_MANAGEMENT = 'projectManagementFileManageMent',
|
||||
PROJECT_MANAGEMENT_LOG = 'projectManagementLog',
|
||||
PROJECT_MANAGEMENT_PERMISSION = 'projectManagementPermission',
|
||||
PROJECT_MANAGEMENT_PERMISSION_BASIC_INFO = 'projectManagementPermissionBasicInfo',
|
||||
|
@ -8,7 +8,7 @@ import { useUserStore, useVisitStore } from '@/store';
|
||||
export default function useVisit(key: string, needTimeStamp = false) {
|
||||
const userStore = useUserStore();
|
||||
const visitStore = useVisitStore();
|
||||
const localKey = `${userStore.accountId}-${key}-${needTimeStamp ? new Date().getTime() : ''}`;
|
||||
const localKey = `${userStore.id}-${key}-${needTimeStamp ? new Date().getTime() : ''}`;
|
||||
const addVisited = () => {
|
||||
visitStore.addVisitedKey(localKey);
|
||||
};
|
||||
|
@ -47,4 +47,5 @@ export default {
|
||||
'common.unSaveLeaveContent': 'The system may not save your changes',
|
||||
'common.leave': 'Leave',
|
||||
'common.rename': 'Rename',
|
||||
'common.noData': 'No data',
|
||||
};
|
||||
|
@ -20,13 +20,14 @@ Object.keys(_Vmodules).forEach((key) => {
|
||||
export default {
|
||||
message: {
|
||||
'menu.workbench': 'Workbench',
|
||||
'menu.testPlan': 'Test plan',
|
||||
'menu.bugManagement': 'Bug management',
|
||||
'menu.featureTest': 'Feature test',
|
||||
'menu.apiTest': 'API test',
|
||||
'menu.uiTest': 'UI test',
|
||||
'menu.performanceTest': 'Performance test',
|
||||
'menu.projectManagement': 'Project management',
|
||||
'menu.testPlan': 'Test Plan',
|
||||
'menu.bugManagement': 'Bug',
|
||||
'menu.featureTest': 'Feature Test',
|
||||
'menu.apiTest': 'API Test',
|
||||
'menu.uiTest': 'UI Test',
|
||||
'menu.performanceTest': 'Performance Test',
|
||||
'menu.projectManagement': 'Project',
|
||||
'menu.projectManagement.fileManagement': 'File Management',
|
||||
'menu.projectManagement.projectPermission': 'Project Permission',
|
||||
'menu.projectManagement.log': 'Log',
|
||||
'menu.settings': 'Settings',
|
||||
@ -39,7 +40,7 @@ export default {
|
||||
'menu.settings.system.resourcePool': 'Resource Pool',
|
||||
'menu.settings.system.resourcePoolDetail': 'Add resource pool',
|
||||
'menu.settings.system.resourcePoolEdit': 'Edit resource pool',
|
||||
'menu.settings.system.parameter': 'System parameter',
|
||||
'menu.settings.system.parameter': 'System Parameter',
|
||||
'menu.settings.system.log': 'Log',
|
||||
'menu.settings.organization': 'Organization',
|
||||
'menu.settings.organization.member': 'Member',
|
||||
|
@ -49,4 +49,5 @@ export default {
|
||||
'common.unSaveLeaveContent': '系统可能不会保存你所做的更改',
|
||||
'common.leave': '离开',
|
||||
'common.rename': '重命名',
|
||||
'common.noData': '暂无数据',
|
||||
};
|
||||
|
@ -27,6 +27,7 @@ export default {
|
||||
'menu.performanceTest': '性能测试',
|
||||
'menu.projectManagement': '项目管理',
|
||||
'menu.projectManagement.log': '日志',
|
||||
'menu.projectManagement.fileManagement': '文件管理',
|
||||
'menu.projectManagement.projectPermission': '项目与权限',
|
||||
'menu.settings': '系统设置',
|
||||
'menu.settings.system': '系统',
|
||||
|
@ -2,11 +2,14 @@ import type { Router } from 'vue-router';
|
||||
import { setRouteEmitter } from '@/utils/route-listener';
|
||||
import setupUserLoginInfoGuard from './userLoginInfo';
|
||||
import setupPermissionGuard from './permission';
|
||||
import { AxiosCanceler } from '@/api/http/axiosCancel';
|
||||
|
||||
function setupPageGuard(router: Router) {
|
||||
const axiosCanceler = new AxiosCanceler();
|
||||
router.beforeEach(async (to) => {
|
||||
// 监听路由变化
|
||||
setRouteEmitter(to);
|
||||
axiosCanceler.removeAllPending();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,6 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_INDEX,
|
||||
component: () => import('@/views/project-management/index.vue'),
|
||||
meta: {
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
// 项目与权限
|
||||
{
|
||||
path: 'permission',
|
||||
@ -87,6 +79,17 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||
},
|
||||
],
|
||||
},
|
||||
// 文件管理
|
||||
{
|
||||
path: 'fileManagement',
|
||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_FILE_MANAGEMENT,
|
||||
component: () => import('@/views/project-management/fileManagement/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.projectManagement.fileManagement',
|
||||
roles: ['*'],
|
||||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
// 项目日志
|
||||
{
|
||||
path: 'log',
|
||||
|
@ -26,7 +26,7 @@ const useUserStore = defineStore('user', {
|
||||
locationName: undefined,
|
||||
phone: undefined,
|
||||
registrationDate: undefined,
|
||||
accountId: undefined,
|
||||
id: undefined,
|
||||
certification: undefined,
|
||||
role: '',
|
||||
salt: '',
|
||||
|
@ -13,7 +13,7 @@ export interface UserState {
|
||||
locationName?: string;
|
||||
phone?: string;
|
||||
registrationDate?: string;
|
||||
accountId?: string;
|
||||
id?: string;
|
||||
certification?: number;
|
||||
role: RoleType;
|
||||
lastOrganizationId?: string;
|
||||
|
@ -72,7 +72,7 @@
|
||||
</MsCard>
|
||||
<div class="log-card">
|
||||
<div class="log-card-header">
|
||||
<div class="text-[var(--color-text-000)]">{{ t('system.log.log') }}</div>
|
||||
<div class="font-medium text-[var(--color-text-000)]">{{ t('system.log.log') }}</div>
|
||||
</div>
|
||||
<ms-base-table v-bind="propsRes" no-disable sticky-header v-on="propsEvent">
|
||||
<template #range="{ record }">
|
||||
@ -381,7 +381,7 @@
|
||||
|
||||
function resetFilter() {
|
||||
operUser.value = '';
|
||||
operateRange.value = [MENU_LEVEL[0]];
|
||||
operateRange.value = [props.mode];
|
||||
type.value = '';
|
||||
_module.value = '';
|
||||
content.value = '';
|
||||
|
@ -150,8 +150,9 @@
|
||||
</template>
|
||||
<a-popconfirm
|
||||
v-if="!getIsVisited()"
|
||||
class="ms-pop-confirm"
|
||||
position="br"
|
||||
class="ms-pop-confirm--hidden-cancel"
|
||||
position="bl"
|
||||
popup-container="#typeRadioGroupRef"
|
||||
:ok-text="t('system.resourcePool.batchAddTipConfirm')"
|
||||
@popup-visible-change="handlePopChange"
|
||||
>
|
||||
@ -166,10 +167,12 @@
|
||||
{{ t('system.resourcePool.changeAddTypeTip') }}
|
||||
</div>
|
||||
</template>
|
||||
<a-radio-group v-model:model-value="form.addType" type="button" @change="handleTypeChange">
|
||||
<a-radio value="single">{{ t('system.resourcePool.singleAdd') }}</a-radio>
|
||||
<a-radio value="multiple">{{ t('system.resourcePool.batchAdd') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div id="typeRadioGroupRef" class="relative">
|
||||
<a-radio-group v-model:model-value="form.addType" type="button" @change="handleTypeChange">
|
||||
<a-radio value="single">{{ t('system.resourcePool.singleAdd') }}</a-radio>
|
||||
<a-radio value="multiple">{{ t('system.resourcePool.batchAdd') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</a-popconfirm>
|
||||
<a-radio-group v-else v-model:model-value="form.addType" type="button" @change="handleTypeChange">
|
||||
<a-radio value="single">{{ t('system.resourcePool.singleAdd') }}</a-radio>
|
||||
|
@ -2,7 +2,7 @@ export default {
|
||||
'system.user.createUser': 'Create User',
|
||||
'system.user.emailInvite': 'Email Invite',
|
||||
'system.user.importUser': 'Import User',
|
||||
'system.user.searchUser': 'Search by name or email address',
|
||||
'system.user.searchUser': 'Search by name or email',
|
||||
'system.user.editUser': 'Edit',
|
||||
'system.user.resetPassword': 'Reset PSW',
|
||||
'system.user.disable': 'Disable',
|
||||
@ -53,7 +53,7 @@ export default {
|
||||
'system.user.createUserPhonePlaceholder': 'Please enter an 11-digit mobile number',
|
||||
'system.user.createUserOrganization': 'Organization',
|
||||
'system.user.createUserOrganizationPlaceholder': 'Please select user organization',
|
||||
'system.user.createUserUserGroup': 'UserGroup',
|
||||
'system.user.createUserUserGroup': 'User Group',
|
||||
'system.user.createUserUserGroupPlaceholder': 'Please select a user group',
|
||||
'system.user.editUserModalTitle': 'Edit the user',
|
||||
'system.user.editUserModalCancelCreate': 'Cancel',
|
||||
@ -103,7 +103,7 @@ export default {
|
||||
'system.user.tableColumnName': 'Name',
|
||||
'system.user.tableColumnPhone': 'Phone',
|
||||
'system.user.tableColumnOrg': 'Organization',
|
||||
'system.user.tableColumnUserGroup': 'UserGroup',
|
||||
'system.user.tableColumnUserGroup': 'User Group',
|
||||
'system.user.tableColumnStatus': 'Status',
|
||||
'system.user.tableColumnActions': 'Actions',
|
||||
};
|
||||
|
21
frontend/types/axios.d.ts
vendored
21
frontend/types/axios.d.ts
vendored
@ -1,20 +1,15 @@
|
||||
export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined;
|
||||
|
||||
export interface RequestOptions {
|
||||
// 是否需要处理请求结果
|
||||
isTransformResponse?: boolean;
|
||||
// 是否需要返回原生响应头
|
||||
isReturnNativeResponse?: boolean;
|
||||
isTransformResponse?: boolean; // 是否需要处理请求结果
|
||||
isReturnNativeResponse?: boolean; // 是否需要返回原生响应头
|
||||
handleError?: boolean;
|
||||
// post请求时,是否使用URLSearchParams
|
||||
joinParamsToUrl?: boolean;
|
||||
// Error message prompt type
|
||||
errorMessageMode?: ErrorMessageMode;
|
||||
// Whether to add a timestamp
|
||||
joinTime?: boolean;
|
||||
ignoreCancelToken?: boolean;
|
||||
// Whether to send token in header
|
||||
withToken?: boolean;
|
||||
joinParamsToUrl?: boolean; // post请求时,是否使用URLSearchParams
|
||||
noErrorTip?: boolean;
|
||||
errorMessageMode?: ErrorMessageMode; // 错误信息提示模式,none不提示
|
||||
joinTime?: boolean; // 是否加入时间戳
|
||||
ignoreCancelToken?: boolean; // 是否不记录取消请求的token,不记录则请求不会被取消;默认为记录,在路由切换时会清除上个页面未完成的请求
|
||||
withToken?: boolean; // 是否携带token
|
||||
}
|
||||
|
||||
export interface Result<T = any> {
|
||||
|
Loading…
Reference in New Issue
Block a user