This commit is contained in:
吴红兵
2026-03-07 01:34:48 +08:00
parent adc511cfdc
commit 94c3473958
1211 changed files with 599405 additions and 322105 deletions

View File

@@ -39,12 +39,7 @@
<el-skeleton :rows="3" animated />
</div>
<div class="todo-list" v-else-if="todoList.length > 0">
<div
v-for="item in todoList"
:key="item.id"
class="todo-item"
@click="handleTodoClick(item)"
>
<div v-for="item in todoList" :key="item.id" class="todo-item" @click="handleTodoClick(item)">
<div class="todo-item-left">
<el-tag size="small" type="primary">
{{ item.flowName || '流程' }}
@@ -78,12 +73,7 @@
<el-skeleton :rows="3" animated />
</div>
<div class="notice-list" v-else-if="noticeList.length > 0">
<div
v-for="item in noticeList"
:key="item.id"
class="notice-item"
@click="handleNoticeClick(item)"
>
<div v-for="item in noticeList" :key="item.id" class="notice-item" @click="handleNoticeClick(item)">
<div class="notice-title">{{ item.title }}</div>
<div class="notice-time">{{ formatTime(item.createTime) }}</div>
</div>
@@ -128,166 +118,166 @@
</template>
<script setup lang="ts" name="home">
import { ref, onMounted, onActivated, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { fetchTodoPage } from '/@/api/jsonflow/do-job'
import { fetchList as fetchNoticeList } from '/@/api/jsonflow/ws-notice'
import { fetchUserMessageList, readUserMessage } from '/@/api/admin/message'
import { ref, onMounted, onActivated, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { fetchTodoPage } from '/@/api/jsonflow/do-job';
import { fetchList as fetchNoticeList } from '/@/api/jsonflow/ws-notice';
import { fetchUserMessageList, readUserMessage } from '/@/api/admin/message';
const router = useRouter()
const router = useRouter();
// 用户信息模拟实际应从store获取
const userName = ref('用户')
const userName = ref('用户');
// 时间相关
const currentTime = ref('')
const currentDate = ref('')
const currentWeek = ref('')
let timeTimer: ReturnType<typeof setInterval>
const currentTime = ref('');
const currentDate = ref('');
const currentWeek = ref('');
let timeTimer: ReturnType<typeof setInterval>;
// 待办工作
const todoList = ref<any[]>([])
const todoLoading = ref(true)
const todoList = ref<any[]>([]);
const todoLoading = ref(true);
// 通知公告
const noticeList = ref<any[]>([])
const noticeLoading = ref(true)
const noticeList = ref<any[]>([]);
const noticeLoading = ref(true);
// 站内提醒
const messageList = ref<any[]>([])
const messageLoading = ref(true)
const unreadCount = ref(0)
const messageList = ref<any[]>([]);
const messageLoading = ref(true);
const unreadCount = ref(0);
// 更新时间
const updateTime = () => {
const now = new Date()
currentTime.value = now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
currentDate.value = now.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' })
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
currentWeek.value = weekDays[now.getDay()]
}
const now = new Date();
currentTime.value = now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
currentDate.value = now.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' });
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
currentWeek.value = weekDays[now.getDay()];
};
// 格式化时间
const formatTime = (time: string) => {
if (!time) return ''
const date = new Date(time)
const now = new Date()
const diff = now.getTime() - date.getTime()
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
if (!time) return '';
const date = new Date(time);
const now = new Date();
const diff = now.getTime() - date.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
if (days === 0) {
return '今天'
return '今天';
} else if (days === 1) {
return '昨天'
return '昨天';
} else if (days < 7) {
return `${days}天前`
return `${days}天前`;
} else {
return time.substring(0, 10)
return time.substring(0, 10);
}
}
};
// 加载待办工作
const loadTodoList = async () => {
try {
todoLoading.value = true
const res = await fetchTodoPage({ current: 1, size: 10 })
todoLoading.value = true;
const res = await fetchTodoPage({ current: 1, size: 10 });
if (res.code === 0 && res.data) {
todoList.value = res.data.records || res.data.rows || res.data || []
todoList.value = res.data.records || res.data.rows || res.data || [];
}
} catch (e) {
console.error('加载待办工作失败:', e)
console.error('加载待办工作失败:', e);
} finally {
todoLoading.value = false
todoLoading.value = false;
}
}
};
// 加载通知公告
const loadNoticeList = async () => {
try {
noticeLoading.value = true
const res = await fetchNoticeList({ size: 10 })
noticeLoading.value = true;
const res = await fetchNoticeList({ size: 10 });
if (res.code === 0 && res.data) {
noticeList.value = res.data.rows || res.data || []
noticeList.value = res.data.rows || res.data || [];
}
} catch (e) {
console.error('加载通知公告失败:', e)
console.error('加载通知公告失败:', e);
} finally {
noticeLoading.value = false
noticeLoading.value = false;
}
}
};
// 加载站内提醒
const loadMessageList = async () => {
try {
messageLoading.value = true
const res = await fetchUserMessageList({ size: 10 })
messageLoading.value = true;
const res = await fetchUserMessageList({ size: 10 });
if (res.code === 0 && res.data) {
const list = res.data.rows || res.data || []
messageList.value = list
unreadCount.value = list.filter((item: any) => !item.readFlag).length
const list = res.data.rows || res.data || [];
messageList.value = list;
unreadCount.value = list.filter((item: any) => !item.readFlag).length;
}
} catch (e) {
console.error('加载站内提醒失败:', e)
console.error('加载站内提醒失败:', e);
} finally {
messageLoading.value = false
messageLoading.value = false;
}
}
};
// 点击待办项
const handleTodoClick = (item: any) => {
// 跳转到流程处理页面
router.push({
path: '/jsonflow/run-job/do-job',
query: {
query: {
flowInstId: item.flowInstId,
id: item.id,
runNodeId: item.runNodeId
}
})
}
runNodeId: item.runNodeId,
},
});
};
// 点击通知公告
const handleNoticeClick = (item: any) => {
router.push({
path: '/jsonflow/ws-notice',
query: { id: item.id }
})
}
query: { id: item.id },
});
};
// 点击站内提醒
const handleMessageClick = async (item: any) => {
// 标记已读
if (!item.readFlag) {
try {
await readUserMessage({ id: item.id })
item.readFlag = true
unreadCount.value = Math.max(0, unreadCount.value - 1)
await readUserMessage({ id: item.id });
item.readFlag = true;
unreadCount.value = Math.max(0, unreadCount.value - 1);
} catch (e) {
console.error('标记已读失败:', e)
console.error('标记已读失败:', e);
}
}
}
};
onMounted(() => {
updateTime()
timeTimer = setInterval(updateTime, 1000)
updateTime();
timeTimer = setInterval(updateTime, 1000);
// 加载数据
loadTodoList()
loadNoticeList()
loadMessageList()
})
loadTodoList();
loadNoticeList();
loadMessageList();
});
// 页面激活时刷新待办列表(处理从待办返回的情况)
onActivated(() => {
loadTodoList()
})
loadTodoList();
});
onUnmounted(() => {
if (timeTimer) {
clearInterval(timeTimer)
clearInterval(timeTimer);
}
})
});
</script>
<style scoped lang="scss">
@@ -304,7 +294,7 @@ onUnmounted(() => {
.welcome-card {
background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
border: none;
:deep(.el-card__body) {
padding: 30px;
}
@@ -343,12 +333,12 @@ onUnmounted(() => {
font-weight: 600;
font-family: 'DIN Alternate', monospace;
}
.date-display {
font-size: 16px;
opacity: 0.9;
}
.week-display {
font-size: 14px;
opacity: 0.8;
@@ -398,7 +388,7 @@ onUnmounted(() => {
border-bottom: 1px solid var(--el-border-color-lighter);
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: var(--el-fill-color-light);
padding-left: 8px;
@@ -406,7 +396,7 @@ onUnmounted(() => {
margin-left: -8px;
margin-right: -8px;
}
&:last-child {
border-bottom: none;
}
@@ -460,11 +450,11 @@ onUnmounted(() => {
border-bottom: 1px solid var(--el-border-color-lighter);
cursor: pointer;
transition: all 0.2s;
&:hover {
color: var(--el-color-primary);
}
&:last-child {
border-bottom: none;
}
@@ -491,7 +481,7 @@ onUnmounted(() => {
border-bottom: 1px solid var(--el-border-color-lighter);
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: var(--el-fill-color-light);
padding-left: 8px;
@@ -499,14 +489,14 @@ onUnmounted(() => {
margin-left: -8px;
margin-right: -8px;
}
&.is-unread {
background-color: var(--el-color-primary-light-9);
border-left: 3px solid var(--el-color-primary);
padding-left: 5px;
margin-left: -8px;
}
&:last-child {
border-bottom: none;
}
@@ -546,9 +536,9 @@ onUnmounted(() => {
text-align: center;
gap: 20px;
}
.welcome-right {
text-align: center;
}
}
</style>
</style>

View File

@@ -1,43 +1,43 @@
<template>
<!-- 消息内容 -->
<el-drawer v-model="visible" size="40%">
<div class="flex items-center justify-center -mt-8">
<div class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
<h1 class="text-2xl font-semibold text-center text-gray-500 mb-6">{{ currentNew.title }}</h1>
<div class="text-center">
<p class="text-xs text-gray-600 text-center mt-8">&copy; {{ currentNew.createBy }} {{ currentNew.createTime }}</p>
</div>
<p class="text-sm text-gray-600 text-justify mt-8 mb-6" v-html="currentNew.content"></p>
</div>
</div>
</el-drawer>
<!-- 消息内容 -->
<el-drawer v-model="visible" size="40%">
<div class="flex items-center justify-center -mt-8">
<div class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
<h1 class="text-2xl font-semibold text-center text-gray-500 mb-6">{{ currentNew.title }}</h1>
<div class="text-center">
<p class="text-xs text-gray-600 text-center mt-8">&copy; {{ currentNew.createBy }} {{ currentNew.createTime }}</p>
</div>
<p class="text-sm text-gray-600 text-justify mt-8 mb-6" v-html="currentNew.content"></p>
</div>
</div>
</el-drawer>
</template>
<script setup lang="ts" name="newsLetter">
import {readUserMessage} from "/@/api/admin/message";
import { readUserMessage } from '/@/api/admin/message';
const emit = defineEmits(['refresh']);
const currentNew = ref()
const visible = ref(false)
const currentNew = ref();
const visible = ref(false);
// 打开信息内容
const openDialog = (item: any) => {
visible.value = true
currentNew.value = item;
readMessage(item)
}
visible.value = true;
currentNew.value = item;
readMessage(item);
};
// 阅读事件
const readMessage = async (item: any) => {
if (item.readFlag === '1') {
return
}
await readUserMessage({id: item.id})
emit('refresh')
}
if (item.readFlag === '1') {
return;
}
await readUserMessage({ id: item.id });
emit('refresh');
};
defineExpose({
openDialog
})
openDialog,
});
</script>

View File

@@ -1,53 +1,51 @@
<template>
<el-drawer v-model="visible" size="40%">
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%" @sort-change="sortChangeHandle"
@cell-click="cellClick">
<el-table-column type="index" label="序号" width="60"/>
<el-table-column prop="title" label="标题" show-overflow-tooltip/>
<el-table-column prop="readFlag" label="状态" show-overflow-tooltip>
<template #default="scope">
<el-tag>{{ scope.row.readFlag === '1' ? $t('msg.readed') : $t('msg.unread') }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="时间"/>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination"/>
<el-drawer v-model="visible" size="40%">
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%" @sort-change="sortChangeHandle" @cell-click="cellClick">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="title" label="标题" show-overflow-tooltip />
<el-table-column prop="readFlag" label="状态" show-overflow-tooltip>
<template #default="scope">
<el-tag>{{ scope.row.readFlag === '1' ? $t('msg.readed') : $t('msg.unread') }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="时间" />
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
<!-- 消息内容 -->
<news-content ref="contentRef" @refresh="getDataList"/>
</el-drawer>
<!-- 消息内容 -->
<news-content ref="contentRef" @refresh="getDataList" />
</el-drawer>
</template>
<script setup lang="ts" name="newsList">
import {BasicTableProps, useTable} from '/@/hooks/table';
import {fetchUserMessageList} from '/@/api/admin/message';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchUserMessageList } from '/@/api/admin/message';
const NewsContent = defineAsyncComponent(() => import('./content.vue'));
// 搜索变量
const contentRef = ref()
const contentRef = ref();
const visible = ref(false);
// table hook
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {category: '0'},
pageList: fetchUserMessageList,
queryForm: { category: '0' },
pageList: fetchUserMessageList,
});
const {getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle} = useTable(state);
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle } = useTable(state);
// 打开弹窗
const openDialog = (type: string) => {
state.queryForm.category = type
getDataList();
visible.value = true
state.queryForm.category = type;
getDataList();
visible.value = true;
};
const cellClick = (row: any) => {
contentRef.value.openDialog(row)
}
contentRef.value.openDialog(row);
};
// 暴露变量
defineExpose({
openDialog
openDialog,
});
</script>

View File

@@ -51,10 +51,10 @@
</template>
<script setup lang="ts" name="SysScheduleDialog">
import {useMessage} from '/@/hooks/message';
import {addObj, getObj, putObj} from '/@/api/admin/schedule';
import {useI18n} from 'vue-i18n';
import {useDict} from '/@/hooks/dict';
import { useMessage } from '/@/hooks/message';
import { addObj, getObj, putObj } from '/@/api/admin/schedule';
import { useI18n } from 'vue-i18n';
import { useDict } from '/@/hooks/dict';
const emit = defineEmits(['refresh']);
@@ -73,21 +73,21 @@ const loading = ref(false);
const form = reactive({
id: '',
title: '',
scheduleType: 'record',
scheduleState: '0',
scheduleType: 'record',
scheduleState: '0',
content: '',
scheduleTime: '',
scheduleDate: '',
scheduleTime: '',
scheduleDate: '',
});
// 定义校验规则
const dataRules = ref({
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
scheduleType: [{ required: true, message: '日程类型不能为空', trigger: 'blur' }],
scheduleState: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
scheduleType: [{ required: true, message: '日程类型不能为空', trigger: 'blur' }],
scheduleState: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
content: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
scheduleTime: [{ required: true, message: '时间不能为空', trigger: 'blur' }],
scheduleDate: [{ required: true, message: '日期不能为空', trigger: 'blur' }],
scheduleTime: [{ required: true, message: '时间不能为空', trigger: 'blur' }],
scheduleDate: [{ required: true, message: '日期不能为空', trigger: 'blur' }],
});
/**

View File

@@ -27,10 +27,10 @@ const props = defineProps({
type: String,
default: true,
},
emptyDescription:{
type: String,
default: true,
}
emptyDescription: {
type: String,
default: true,
},
});
/**

View File

@@ -1,99 +1,98 @@
<script lang="ts">
export default {
title: '示例图表1',
icon: 'DocumentCopy',
description: '示例图表无意义,可删除',
title: '示例图表1',
icon: 'DocumentCopy',
description: '示例图表无意义,可删除',
};
</script>
<template>
<el-card class="relative h-full">
<v-chart class="w-full h-80" :option="option"/>
</el-card>
<el-card class="relative h-full">
<v-chart class="w-full h-80" :option="option" />
</el-card>
</template>
<script setup lang="ts" name="demo-chart1">
import VChart from 'vue-echarts';
import {use} from 'echarts/core';
import {PieChart} from 'echarts/charts';
import {TooltipComponent, LegendComponent} from 'echarts/components';
import {CanvasRenderer} from 'echarts/renderers';
import {useTagsViewRoutes} from "/@/stores/tagsViewRoutes";
import {useMessage} from "/@/hooks/message";
import { use } from 'echarts/core';
import { PieChart } from 'echarts/charts';
import { TooltipComponent, LegendComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useMessage } from '/@/hooks/message';
use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer]);
const option = reactive({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)',
},
legend: {
data: ['Java17', 'Java8', 'Other'],
},
series: [
{
name: 'Java',
type: 'pie',
selectedMode: 'single',
radius: [0, '30%'],
label: {
position: 'inner',
fontSize: 14,
},
labelLine: {
show: false,
},
data: [
{value: 1548, name: 'Java17'},
{value: 775, name: 'Java8'},
{value: 679, name: 'Other', selected: true},
],
},
{
name: '使用率',
type: 'pie',
radius: ['45%', '60%'],
labelLine: {
length: 30,
},
label: {
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}}{c} {per|{d}%} ',
backgroundColor: '#F6F8FC',
borderColor: '#8C8D8E',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center',
},
hr: {
borderColor: '#8C8D8E',
width: '100%',
borderWidth: 1,
height: 0,
},
b: {
color: '#4C5058',
fontSize: 14,
fontWeight: 'bold',
lineHeight: 33,
},
per: {
color: '#fff',
backgroundColor: '#4C5058',
padding: [3, 4],
borderRadius: 4,
},
},
},
data: [
{value: 1048, name: 'Java17'},
{value: 335, name: 'Java8'},
{value: 310, name: 'Other'},
],
},
],
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)',
},
legend: {
data: ['Java17', 'Java8', 'Other'],
},
series: [
{
name: 'Java',
type: 'pie',
selectedMode: 'single',
radius: [0, '30%'],
label: {
position: 'inner',
fontSize: 14,
},
labelLine: {
show: false,
},
data: [
{ value: 1548, name: 'Java17' },
{ value: 775, name: 'Java8' },
{ value: 679, name: 'Other', selected: true },
],
},
{
name: '使用率',
type: 'pie',
radius: ['45%', '60%'],
labelLine: {
length: 30,
},
label: {
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}}{c} {per|{d}%} ',
backgroundColor: '#F6F8FC',
borderColor: '#8C8D8E',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center',
},
hr: {
borderColor: '#8C8D8E',
width: '100%',
borderWidth: 1,
height: 0,
},
b: {
color: '#4C5058',
fontSize: 14,
fontWeight: 'bold',
lineHeight: 33,
},
per: {
color: '#fff',
backgroundColor: '#4C5058',
padding: [3, 4],
borderRadius: 4,
},
},
},
data: [
{ value: 1048, name: 'Java17' },
{ value: 335, name: 'Java8' },
{ value: 310, name: 'Other' },
],
},
],
});
</script>

View File

@@ -29,7 +29,7 @@ export default {
</el-card>
<!-- 消息列表 -->
<news-lists ref="listRef"/>
<news-lists ref="listRef" />
<!-- 消息内容 -->
<news-content ref="contentRef" @refresh="getUserMessage" />