Files
SPDM/src/views/system/application/index.vue
2026-03-27 17:39:30 +08:00

482 lines
12 KiB
Vue

<template>
<appConfigPage v-if="isAppInfo" :app-info="currentAppInfo" @back-up="backUpFun"></appConfigPage>
<div class="gl-page-content-full" v-else>
<BaseTable
tableName="APP_CENTER"
ref="baseTableRef"
:api="setTableDataFun"
:params="tableParams"
fullHeight
:actionList="actionList"
>
<template #leftOptions>
<div>
<el-button type="primary" @click="editAppInfoFun">新增应用 </el-button>
<el-button type="" @click="showAppUseFun">应用统计 </el-button>
</div>
</template>
<template #appName="{ row }">
<div class="app-center-cell-content">
<img
v-if="row.appImage"
:src="getImgPathFun(row.appImage)"
width="28"
class="mr10"
alt=""
/>
<div v-else class="no-img mr5">
<appNameBg :app-name="row.appName" :size="14"></appNameBg>
</div>
<span class="app-name" :title="row.appName" @click="setAppConfigInfoFun(row)">{{
row.appName
}}</span>
<!-- <el-button link type="primary" @click="setAppConfigInfoFun(row)">{{ row.appName }}</el-button> -->
</div>
</template>
<template #appType="{ row }">
<div class="app-center-cell-content flex-center">
<el-tag v-if="row.appType === '3'" type="primary">{{
getTypeNameFun(row.appType)
}}</el-tag>
<el-tag v-else-if="row.appType === '2'" type="success">{{
getTypeNameFun(row.appType)
}}</el-tag>
<el-tag v-else-if="row.appType === '1'" type="warning">{{
getTypeNameFun(row.appType)
}}</el-tag>
<el-tag v-else type="primary">{{ getTypeNameFun(row.appType) }}</el-tag>
</div>
</template>
<template #appStatus="{ row }">
<div class="app-center-cell-content flex-center">
<div :class="row.appStatus === '1' ? 'point success mr5' : 'point error mr5'"></div>
<span>{{ row.appStatus === '1' ? '启用' : '禁用' }}</span>
</div>
</template>
<template #appPath="{ row }">
<div class="app-center-cell-content flex-center">
<span class="ellipsis" :title="row.appPath">{{ row.appPath }}</span>
</div>
</template>
<template #operate="{ row }">
<div class="app-center-cell-content flex-center">
<el-button type="primary" link @click="editAppInfoFun(row)">编辑</el-button>
<el-button type="primary" link @click="disabledAppFun(row)">{{
row.appStatus === '1' ? '禁用' : '启用'
}}</el-button>
<el-button type="danger" link @click="deleteAppFun(row)">删除</el-button>
</div>
</template>
</BaseTable>
<addOrEditApp
v-if="detailVisible"
:table-name="'APP_CENTER'"
:current-app-info="currentAppInfo"
@cancel="closeAddOrEditAppFun"
@submit="updateAppInfoFun"
></addOrEditApp>
<appUseChart v-if="showAppChart" @close="showAppChart = false"></appUseChart>
</div>
</template>
<script lang="ts" setup>
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import { ElMessage } from 'element-plus';
import addOrEditApp from '../application/components/addOrEditApp.vue';
import { execApi, getdeviceuuidApi, startupPlugin } from '@/api/application/application';
import appConfigPage from './components/appConfigPage.vue';
import {
addApplicationApi,
queryAllApplicationApi,
updateApplicationApi,
deleteApplicationApi,
addApplicationCallRecordApi,
} from '@/api/system/application';
import appNameBg from './components/appNameBg.vue';
import { getDictionaryDataApi } from '@/api/system/systemData';
import { getUserData, getUserId } from '@/utils/user';
import appUseChart from './components/appUseChart.vue';
import { cloneDeep } from 'lodash-es';
const env = import.meta.env;
const baseTableRef = ref();
const detailVisible = ref(false);
const isAppInfo = ref(false);
const showAppChart = ref(false);
const appSearchName = ref('');
const tableParams = ref({
appName: appSearchName.value,
});
const actionList = ref([
{
title: '启动',
type: 'primary',
click: (row: any) => {
startAppFun(row);
},
},
{
title: '编辑',
type: 'primary',
click: (row: any) => {
editAppInfoFun(row);
},
},
{
title: '启用',
type: 'primary',
hide: (row: any) => {
return row.appStatus === '1';
},
click: (row: any) => {
disabledAppFun(row);
},
},
{
title: '禁用',
type: 'danger',
hide: (row: any) => {
return row.appStatus != '1';
},
click: (row: any) => {
disabledAppFun(row);
},
},
{
title: '删除',
type: 'danger',
needConfirm: true,
confirmTip: '确认删除吗?',
click: (row: any) => {
deleteAppFun(row);
},
},
]);
const setTableDataFun = async (data: any) => {
const param = {
...data,
};
const res: any = await queryAllApplicationApi(param);
if (res && res.code === 200) {
for (let i = 0; i < res?.data?.data?.length; i++) {
res.data.data[i].appStatus = res?.data?.data[i].appStatus.toString();
res.data.data[i].appType = res?.data?.data[i].appType.toString();
res.data.data[i].userAppPath = cloneDeep(res.data.data[i].appPath);
const paths = isJSONFun(res.data.data[i].appPath)
? JSON.parse(res.data.data[i].appPath as string)
: res.data.data[i].appPath;
if (paths && paths instanceof Object) {
const keys = Object.keys(paths);
if (keys.includes(getUserId())) {
res.data.data[i].appPath = paths[getUserId()];
} else {
res.data.data[i].appPath = '';
}
}
}
}
return res;
};
const isJSONFun = (str: any) => {
try {
JSON.parse(str);
return true;
} catch {
return false;
}
};
const currentAppInfo = ref<any>({});
// 打开编辑应用弹窗
const editAppInfoFun = (row?: any) => {
// const uuid = localStorage.getItem('USER_UUID');
// if (uuid) {
if (row) {
currentAppInfo.value = cloneDeep(row);
} else {
currentAppInfo.value = {};
}
detailVisible.value = true;
};
const closeAddOrEditAppFun = () => {
currentAppInfo.value = {};
detailVisible.value = false;
};
// 禁用应用
const disabledAppFun = async (row: any) => {
ElMessage.success(row.appStatus === '1' ? '应用已禁用' : '应用已启用');
// row.status = !row.status;
if (row.appStatus === '1') {
row.appStatus = '0';
} else {
row.appStatus = '1';
}
const res: any = await updateApplicationApi({
appName: row.appName,
appType: Number(row.appType),
appPath: row.appPath,
appImage: row.appImage.toString(),
appStatus: Number(row.appStatus),
appVersion: row.appVersion,
appVendor: row.appVendor,
machineCode: row.machineCode,
comment: row.comment,
uuid: row.uuid,
creator: row.creator,
});
if (res && res.code === 200) {
}
nextTick(() => {
baseTableRef.value.resetFun();
});
};
// 删除应用
const deleteAppFun = async (row: any) => {
const res: any = await deleteApplicationApi({
appId: row.uuid,
});
if (res && res.code === 200) {
ElMessage.success('删除成功!');
nextTick(() => {
baseTableRef.value.resetFun();
});
}
};
const updateAppInfoFun = async (data: any) => {
const uuid =
data.appType === 1 || data.appType === '1' ? localStorage.getItem('USER_UUID') : '--';
detailVisible.value = false;
if (uuid) {
if (data?.id) {
let paths: any = {};
if (isJSONFun(currentAppInfo.value.userAppPath)) {
paths = JSON.parse(currentAppInfo.value.userAppPath);
}
paths[getUserId()] = data.appPath || '';
const res: any = await updateApplicationApi({
appName: data.appName,
appType: Number(data.appType),
appPath: JSON.stringify(paths) || '',
appImage: data.appImage.toString(),
appStatus: Number(data.appStatus),
appVersion: data.appVersion,
appVendor: data.appVendor,
machineCode: data.machineCode,
comment: data.comment,
uuid: data.uuid,
// creator: 'vu0151d',
});
if (res && res.code === 200) {
}
} else {
const path = JSON.stringify({
[getUserId()]: data.appPath,
});
const param = {
appName: data.appName,
appType: Number(data.appType),
appStatus: Number(data.appStatus),
appPath: path || '',
appImage: data?.appImage ? data.appImage.toString() : '',
appVersion: data.appVersion || '',
appVendor: data.appVendor || '',
machineCode: localStorage.getItem('USER_UUID'),
comment: data.comment || '',
creator: getUserId() || '',
creatorName: getUserData()?.nickname || '',
};
const res: any = await addApplicationApi(param);
if (res && res.code === 200) {
}
}
nextTick(() => {
baseTableRef.value.resetFun();
});
} else {
getdeviceuuidFun();
}
};
const getImgPathFun = (fileId: any) => {
const url = `${env.VITE_API_IMAGE_PREVIEW_URL}/data/previewImage?fileId=${fileId}`;
return url;
};
const getdeviceuuidFun = async () => {
try {
const res: any = await getdeviceuuidApi();
if (res && res.code === 200) {
const uuid = res.data.returnCode
.replace('UUID', '')
.replace(/\ +/g, '')
.replace(/[\r\n]/g, '');
localStorage.setItem('USER_UUID', uuid);
}
} catch {
startupPlugin();
}
};
const setAppConfigInfoFun = (row: any) => {
currentAppInfo.value = row;
isAppInfo.value = true;
};
const backUpFun = () => {
isAppInfo.value = false;
nextTick(() => {
baseTableRef.value.resetFun();
});
};
const timer: any = ref(null);
const startAppFun = async (data: any) => {
await getdeviceuuidFun();
const uuid = localStorage.getItem('USER_UUID');
if (uuid) {
const res: any = await execApi({
path: data.appPath,
param: '',
});
if (res && res.code === 200) {
ElMessage.success('应用正在启动中,请等待');
const res2: any = await addApplicationCallRecordApi({
appName: data.appName,
appType: data.appType,
creator: data.creator,
});
if (res2 && res2.code === 200) {
}
} else {
}
} else {
return;
}
};
const appTypeList = ref<any>([]);
const getDictionaryDataFun = async () => {
const res: any = await getDictionaryDataApi({
dictClass: 'APP_TYPE',
});
if (res && res.code === 200) {
appTypeList.value = res.data;
}
};
const getTypeNameFun = (type: any) => {
const str =
appTypeList.value.find((item: any) => {
return item.dictValue === type;
})?.dictName || '';
return str;
};
const showAppUseFun = () => {
showAppChart.value = true;
};
onMounted(async () => {
await getDictionaryDataFun();
});
onBeforeUnmount(() => {
clearTimeout(timer.value);
});
</script>
<style lang="scss" scoped>
.app-center-cell-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
.app-name {
width: 100px;
text-align: left;
cursor: pointer;
color: #409eff;
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出的内容 */
text-overflow: ellipsis;
}
.ellipsis {
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出的内容 */
text-overflow: ellipsis;
}
.no-img {
width: 28px;
height: 28px;
border-radius: 5px;
overflow: hidden;
}
.mr5 {
margin-right: 5px;
}
.mr10 {
margin-right: 10px;
}
.point {
width: 8px;
height: 8px;
border-radius: 50%;
}
.success {
background-color: #67c23a;
}
.error {
background-color: #f56c6c;
}
}
.flex-center {
// justify-content: center;
align-items: center;
}
.search-form {
.el-form-item {
margin-bottom: 0 !important;
}
}
</style>