From 2c726bfdb6fd802e5a8d220854ec3e900fb287fb Mon Sep 17 00:00:00 2001 From: wwl <xchao828@163.com> Date: 星期五, 20 六月 2025 17:42:13 +0800 Subject: [PATCH] 消息通知 --- src/views/index.vue | 540 ++++++++++++++-------------- src/api/system/user.js | 9 src/views/system/notice/index.vue | 535 ++++++++++++++++++++------- src/api/system/notice.js | 7 4 files changed, 668 insertions(+), 423 deletions(-) diff --git a/src/api/system/notice.js b/src/api/system/notice.js index c274ea5..4aea2e6 100644 --- a/src/api/system/notice.js +++ b/src/api/system/notice.js @@ -8,7 +8,12 @@ params: query }) } - +export function noticeToday() { + return request({ + url: '/system/notice/noticeToday', + method: 'get', + }) +} // 鏌ヨ鍏憡璇︾粏 export function getNotice(noticeId) { return request({ diff --git a/src/api/system/user.js b/src/api/system/user.js index 6a38491..9022ba4 100644 --- a/src/api/system/user.js +++ b/src/api/system/user.js @@ -11,7 +11,14 @@ params: query }) } - +// 鏌ヨ鐢ㄦ埛鍒楄〃 +export function listUser1(query) { + return request({ + url: '/system/user/userListByDeptId', + method: 'get', + params: query + }) +} export function getlistUser() { return request({ url: '/system/user/getList', diff --git a/src/views/index.vue b/src/views/index.vue index d925659..1ea2590 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -1,6 +1,30 @@ <template> <div class="centre"> - <div style="display:flex;justify-content: center;align-items: center;"> + <!-- 浠婃棩閫氱煡 --> + <div style="display: flex; justify-content: center; align-items: center;"> + <h4>浠婃棩閫氱煡</h4> + </div> + <div class="notice-area"> + <el-carousel :interval="2000" direction="vertical" :autoplay="true" :loop="true" height="120px" + v-if="groupedNoticeList.length > 0" class="carousel"> + <el-carousel-item v-for="(group, index) in groupedNoticeList" :key="index"> + <div class="notice-group"> + <div class="notice-item" v-for="notice in group" :key="notice.noticeId" + @click="goToNotice(notice.noticeId)"> + <el-tag size="small" :type="notice.noticeType === '1' ? 'info' : 'warning'"> + {{ notice.noticeType === '1' ? '閫氱煡' : '鍏憡' }} + </el-tag> + <span class="notice-title">{{ notice.noticeTitle || '鏃犳爣棰�' }}</span> + <span class="notice-time">{{ parseTime(notice.createTime, '{y}-{m}-{d}') || '鏃犳椂闂�' }}</span> + </div> + </div> + </el-carousel-item> + </el-carousel> + <div v-else class="no-notice">鏆傛棤閫氱煡</div> + </div> + + <!-- 浠婃棩缁熻 --> + <div style="display: flex; justify-content: center; align-items: center;"> <h4>浠婃棩缁熻</h4> </div> <div class="top"> @@ -37,11 +61,13 @@ </div> </div> </div> - <div style="display:flex;justify-content: center;align-items: center;"> + + <!-- 杩戜竴鏈堢粺璁� --> + <div style="display: flex; justify-content: center; align-items: center;"> <h4>杩戜竴鏈堢粺璁�</h4> </div> <div class="data-view"> - <div id="main"></div> + <div id="main" style="width: 95%; height: 330px"></div> </div> <div class="view"> <div id="main2"></div> @@ -52,11 +78,13 @@ <script> import { getCustomer, getOrder, getReportToday, getTobeToday, getPieChart, getChart } from "@/api/home"; +import { noticeToday } from "@/api/system/notice"; const echarts = require('echarts/lib/echarts'); require('echarts/lib/component/title'); require('echarts/lib/component/tooltip'); require('echarts/lib/component/legend'); require('echarts/lib/chart/pie'); +require('echarts/lib/chart/line'); export default { data() { @@ -73,323 +101,304 @@ teamYYNum: [], PieChart: [], PieChart2: [], - } + noticeList: [], + groupedNoticeList: [], // 鍒嗙粍鍚庣殑閫氱煡鍒楄〃 + loading: false + }; }, created() { this.getList(); - }, + watch: { - $route(to, from) { - window.location.reload(); //鐩戞祴鍒拌矾鐢卞彂鐢熻烦杞椂鍒锋柊涓�娆¢〉闈� - // this.$router.go(0); - }, + $route(to, from) { + window.location.reload(); }, - + noticeList: { + handler(newList) { + // 灏嗛�氱煡鎸夋瘡缁勪笁鏉″垎缁� + this.groupedNoticeList = this.chunkArray(newList, 3); + console.log('groupedNoticeList:', this.groupedNoticeList); // 璋冭瘯 + }, + deep: true + } + }, methods: { - + goToNotice(noticeId) { + this.$router.push({ + path: '/notice', + query: { noticeId } + }); + }, getList() { this.loading = true; - - // 淇敼API璋冪敤鐨勯敊璇鐞� - getCustomer().then((response) => { - this.Customer = response || 0; // 娣诲姞榛樿鍊� + + // 鏌ヨ鎵�鏈夊叕鍛� + noticeToday().then(response => { + console.log('Notice API response:', response); + this.noticeList = response.rows || response.data || []; + console.log('noticeList:', this.noticeList); + this.loading = false; + this.$nextTick(() => { + console.log('Carousel updated'); + }); }).catch(error => { - console.error('鑾峰彇浠婃棩鐧昏鏁版嵁澶辫触:', error); - this.Customer = 0; + console.error('Notice API error:', error); + this.$message.error("鑾峰彇閫氱煡澶辫触锛�" + error.message); + this.loading = false; }); - getOrder().then((response) => { - this.Order = response || 0; - }).catch(error => { - console.error('鑾峰彇浠婃棩宸叉鏁版嵁澶辫触:', error); - this.Order = 0; + // 鏌ヨ浠婃棩鐧昏 + getCustomer().then(response => { + this.Customer = response.data || response; + this.loading = false; }); - getReportToday().then((response) => { - this.ReportToday = response || 0; - }).catch(error => { - console.error('鑾峰彇浠婃棩鎶ュ憡鏁版嵁澶辫触:', error); - this.ReportToday = 0; + // 鏌ヨ浠婃棩宸叉 + getOrder().then(response => { + this.Order = response.data || response; + this.loading = false; }); - getTobeToday().then((response) => { - this.TobeToday = response || 0; - }).catch(error => { - console.error('鑾峰彇浠婃棩寰呮鏁版嵁澶辫触:', error); - this.TobeToday = 0; + // 鏌ヨ浠婃棩鎶ュ憡 + getReportToday().then(response => { + this.ReportToday = response.data || response; + this.loading = false; }); - // 淇敼鎶樼嚎鍥炬暟鎹鐞� - getChart().then((response) => { - if (response && response.data) { - this.LineChart = []; - this.reportNum = []; - this.personYYNum = []; - this.teamYYNum = []; - - response.data.forEach(item => { - this.LineChart.push(item.date); - this.reportNum.push(item.tdcoun || 0); - this.personYYNum.push(item.grcoun || 0); - this.teamYYNum.push(item.bgcoun || 0); - }); - let myChart = this.$echarts.init(document.getElementById('main')); + // 鏌ヨ浠婃棩寰呮 + getTobeToday().then(response => { + this.TobeToday = response.data || response; + this.loading = false; + }); - myChart.setOption({ - tooltip: { - trigger: 'axis' - }, - legend: { - data: ['姣忔棩浣撴鐧昏鏁�', '姣忔棩鍥綋鐧昏鏁�', '姣忔棩鍙戝竷鎶ュ憡鏁�'] - }, - grid: { - left: '3%', - right: '4%', - bottom: '3%', - containLabel: true - }, - toolbox: { - feature: { - saveAsImage: {} - } - }, - xAxis: { - type: 'category', - boundaryGap: false, - axisLine: { - show: true, - lineStyle: { - color: "blue", - size: 12, - width: 0, - tyle: "solid" - } - }, - data: this.LineChart - }, - yAxis: { - type: 'value', - min: 0, - max: 100, - interval: 5 - }, - series: [ - { - name: '姣忔棩浣撴鐧昏鏁�', - type: 'line', - stack: 'Total', - data: this.personYYNum - }, - { - name: '姣忔棩鍥綋鐧昏鏁�', - type: 'line', - stack: 'Total', - data: this.reportNum - }, - { - name: '姣忔棩鍙戝竷鎶ュ憡鏁�', - type: 'line', - stack: 'Total', - data: this.teamYYNum - }, - ] + // 鎶樼嚎鍥� + getChart().then(response => { + response.data.forEach(item => { + this.LineChart.push(item.date); + this.reportNum.push(item.tdcoun); + this.personYYNum.push(item.grcoun); + this.teamYYNum.push(item.bgcoun); + }); - }) - let sizeFun = ()=> { - myChart.resize() - } - window.addEventListener("resize", sizeFun) + let myChart = this.$echarts.init(document.getElementById('main')); + myChart.setOption({ + tooltip: { trigger: 'axis' }, + legend: { data: ['姣忔棩浣撴鐧昏鏁�', '姣忔棩鍥綋鐧昏鏁�', '姣忔棩鍙戝竷鎶ュ憡鏁�'] }, + grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + toolbox: { feature: { saveAsImage: {} } }, + xAxis: { + type: 'category', + boundaryGap: false, + axisLine: { + show: true, + lineStyle: { width: 0, color: 'blue', type: 'solid' } + }, + data: this.LineChart + }, + yAxis: { type: 'value', min: 0, max: 400, interval: 20 }, + series: [ + { name: '姣忔棩浣撴鐧昏鏁�', type: 'line', stack: 'Total', data: this.personYYNum }, + { name: '姣忔棩鍥綋鐧昏鏁�', type: 'line', stack: 'Total', data: this.reportNum }, + { name: '姣忔棩鍙戝竷鎶ュ憡鏁�', type: 'line', stack: 'Total', data: this.teamYYNum } + ] + }); - this.loading = false; - } - }).catch(error => { - console.error('鑾峰彇鍥捐〃鏁版嵁澶辫触:', error); + const sizeFun = () => myChart.resize(); + window.addEventListener('resize', sizeFun); + this.loading = false; }); // 楗肩姸鍥� - getPieChart().then((response) => { + getPieChart().then(response => { if (response.data) { - - if(response.data.tjdj == 0){ - this.PieChart = [] - this.PieChart = [ - { - "name": "浣撴鐧昏浜烘暟鍒嗗竷", - "count": 1, - "value": 10 - }, - - ] - }else if (response.data.tjdj.length === 0) { - - this.PieChart = [] - this.PieChart = [ - { - "name": "浣撴鐧昏浜烘暟鍒嗗竷", - "count": 1, - "value": 10 - }, - - ] + if (response.data.tjdj == 0 || !response.data.tjdj?.length) { + this.PieChart = [{ name: '浣撴鐧昏浜烘暟鍒嗗竷', count: 1, value: 10 }]; } else { - this.PieChart = response.data.tjdj - this.PieChart.forEach(item => { - item.value = item.count - }) - this.PieChart.reverse() - this.PieChart.push(this.PieChart[0]) - this.PieChart.splice(0, 1) - + this.PieChart = response.data.tjdj; + this.PieChart.forEach(item => { item.value = item.count; }); + this.PieChart.reverse(); + this.PieChart.push(this.PieChart[0]); + this.PieChart.splice(0, 1); } let myChart2 = this.$echarts.init(document.getElementById('main2')); myChart2.setOption({ - title: { - text: '浣撴鐧昏浜烘暟鍒嗗竷', - top: '5' + title: { text: '浣撴鐧昏浜烘暟鍒嗗竷', top: '5' }, + tooltip: { trigger: 'item' }, + legend: { top: '80%', left: 'center' }, + series: [{ + type: 'pie', + radius: ['16%', '54%'], + center: ['50%', '43%'], + avoidLabelOverlap: false, + startAngle: 180, + minAngle: 10, + data: this.PieChart, + emphasis: { + itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } + } + }] + }); - }, - - tooltip: { - trigger: 'item' - }, - legend: { - top: '80%', - left: 'center' - }, - series: [ - { - // name: 'Access From', - type: 'pie', - radius: ['16%', '54%'], - center: ["50%", "43%"], - avoidLabelOveralap:false, - startAngle:180, - minAngle:10, - data: this.PieChart, - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - } - } - }] - }) - - if(response.data.tjyc == 0){ - this.PieChart2 = [] - this.PieChart2 = [ - { - "name": "浣撴缁撴灉寮傚父浜烘暟鍒嗗竷", - "count": 1, - "value": 0 - }, - - ] - }else if (response.data.tjyc.length === 0) { - this.PieChart2 = [] - this.PieChart2 = [ - { - "name": "浣撴缁撴灉寮傚父浜烘暟鍒嗗竷", - "count": 1, - "value": 0 - }, - - ] + if (response.data.tjyc == 0 || !response.data.tjyc?.length) { + this.PieChart2 = [{ name: '浣撴缁撴灉寮傚父浜烘暟鍒嗗竷', count: 1, value: 0 }]; } else { - this.PieChart2 = response.data.tjyc - this.PieChart2.reverse() - this.PieChart2.push(this.PieChart2[0]) - this.PieChart2.splice(0, 1) - this.PieChart2.forEach(item => { - item.value = item.count - }) - // this.TobeToday = response + this.PieChart2 = response.data.tjyc; + this.PieChart2.reverse(); + this.PieChart2.push(this.PieChart2[0]); + this.PieChart2.splice(0, 1); + this.PieChart2.forEach(item => { item.value = item.count; }); } + let myChart3 = this.$echarts.init(document.getElementById('main3')); - myChart3.setOption({ - title: { - text: '浣撴缁撴灉寮傚父浜烘暟鍒嗗竷', - top: '5' + title: { text: '浣撴缁撴灉寮傚父浜烘暟鍒嗗竷', top: '5' }, + tooltip: { trigger: 'item' }, + legend: { top: '80%', left: 'center' }, + series: [{ + type: 'pie', + radius: ['16%', '54%'], + center: ['50%', '43%'], + avoidLabelOverlap: false, + startAngle: 180, + minAngle: 10, + data: this.PieChart2, + emphasis: { + itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } + } + }] + }); - }, - tooltip: { - trigger: 'item' - }, - legend: { - top: '80%', - left: 'center' - }, - series: [ - { - // name: 'Access From', - type: 'pie', - radius: ['16%', '54%'], - center: ["50%", "43%"], - avoidLabelOveralap:false, - startAngle:180, - minAngle:10, - data: this.PieChart2, - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - } - } - }] - }) - window.onresize = () =>{ - myChart2.resize() - myChart3.resize() + window.onresize = () => { + myChart2.resize(); + myChart3.resize(); + }; } - } - - - this.loading = false; }); + }, + // 鏁扮粍鍒嗙粍鏂规硶 + chunkArray(array, size) { + if (!array || array.length === 0) return []; + const result = []; + for (let i = 0; i < array.length; i += size) { + result.push(array.slice(i, i + size)); + } + // 纭繚寰幆婊氬姩骞虫粦锛岃嫢涓嶈冻 size 鏉★紝琛ラ綈 + if (array.length % size !== 0 && array.length > size) { + const lastGroup = result[result.length - 1]; + while (lastGroup.length < size) { + lastGroup.push(array[lastGroup.length % array.length]); + } + } + return result; + }, + + parseTime(time, cFormat) { + if (!time) return ''; + try { + const date = new Date(time); + if (isNaN(date.getTime())) return ''; + const formatObj = { + y: date.getFullYear(), + m: String(date.getMonth() + 1).padStart(2, '0'), + d: String(date.getDate()).padStart(2, '0'), + h: String(date.getHours()).padStart(2, '0'), + i: String(date.getMinutes()).padStart(2, '0'), + s: String(date.getSeconds()).padStart(2, '0') + }; + return cFormat.replace(/{([ymdhis]+)}/g, (result, key) => formatObj[key] || ''); + } catch (error) { + console.error('parseTime error:', error, 'time:', time); + return ''; + } } - }, - - - mounted() { - } -} - - +}; </script> <style> .centre { min-height: 820px; - margin: 15px 15px; + margin: 15px; background-color: #f3f3f3; - padding: 10px 10px 10px 10px; + padding: 10px; +} + +.notice-area { + width: 100%; + min-height: 120px; + /* 璋冩暣涓轰笁鏉¢�氱煡楂樺害 */ + background-color: #fff; + margin: 10px 0; + padding: 0 20px; +} + +.carousel { + width: 100% !important; +} + +.notice-group { + display: flex; + flex-direction: column; + height: 120px; + /* 纭繚鍖呭惈涓夋潯閫氱煡 */ +} + +.notice-item { + display: flex; + align-items: center; + width: 100%; + height: 40px; + line-height: 40px; + font-size: 14px; + cursor: pointer; +} + +.notice-title { + margin-left: 10px; + font-size: 14px; + color: #333; + flex-grow: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.notice-time { + font-size: 12px; + color: #999; + margin-left: 20px; +} + +.no-notice { + width: 100%; + height: 120px; + /* 涓庤疆鎾珮搴︿竴鑷� */ + line-height: 120px; + text-align: center; + color: #999; + font-size: 14px; } .top { width: 100%; display: flex; height: 120px; - } .add { - width: 380px; + width: 320px; height: 75px; - margin-top: 30px; + margin-top: 20px; margin-left: 20px; margin-right: 20px; background-color: #fff; - display: flex + display: flex; } .img { @@ -403,7 +412,6 @@ .image { width: 60px; height: 60px; - } .txt { @@ -414,34 +422,26 @@ .day { height: 40px; line-height: 40px; - font-size: 14px; + font-size: 12px; } .data-view { margin: 0 15px; - height: 323px !important + height: 323px !important; } #main { padding: 10px; - width:95%; - height:330px } .view { - margin: 0px 15px; + margin: 0 15px; padding-top: 15px; min-height: 350px; display: flex; } -#main2 { - width: 820px; - height: 350px; - background-color: #fff; - margin-right: 20px; -} - +#main2, #main3 { width: 820px; height: 350px; diff --git a/src/views/system/notice/index.vue b/src/views/system/notice/index.vue index 71d6425..a338adf 100644 --- a/src/views/system/notice/index.vue +++ b/src/views/system/notice/index.vue @@ -2,29 +2,15 @@ <div class="app-container"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form-item label="鍏憡鏍囬" prop="noticeTitle"> - <el-input - v-model="queryParams.noticeTitle" - placeholder="璇疯緭鍏ュ叕鍛婃爣棰�" - clearable - @keyup.enter.native="handleQuery" - /> + <el-input v-model="queryParams.noticeTitle" placeholder="璇疯緭鍏ュ叕鍛婃爣棰�" clearable @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item label="鎿嶄綔浜哄憳" prop="createBy"> - <el-input - v-model="queryParams.createBy" - placeholder="璇疯緭鍏ユ搷浣滀汉鍛�" - clearable - @keyup.enter.native="handleQuery" - /> + <el-input v-model="queryParams.createBy" placeholder="璇疯緭鍏ユ搷浣滀汉鍛�" clearable @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item label="绫诲瀷" prop="noticeType"> <el-select v-model="queryParams.noticeType" placeholder="鍏憡绫诲瀷" clearable> - <el-option - v-for="dict in dict.type.sys_notice_type" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> + <el-option v-for="dict in dict.type.sys_notice_type" :key="dict.value" :label="dict.label" + :value="dict.value" /> </el-select> </el-form-item> <el-form-item> @@ -35,51 +21,48 @@ <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> - <el-button type="primary" - icon="el-icon-plus" - size="mini" - @click="handleAdd" - v-hasPermi="['system:notice:add']" - >鏂板</el-button> + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" + v-hasPermi="['system:notice:add']">鏂板</el-button> </el-col> <el-col :span="1.5"> - <el-button type="primary" - icon="el-icon-edit" - size="mini" - :disabled="single" - @click="handleUpdate" - v-hasPermi="['system:notice:edit']" - >淇敼</el-button> + <el-button type="primary" icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" + v-hasPermi="['system:notice:edit']">淇敼</el-button> </el-col> <el-col :span="1.5"> - <el-button type="primary" - icon="el-icon-delete" - size="mini" - :disabled="multiple" - @click="handleDelete" - v-hasPermi="['system:notice:remove']" - >鍒犻櫎</el-button> + <el-button type="primary" icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" + v-hasPermi="['system:notice:remove']">鍒犻櫎</el-button> </el-col> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> </el-row> - <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange"> + <el-table + v-loading="loading" + :data="noticeList" + @selection-change="handleSelectionChange" + :row-class-name="tableRowClassName" + ref="table" + > <el-table-column type="selection" width="55" align="center" /> <el-table-column label="搴忓彿" align="center" prop="noticeId" width="100" /> - <el-table-column - label="鍏憡鏍囬" - align="center" - prop="noticeTitle" - :show-overflow-tooltip="true" - /> + <el-table-column label="鍏憡鏍囬" align="center" prop="noticeTitle" :show-overflow-tooltip="true" /> <el-table-column label="鍏憡绫诲瀷" align="center" prop="noticeType" width="100"> <template slot-scope="scope"> - <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/> + <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType" /> </template> </el-table-column> <el-table-column label="鐘舵��" align="center" prop="status" width="100"> <template slot-scope="scope"> - <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/> + <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status" /> + </template> + </el-table-column> + <el-table-column label="鎺ユ敹绉戝" align="center" prop="deptId" width="150"> + <template slot-scope="scope"> + <span>{{ getDeptNames(scope.row.deptId) }}</span> + </template> + </el-table-column> + <el-table-column label="鎺ユ敹鐢ㄦ埛" align="center" prop="userIds" width="200" :show-overflow-tooltip="true"> + <template slot-scope="scope"> + <span>{{ getUserNames(scope.row.userIds) }}</span> </template> </el-table-column> <el-table-column label="鍒涘缓鑰�" align="center" prop="createBy" width="100" /> @@ -90,37 +73,20 @@ </el-table-column> <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> <template slot-scope="scope"> - <el-button - size="mini" - type="text" - icon="el-icon-edit" - @click="handleUpdate(scope.row)" - v-hasPermi="['system:notice:edit']" - >淇敼</el-button> - <el-button - size="mini" - type="text" - icon="el-icon-delete" - @click="handleDelete(scope.row)" - v-hasPermi="['system:notice:remove']" - >鍒犻櫎</el-button> - <el-button - size="mini" - type="text" - icon="el-icon-share" - @click="handledetails(scope.row)" - v-hasPermi="['system:notice:remove']" - >璇︽儏</el-button> + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" + v-hasPermi="['system:notice:edit']">淇敼</el-button> + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" + v-hasPermi="['system:notice:remove']">鍒犻櫎</el-button> + <el-button size="mini" type="text" icon="el-icon-share" @click="handledetails(scope.row)" + v-hasPermi="['system:notice:query']">璇︽儏</el-button> </template> </el-table-column> </el-table> - <div class="pag"> - <div class="pag1"> - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" - :limit.sync="queryParams.pageSize" @pagination="getList" /> - </div> - </div> + <div class="pagination-container"> + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" @pagination="getList" /> + </div> <!-- 娣诲姞鎴栦慨鏀瑰叕鍛婂璇濇 --> <el-dialog :title="title" :visible.sync="open" width="780px" append-to-body> @@ -134,34 +100,37 @@ <el-col :span="12"> <el-form-item label="鍏憡绫诲瀷" prop="noticeType"> <el-select v-model="form.noticeType" placeholder="璇烽�夋嫨鍏憡绫诲瀷"> - <el-option - v-for="dict in dict.type.sys_notice_type" - :key="dict.value" - :label="dict.label" - :value="dict.value" - ></el-option> + <el-option v-for="dict in dict.type.sys_notice_type" :key="dict.value" :label="dict.label" + :value="dict.value"></el-option> </el-select> </el-form-item> </el-col> - <el-col :span="12" v-if="form.noticeType == 1"> - <el-form-item label="閫氱煡浜哄憳" prop="noticeType"> - <el-input v-model="form.noticeTitle" placeholder="璇疯緭鍏ラ�氱煡浜哄憳" /> + <el-col :span="12"> + <el-form-item label="鎺ユ敹绉戝" prop="deptId"> + <el-select v-model="form.deptId" filterable placeholder="璇烽�夋嫨鎺ユ敹绉戝" @change="handleDeptChange"> + <el-option v-for="dept in deptList" :key="dept.id" :label="dept.label" :value="dept.id"></el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鎺ユ敹鐢ㄦ埛" prop="userIds"> + <el-select v-model="form.userIds" multiple filterable placeholder="璇烽�夋嫨鎺ユ敹鐢ㄦ埛"> + <el-option v-for="user in editUserList" :key="user.userId" :label="user.nickName || user.userName" + :value="user.userId"></el-option> + </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="鐘舵��"> <el-radio-group v-model="form.status"> - <el-radio - v-for="dict in dict.type.sys_notice_status" - :key="dict.value" - :label="dict.value" - >{{dict.label}}</el-radio> + <el-radio v-for="dict in dict.type.sys_notice_status" :key="dict.value" + :label="dict.value">{{ dict.label }}</el-radio> </el-radio-group> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="鍐呭"> - <editor v-model="form.noticeContent" :min-height="192"/> + <editor v-model="form.noticeContent" :min-height="192" /> </el-form-item> </el-col> </el-row> @@ -172,46 +141,44 @@ </div> </el-dialog> - <!--閫氱煡鍏憡璇︽儏 --> + <!-- 閫氱煡鍏憡璇︽儏 --> <el-dialog :title="formIn.noticeTitle" :visible.sync="openDetail" width="800px" append-to-body> - <div style="margin-top:-20px;margin-bottom:10px;"> - <el-tag size="mini" effect="dark" type="warning" v-if="form.noticeType==2">鍏憡</el-tag> + <div class="detail-header"> + <el-tag size="mini" effect="dark" type="warning" v-if="formIn.noticeType === '2'">鍏憡</el-tag> <el-tag size="mini" effect="dark" v-else>閫氱煡</el-tag> - <span style="margin-left:20px;">{{formIn.createTime}}</span> + <span class="time">{{ parseTime(formIn.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '鏃�' }}</span> </div> - <div class="content"> - <div v-html="formIn.noticeContent" style="margin-left:0px;margin-right:76px" class="ql-editor"></div> + <div class="detail-item"> + <span class="label">鎺ユ敹绉戝锛�</span> + <span>{{ getDeptNames(formIn.deptId) }}</span> + </div> + <div class="detail-item"> + <span class="label">鎺ユ敹鐢ㄦ埛锛�</span> + <span>{{ getUserNames(formIn.userIds) }}</span> + </div> + <div class="detail-content"> + <div v-html="formIn.noticeContent" class="ql-editor"></div> </div> <div slot="footer" class="dialog-footer"> - <el-button type="primary" @click="cancel"> 鍏� 闂� </el-button> + <el-button type="primary" @click="cancel">鍏抽棴</el-button> </div> </el-dialog> - </div> </template> <script> import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"; +import { deptTreeSelect } from "@/api/system/dept"; +import { listUser1 } from "@/api/system/user"; export default { name: "Notice", - dicts: ['sys_notice_status', 'sys_notice_type'], + dicts: ["sys_notice_status", "sys_notice_type"], data() { - let checkPhoneNum = (rule, value, callback) => { - console.log( value) - let patter = new RegExp(/^1\s*[3456789]\s*(\d\s*){9}$/); - if (value == "" && value == undefined && !value) { - return callback(''); - } else if(value != undefined && value != ""){ - return callback(); - }else if (!patter.test(value)) { - return callback(''); - } - }; return { // 閬僵灞� loading: true, - openDetail:false, + openDetail: false, // 閫変腑鏁扮粍 ids: [], // 闈炲崟涓鐢� @@ -224,49 +191,190 @@ total: 0, // 鍏憡琛ㄦ牸鏁版嵁 noticeList: [], + // 绉戝鍒楄〃 + deptList: [], + // 鐢ㄦ埛鍒楄〃锛堝叏灞�锛岀敤浜庤〃鏍煎拰璇︽儏锛� + userList: [], + // 鐢ㄦ埛鍒楄〃锛堢敤浜庣紪杈戝璇濇锛� + editUserList: [], // 寮瑰嚭灞傛爣棰� title: "", // 鏄惁鏄剧ず寮瑰嚭灞� open: false, + // 鏄惁涓哄垵娆″姞杞� + isInitialLoad: true, // 鏌ヨ鍙傛暟 queryParams: { pageNum: 1, pageSize: 10, noticeTitle: undefined, createBy: undefined, - status: undefined + noticeType: undefined, }, - formIn:{}, + formIn: {}, // 琛ㄥ崟鍙傛暟 - form: {}, + form: { + noticeId: undefined, + noticeTitle: undefined, + noticeType: undefined, + noticeContent: undefined, + status: "0", + deptId: undefined, + userIds: [], + }, // 琛ㄥ崟鏍¢獙 rules: { - noticeTitle: [ - { required: true, validator: checkPhoneNum, trigger: "blur" } + noticeTitle: [{ required: true, message: "鍏憡鏍囬涓嶈兘涓虹┖", trigger: "blur" }], + noticeType: [{ required: true, message: "鍏憡绫诲瀷涓嶈兘涓虹┖", trigger: "change" }], + deptId: [ + { + required: false, + message: "璇烽�夋嫨鎺ユ敹绉戝", + trigger: "change", + validator: (rule, value, callback) => { + callback(); // 闈炲繀濉� + }, + }, ], - noticeType: [ - { required: true, validator: checkPhoneNum, trigger: "change" } - ] - } + userIds: [ + { + required: false, + message: "璇烽�夋嫨鎺ユ敹鐢ㄦ埛", + trigger: "change", + validator: (rule, value, callback) => { + callback(); // 闈炲繀濉� + }, + }, + ], + }, }; }, created() { this.getList(); + // 鑾峰彇绉戝鍒楄〃 + deptTreeSelect() + .then((response) => { + this.deptList = response.data || []; + this.deptList = this.flattenDeptList(this.deptList); + console.log("Flattened deptList:", this.deptList); + }) + .catch((error) => { + this.$modal.msgError("鑾峰彇绉戝鍒楄〃澶辫触锛�" + error.message); + }); + // 棰勫姞杞芥墍鏈夌敤鎴峰垪琛紙鐢ㄤ簬琛ㄦ牸鍜岃鎯咃級 + listUser1({}) + .then((response) => { + this.userList = (response.rows || response.data || []).map(user => ({ + ...user, + userId: String(user.userId), + })); + this.editUserList = [...this.userList]; // 鍒濆鍖栫紪杈戠敤鎴峰垪琛� + console.log("Preloaded userList:", this.userList); + }) + .catch((error) => { + this.$modal.msgError("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触锛�" + error.message); + }); + // 澶勭悊璺宠浆鍙傛暟 + this.handleRouteParams(); }, methods: { /** 鏌ヨ鍏憡鍒楄〃 */ getList() { this.loading = true; - listNotice(this.queryParams).then(response => { + listNotice(this.queryParams).then((response) => { this.noticeList = response.rows; this.total = response.total; this.loading = false; + // 楂樹寒鎴栨墦寮�璇︽儏锛堜粎鍒濇鍔犺浇鏃惰Е鍙戣鎯咃級 + this.$nextTick(() => { + this.highlightNotice(this.isInitialLoad); + this.isInitialLoad = false; // 鏍囪涓洪潪鍒濇鍔犺浇 + }); + }).catch((error) => { + console.error("listNotice error:", error); + this.$modal.msgError("鑾峰彇鍏憡鍒楄〃澶辫触锛�" + error.message); + this.loading = false; }); + }, + /** 澶勭悊璺敱鍙傛暟 */ + handleRouteParams() { + const { noticeId } = this.$route.query; + if (noticeId) { + this.queryParams.noticeId = noticeId; + this.getList(); + } + }, + /** 楂樹寒鎴栨墦寮�鍏憡璇︽儏 */ + highlightNotice(isInitialLoad) { + const { noticeId } = this.$route.query; + if (noticeId) { + const notice = this.noticeList.find(item => item.noticeId === noticeId); + if (notice) { + this.$refs.table.setCurrentRow(notice); + if (isInitialLoad) { + this.handledetails(notice); // 浠呭垵娆″姞杞芥椂鎵撳紑璇︽儏 + } + } + } + }, + /** 琛ㄦ牸琛岀被鍚� */ + tableRowClassName({ row }) { + const { noticeId } = this.$route.query; + return noticeId && row.noticeId === noticeId ? 'highlight-row' : ''; + }, + /** 灏嗙瀹D杞崲涓虹瀹ゅ悕绉� */ + getDeptNames(deptId) { + if (!deptId) return "鏃�"; + const dept = this.deptList.find((dept) => dept.id === deptId); + return dept ? dept.label : "鏈煡绉戝"; + }, + /** 灏嗙敤鎴稩D杞崲涓虹敤鎴峰悕 */ + getUserNames(userIds) { + if (!userIds) return "鏃�"; + const ids = typeof userIds === "string" ? userIds.split(",") : userIds; + const names = this.userList + .filter((user) => ids.includes(user.userId)) + .map((user) => user.nickName || user.userName) + .join(", "); + return names || ids.join(", "); + }, + /** 灞曞钩閮ㄩ棬鏍戝舰缁撴瀯 */ + flattenDeptList(depts, result = []) { + depts.forEach((dept) => { + result.push({ id: String(dept.id), label: dept.label }); + if (dept.children && dept.children.length) { + this.flattenDeptList(dept.children, result); + } + }); + return result; + }, + /** 绉戝閫夋嫨鍙樺寲鏃惰皟鐢� */ + handleDeptChange(deptId) { + if (deptId) { + this.editUserList = []; + return listUser1({ deptId }) + .then((response) => { + this.editUserList = (response.rows || response.data || []).map(user => ({ + ...user, + userId: String(user.userId), + })); + console.log("Fetched editUserList for deptId", deptId, ":", this.editUserList); + }) + .catch((error) => { + this.$modal.msgError("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触锛�" + error.message); + this.editUserList = [...this.userList]; // 鍥為��鍒板叏灞�鐢ㄦ埛鍒楄〃 + }); + } else { + console.log("No deptId, retained form.userIds:", this.form.userIds); + this.editUserList = [...this.userList]; // 鎭㈠涓哄叏灞�鐢ㄦ埛鍒楄〃 + return Promise.resolve(); + } }, // 鍙栨秷鎸夐挳 cancel() { + console.log("Cancel triggered, resetting form and closing dialogs"); this.open = false; - this.openDetail = false, + this.openDetail = false; this.reset(); }, // 琛ㄥ崟閲嶇疆 @@ -276,8 +384,11 @@ noticeTitle: undefined, noticeType: undefined, noticeContent: undefined, - status: "0" + status: "0", + deptId: undefined, + userIds: [], }; + this.editUserList = [...this.userList]; // 閲嶇疆涓哄叏灞�鐢ㄦ埛鍒楄〃 this.resetForm("form"); }, /** 鎼滅储鎸夐挳鎿嶄綔 */ @@ -292,46 +403,90 @@ }, // 澶氶�夋閫変腑鏁版嵁 handleSelectionChange(selection) { - this.ids = selection.map(item => item.noticeId) - this.single = selection.length!=1 - this.multiple = !selection.length + this.ids = selection.map((item) => item.noticeId); + this.single = selection.length !== 1; + this.multiple = !selection.length; }, /** 鏂板鎸夐挳鎿嶄綔 */ handleAdd() { + console.log("handleAdd triggered"); this.reset(); this.open = true; this.title = "娣诲姞鍏憡"; }, /** 淇敼鎸夐挳鎿嶄綔 */ handleUpdate(row) { + console.log("handleUpdate triggered for noticeId:", row.noticeId); this.reset(); - const noticeId = row.noticeId || this.ids - getNotice(noticeId).then(response => { - this.form = response.data; - this.open = true; - this.title = "淇敼鍏憡"; - }); + const noticeId = row.noticeId || this.ids; + getNotice(noticeId) + .then((response) => { + console.log("getNotice response:", response.data); + const data = response.data; + this.form = { + noticeId: data.noticeId, + noticeTitle: data.noticeTitle, + noticeType: data.noticeType, + noticeContent: data.noticeContent, + status: data.status, + deptId: data.deptId ? String(data.deptId) : undefined, + userIds: data.userIds ? (typeof data.userIds === 'string' ? data.userIds.split(',') : data.userIds) : [], + }; + if (this.form.deptId) { + return this.handleDeptChange(this.form.deptId).then(() => { + this.open = true; + this.title = "淇敼鍏憡"; + console.log("Modification dialog opened, form:", this.form, "editUserList:", this.editUserList); + }); + } else { + this.editUserList = [...this.userList]; + console.log("No deptId, retained form.userIds:", this.form.userIds, "editUserList:", this.editUserList); + this.open = true; + this.title = "淇敼鍏憡"; + console.log("Modification dialog opened, form:", this.form); + return Promise.resolve(); + } + }) + .catch((error) => { + console.error("getNotice error:", error); + this.$modal.msgError("鑾峰彇鍏憡璇︽儏澶辫触锛�" + error.message); + }); }, - - handledetails(row){ + /** 璇︽儏鎸夐挳鎿嶄綔 */ + handledetails(row) { + console.log("handledetails triggered for noticeId:", row.noticeId); this.formIn = row; this.openDetail = true; + console.log("Detail dialog opened, formIn:", this.formIn); }, /** 鎻愪氦鎸夐挳 */ - submitForm: function() { - this.$refs["form"].validate(valid => { + submitForm() { + console.log("submitForm triggered, form:", this.form); + this.$refs["form"].validate((valid) => { if (valid) { - if (this.form.noticeId != undefined) { - updateNotice(this.form).then(response => { + const formData = { + ...this.form, + deptId: this.form.deptId ? String(this.form.deptId) : "", + userIds: this.form.userIds || [], + }; + console.log("Submitting formData:", formData); + if (formData.noticeId != undefined) { + updateNotice(formData).then((response) => { this.$modal.msgSuccess("淇敼鎴愬姛"); this.open = false; this.getList(); + }).catch((error) => { + console.error("updateNotice error:", error); + this.$modal.msgError("淇敼澶辫触锛�" + error.message); }); } else { - addNotice(this.form).then(response => { + addNotice(formData).then((response) => { this.$modal.msgSuccess("鏂板鎴愬姛"); this.open = false; this.getList(); + }).catch((error) => { + console.error("addNotice error:", error); + this.$modal.msgError("鏂板澶辫触锛�" + error.message); }); } } @@ -339,24 +494,102 @@ }, /** 鍒犻櫎鎸夐挳鎿嶄綔 */ handleDelete(row) { - const noticeIds = row.noticeId || this.ids - this.$modal.confirm('鏄惁纭鍒犻櫎鍏憡缂栧彿涓�"' + noticeIds + '"鐨勬暟鎹」锛�').then(function() { - return delNotice(noticeIds); - }).then(() => { - this.getList(); - this.$modal.msgSuccess("鍒犻櫎鎴愬姛"); - }).catch(() => {}); + console.log("handleDelete triggered for noticeId:", row.noticeId); + const noticeIds = row.noticeId || this.ids; + this.$modal + .confirm('鏄惁纭鍒犻櫎鍏憡缂栧彿涓�"' + noticeIds + '"鐨勬暟鎹」锛�') + .then(() => delNotice(noticeIds)) + .then(() => { + this.getList(); + this.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + }) + .catch(() => {}); + }, + /** 鏃堕棿鏍煎紡鍖� */ + parseTime(time, cFormat = '{y}-{m}-{d} {h}:{i}:{s}') { + if (!time) return ''; + try { + const date = new Date(time); + if (isNaN(date.getTime())) return ''; + const formatObj = { + y: date.getFullYear(), + m: String(date.getMonth() + 1).padStart(2, '0'), + d: String(date.getDate()).padStart(2, '0'), + h: String(date.getHours()).padStart(2, '0'), + i: String(date.getMinutes()).padStart(2, '0'), + s: String(date.getSeconds()).padStart(2, '0') + }; + return cFormat.replace(/{([ymdhis]+)}/g, (result, key) => formatObj[key] || ''); + } catch (error) { + console.error('parseTime error:', error, 'time:', time); + return ''; + } } - } + }, }; </script> + <style scoped> -.pag { - width: 100%; +/* 瀹瑰櫒鏍峰紡锛岀‘淇濆唴瀹规湁閫傚綋鍐呰竟璺� */ +.app-container { + padding: 20px; +} + +/* 鍒嗛〉瀹瑰櫒锛屾浛鎹㈠師 .pag 鍜� .pag1锛屽眳涓樉绀� */ +.pagination-container { display: flex; justify-content: center; + margin-top: 20px; } -.pag1{ - width: 30%; + +/* 楂樹寒琛屾牱寮忥紝绐佸嚭鏄剧ず璺敱鎸囧畾鐨勫叕鍛� */ +.highlight-row { + background-color: #e6f7ff; } -</style> + +/* 瀵硅瘽妗嗗簳閮ㄦ寜閽眳涓� */ +.dialog-footer { + text-align: center; + padding: 10px 0; +} + +/* 璇︽儏瀵硅瘽妗嗗ご閮紙绫诲瀷鏍囩鍜屾椂闂达級 */ +.detail-header { + margin: -20px 0 10px; + display: flex; + align-items: center; +} + +.detail-header .time { + margin-left: 20px; + color: #606266; +} + +/* 璇︽儏瀵硅瘽妗嗕俊鎭」锛堟帴鏀剁瀹ゃ�佹帴鏀剁敤鎴凤級 */ +.detail-item { + margin-bottom: 10px; +} + +.detail-item .label { + font-weight: bold; + color: #303133; +} + +/* 璇︽儏瀵硅瘽妗嗗唴瀹瑰尯鍩燂紝闄愬埗瀵屾枃鏈珮搴� */ +.detail-content .ql-editor { + max-height: 300px; + overflow-y: auto; + padding: 10px; + color: #303133; +} + +/* 琛ㄦ牸鎿嶄綔鍒楋紝浼樺寲鎸夐挳闂磋窛 */ +.small-padding { + padding: 0 10px; +} + +/* 鎼滅储琛ㄥ崟椤堕儴闂磋窛 */ +.mb8 { + margin-bottom: 8px; +} +</style> \ No newline at end of file -- Gitblit v1.8.0