554 lines
19 KiB
JavaScript
554 lines
19 KiB
JavaScript
const user = {
|
||
template: /*language=HTML*/ `
|
||
<div class="user-wrapper">
|
||
<!-- 用户容器:左右布局 -->
|
||
<div class="user-container">
|
||
<!-- 左侧:用户信息卡片 -->
|
||
<div class="user-info-card">
|
||
<div class="user-details">
|
||
<div class="user-name">${@auth.getPrincipalProperty('username')}</div>
|
||
|
||
<div class="user-meta-grid">
|
||
<div class="meta-row">
|
||
<span class="meta-icon">🆔</span>
|
||
<div>
|
||
<span class="meta-label">工号</span>
|
||
<span class="meta-value">${@auth.getPrincipalProperty('loginname')}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="meta-row">
|
||
<span class="meta-icon">🏢</span>
|
||
<div>
|
||
<span class="meta-label">单位信息</span>
|
||
<span class="meta-value">
|
||
<!--#if(!isEmpty(@auth.getPrincipalProperty('unit'))){#-->
|
||
${@auth.getPrincipalProperty('unit').getName()}
|
||
<!--#}#-->
|
||
(
|
||
<!--#if(!isEmpty(@auth.getPrincipalProperty('union'))){#-->
|
||
${@auth.getPrincipalProperty('union').getName()}
|
||
<!--#}#-->
|
||
)
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="meta-row">
|
||
<span class="meta-icon">🎭</span>
|
||
<div>
|
||
<span class="meta-label">角色</span>
|
||
<span class="meta-value">{{ roleNames || '—' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 天气区域 -->
|
||
<div v-if="weatherData" class="weather-section" :class="weatherData.bgClass">
|
||
<div style="display: flex; justify-content: space-around">
|
||
<div class="weather-header">
|
||
<span class="weather-location">{{ weatherData.name }}</span>
|
||
<span class="weather-text">{{ weatherData.text }}</span>
|
||
</div>
|
||
<div class="weather-main">
|
||
<span class="weather-emoji">{{ weatherData.emoji }}</span>
|
||
<span class="weather-temp">{{ weatherData.temp }}°</span>
|
||
</div>
|
||
</div>
|
||
<div class="weather-tip">{{ weatherData.tip }}</div>
|
||
</div>
|
||
<div v-else-if="weatherError" class="weather-error">
|
||
🌤️ 天气服务暂时不可用
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:待办中心 -->
|
||
<div class="todo-center">
|
||
<!-- 标题和标签 -->
|
||
<div class="header">
|
||
<h3>待办中心</h3>
|
||
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabClick">
|
||
<el-tab-pane :label="tabLabel('待办事宜', taskStats.todoCount)" name="todo"></el-tab-pane>
|
||
<el-tab-pane :label="tabLabel('已办事宜', taskStats.doneCount)" name="done"></el-tab-pane>
|
||
<el-tab-pane :label="tabLabel('我的发起', taskStats.startedCount)" name="started"></el-tab-pane>
|
||
<el-tab-pane :label="tabLabel('办结事务', taskStats.completedCount)" name="completed"></el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
|
||
<!-- 表格 -->
|
||
<el-table
|
||
:data="todoList"
|
||
style="width: 100%"
|
||
border
|
||
stripe
|
||
v-loading="loading"
|
||
:cell-style="{ padding: '8px' }"
|
||
:header-cell-style="{ background: '#f8f9fa', color: '#444', fontWeight: '500' }"
|
||
>
|
||
<el-table-column label="序号" type="index" :index="indexMethod" width="100px"></el-table-column>
|
||
<el-table-column prop="categoryName" label="流程分类" width="100"></el-table-column>
|
||
<el-table-column prop="title" label="流程名称" min-width="300">
|
||
<template slot-scope="scope">
|
||
<el-tooltip effect="dark" :content="scope.row.instanceName" placement="top">
|
||
<span class="table-title">{{ scope.row.instanceName }}</span>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="sender" label="申请人" width="120">
|
||
<template slot-scope="{row}">{{row.variable.initiatorName}}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="taskName" label="当前流程节点" width="140" show-overflow-tooltip></el-table-column>
|
||
<el-table-column prop="date" label="发起日期" width="120">
|
||
<template slot-scope="{row}">
|
||
{{$moment(row.createdAt).format('YYYY-MM-DD')}}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="100px" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button type="primary" size="mini" @click="openView(scope.row)">查看</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<!--#include("/layouts/pagination.html"){}#-->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`,
|
||
mixins: [initTableMixins],
|
||
data() {
|
||
return {
|
||
activeTab: 'todo',
|
||
todoList: [],
|
||
loading: false,
|
||
pageForm: {
|
||
pageNum: 1,
|
||
pageSize: 5,
|
||
totalCount: 0
|
||
},
|
||
taskStats: {
|
||
todoCount: 0,
|
||
doneCount: 0,
|
||
startedCount: 0,
|
||
completedCount: 0
|
||
},
|
||
// 🔆 天气相关数据
|
||
weatherData: null,
|
||
weatherError: false,
|
||
// 🔑 和风天气 API Key(请替换为你自己的)
|
||
QWEATHER_KEY: 'f916578cbb0e4b55b778b0de5847ecf5', // ←← 务必替换!
|
||
roleNames: ""
|
||
|
||
};
|
||
},
|
||
methods: {
|
||
getWeatherInfo(iconCode, temp) {
|
||
const info = {
|
||
emoji: '🌤️',
|
||
tip: '今日天气宜人,心情也该放晴啦!',
|
||
bgClass: 'weather-sunny' // 用于 CSS 类
|
||
};
|
||
|
||
const tempNum = parseFloat(temp);
|
||
const isCold = tempNum < 10;
|
||
const isHot = tempNum > 28;
|
||
|
||
// 按照和风天气 iconCode 分类
|
||
if (['100'].includes(iconCode)) {
|
||
info.emoji = '☀️';
|
||
info.tip = isHot ? '高温预警!注意防暑降温,多喝水~' : '阳光灿烂,适合外出走走!';
|
||
info.bgClass = 'weather-sunny';
|
||
} else if (['101', '102', '103', '104'].includes(iconCode)) {
|
||
info.emoji = ['101', '103'].includes(iconCode) ? '⛅' : '☁️';
|
||
info.tip = isCold ? '天凉加衣,别让感冒找上门!' : '云层温柔,适合静心工作。';
|
||
info.bgClass = 'weather-cloudy';
|
||
} else if (['300', '301', '302', '305', '306', '399'].some(code => code === iconCode)) {
|
||
info.emoji = '🌧️';
|
||
info.tip = '🌧️ 下雨啦!记得带伞,小心路滑~';
|
||
info.bgClass = 'weather-rainy';
|
||
} else if (['307', '308', '309', '310'].includes(iconCode)) {
|
||
info.emoji = '⛈️';
|
||
info.tip = '⛈️ 雷雨天气,请减少外出,注意安全!';
|
||
info.bgClass = 'weather-storm';
|
||
} else if (['400', '401', '402', '403'].includes(iconCode)) {
|
||
info.emoji = '❄️';
|
||
info.tip = '❄️ 天寒地冻,保暖最重要!';
|
||
info.bgClass = 'weather-snowy';
|
||
} else if (['404', '405', '406', '407', '408', '409', '410'].includes(iconCode)) {
|
||
info.emoji = '🌫️';
|
||
info.tip = '🌫️ 能见度较低,出行请注意安全。';
|
||
info.bgClass = 'weather-foggy';
|
||
} else if (['500', '501', '502', '504'].includes(iconCode)) {
|
||
info.emoji = '🌀';
|
||
info.tip = '🌀 极端天气预警!请关注官方通知。';
|
||
info.bgClass = 'weather-extreme';
|
||
} else {
|
||
info.emoji = '🌤️';
|
||
info.tip = '今日天气未知,但愿你心情晴朗!';
|
||
info.bgClass = 'weather-default';
|
||
}
|
||
|
||
return info;
|
||
},
|
||
async getConfigKey(key) {
|
||
const resp = await this.$axios.post("/open/common/getConfigKey", { key })
|
||
return resp.data
|
||
},
|
||
// 🔆 获取天气
|
||
async fetchWeather() {
|
||
try {
|
||
// 存localStorage 112.13,32.01 广州 113.27,23.14
|
||
const AppMapCenterPointX = await this.getConfigKey("AppMapCenterPointX")
|
||
const AppMapCenterPointY = await this.getConfigKey("AppMapCenterPointY")
|
||
if (!AppMapCenterPointX || !AppMapCenterPointY){
|
||
return
|
||
}
|
||
|
||
// 1. 先通过城市名获取 locationId
|
||
this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/geo/v2/city/lookup?location=" + AppMapCenterPointX + "," + AppMapCenterPointY + "&key=" + this.QWEATHER_KEY).then((geoRes) => {
|
||
if (geoRes.code !== '200' || !geoRes.location?.[0]) {
|
||
console.log('城市未找到')
|
||
}
|
||
const locationId = geoRes.location[0].id;
|
||
|
||
// 2. 获取当前天气
|
||
this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/v7/weather/now?location=" + locationId + "&key=" + this.QWEATHER_KEY).then((weatherRes) => {
|
||
if (weatherRes.code !== '200') {
|
||
console.warn('天气数据异常:', weatherRes);
|
||
}
|
||
const weatherInfo = this.getWeatherInfo(weatherRes.now.icon, weatherRes.now.temp);
|
||
this.weatherData = {
|
||
...weatherInfo,
|
||
temp: weatherRes.now.temp,
|
||
text: weatherRes.now.text,
|
||
name: geoRes.location[0].name
|
||
};
|
||
this.weatherError = false;
|
||
})
|
||
|
||
|
||
})
|
||
|
||
} catch (err) {
|
||
console.warn('天气加载失败:', err);
|
||
this.weatherError = true;
|
||
this.weatherData = null;
|
||
}
|
||
},
|
||
// 获取任务列表
|
||
tabLabel(title, count) {
|
||
return title + "(" + (count || 0) + ")"
|
||
},
|
||
async getStatistics() {
|
||
try {
|
||
const res = await $.post("/flow/todoCenter/statistics")
|
||
if (res.code === 0) {
|
||
this.taskStats = Object.assign({}, this.taskStats, res.data)
|
||
}
|
||
} catch (error) {
|
||
console.error("获取待办统计失败:", error)
|
||
}
|
||
},
|
||
async getTasks() {
|
||
this.loading = true
|
||
try {
|
||
const res = await $.post("/flow/todoCenter/" + this.activeTab, this.pageForm)
|
||
if (res.code === 0) {
|
||
this.todoList = res.data.list
|
||
this.pageForm.totalCount = res.data.totalCount
|
||
}
|
||
} catch (error) {
|
||
this.$message.error("获取任务列表失败")
|
||
console.error("获取任务列表失败:", error)
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
pageData() {
|
||
this.getTasks()
|
||
this.getStatistics()
|
||
},
|
||
handleTabClick(tab) {
|
||
this.pageData()
|
||
console.log('切换到:', tab.name);
|
||
},
|
||
// 处理任务
|
||
async openView(task) {
|
||
console.log(task)
|
||
const {taskId, taskKey, taskState, instanceId, businessNo, formKey} = task
|
||
if (!formKey) {
|
||
this.$message.warning("当前流程没有配置地址")
|
||
return
|
||
}
|
||
window.open(formKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
||
},
|
||
getRoleNames() {
|
||
$.post("/platform/sys/role/getRoleNames").then(res => {
|
||
if (res.code === 0) {
|
||
this.roleNames = res.data.roleNames
|
||
}
|
||
})
|
||
|
||
}
|
||
},
|
||
created() {
|
||
this.pageData()
|
||
this.getRoleNames()
|
||
},
|
||
mounted() {
|
||
this.fetchWeather()
|
||
},
|
||
style: /*language=CSS*/ `
|
||
.user-wrapper {
|
||
width: 100%;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.user-container {
|
||
width: 80%;
|
||
margin: 12px auto 20px;
|
||
display: grid;
|
||
grid-template-columns: 0.7fr 2.3fr;
|
||
gap: 24px;
|
||
align-items: stretch;
|
||
row-gap: 24px;
|
||
}
|
||
|
||
.user-info-card {
|
||
background: white;
|
||
border-radius: 16px;
|
||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);
|
||
padding: 24px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
||
}
|
||
|
||
.user-info-card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
/* 头像占位符 */
|
||
.user-avatar-placeholder {
|
||
width: 64px;
|
||
height: 64px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #409eff, #1877f2);
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
margin: 0 auto;
|
||
box-shadow: 0 4px 10px rgba(24, 127, 255, 0.3);
|
||
}
|
||
|
||
/* 用户名 */
|
||
.user-name {
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
text-align: center;
|
||
margin: 8px 0 0;
|
||
}
|
||
|
||
/* 元信息网格 */
|
||
.user-meta-grid {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.meta-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 12px;
|
||
}
|
||
|
||
.meta-icon {
|
||
font-size: 18px;
|
||
min-width: 24px;
|
||
text-align: center;
|
||
color: #409eff;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.meta-row > div {
|
||
flex: 1;
|
||
}
|
||
|
||
.meta-label {
|
||
font-size: 12px;
|
||
color: #6b7280;
|
||
font-weight: 500;
|
||
display: block;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.meta-value {
|
||
font-size: 15px;
|
||
color: #1f2937;
|
||
font-weight: 600;
|
||
word-break: break-word;
|
||
}
|
||
|
||
/* === 天气卡片 - 情感化设计 === */
|
||
.weather-section {
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
text-align: center;
|
||
color: white;
|
||
background: linear-gradient(135deg, #a8edea, #fed6e3); /* 默认柔和渐变 */
|
||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
/* 不同天气的背景主题 */
|
||
.weather-sunny {
|
||
background: linear-gradient(135deg, #FFD700, #FFA500);
|
||
color: #2c3e50;
|
||
}
|
||
.weather-cloudy {
|
||
background: linear-gradient(135deg, #B0C4DE, #708090);
|
||
color: white;
|
||
}
|
||
.weather-rainy {
|
||
background: linear-gradient(135deg, #4A6FA5, #1E3F66);
|
||
color: white;
|
||
}
|
||
.weather-storm {
|
||
background: linear-gradient(135deg, #2F2F2F, #0D0D0D);
|
||
color: #FFD700;
|
||
}
|
||
.weather-snowy {
|
||
background: linear-gradient(135deg, #E0F7FA, #B3E5FC);
|
||
color: #01579B;
|
||
}
|
||
.weather-foggy {
|
||
background: linear-gradient(135deg, #D7CCC8, #A1887F);
|
||
color: white;
|
||
}
|
||
.weather-extreme {
|
||
background: linear-gradient(135deg, #FF5252, #B71C1C);
|
||
color: white;
|
||
}
|
||
.weather-default {
|
||
background: linear-gradient(135deg, #E0E0E0, #90A4AE);
|
||
color: #333;
|
||
}
|
||
|
||
/* 天气头部:城市 + 描述 */
|
||
.weather-header {
|
||
margin-bottom: 12px;
|
||
}
|
||
.weather-location {
|
||
font-weight: 700;
|
||
font-size: 16px;
|
||
display: block;
|
||
}
|
||
.weather-text {
|
||
font-size: 13px;
|
||
opacity: 0.9;
|
||
display: block;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* 主体:图标 + 温度 */
|
||
.weather-main {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 8px;
|
||
position: relative;
|
||
bottom: 8px;
|
||
}
|
||
.weather-emoji {
|
||
font-size: 36px;
|
||
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
|
||
}
|
||
.weather-temp {
|
||
font-size: 28px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
/* 贴心提示语 */
|
||
.weather-tip {
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
opacity: 0.95;
|
||
margin-top: 8px;
|
||
padding: 0 8px;
|
||
}
|
||
|
||
/* 错误状态 */
|
||
.weather-error {
|
||
text-align: center;
|
||
color: #94a3b8;
|
||
font-size: 14px;
|
||
padding: 16px;
|
||
background: #f8fafc;
|
||
border-radius: 12px;
|
||
border: 1px dashed #cbd5e1;
|
||
}
|
||
|
||
/* 右侧待办中心 */
|
||
.todo-center {
|
||
min-width: 320px;
|
||
background: white;
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||
padding: 16px;
|
||
transition: transform 0.2s, box-shadow 0.2s;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.header h3 {
|
||
font-size: 18px;
|
||
color: #333;
|
||
margin: 0;
|
||
border-left: 4px solid #1890ff;
|
||
padding-left: 10px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.el-tabs {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.table-title {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 280px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.pagination {
|
||
margin-top: 20px;
|
||
text-align: right;
|
||
}
|
||
|
||
/* 响应式:小屏下堆叠 */
|
||
@media (max-width: 768px) {
|
||
.user-container {
|
||
flex-direction: column;
|
||
width: 95%;
|
||
}
|
||
|
||
.user-info-card, .todo-center {
|
||
min-width: 100%;
|
||
width: 100%;
|
||
}
|
||
}
|
||
`
|
||
};
|