Commit ec9ec2ce02ede050215aa67d58ddbd7df3075025

Authored by wuxw
1 parent 70492aa4

开发完成物业公告问题

src/api/oa/addNoticeViewApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 保存公告信息
  5 +export function saveNotice(data) {
  6 + return new Promise((resolve, reject) => {
  7 + // 确保communityId存在
  8 + if (!data.communityId) {
  9 + data.communityId = getCommunityId()
  10 + }
  11 +
  12 + request({
  13 + url: '/notice.saveNotice',
  14 + method: 'post',
  15 + data
  16 + }).then(response => {
  17 + resolve(response.data)
  18 + }).catch(error => {
  19 + reject(error)
  20 + })
  21 + })
  22 +}
  23 +
  24 +// 上传图片
  25 +export function uploadImage(file) {
  26 + const formData = new FormData()
  27 + formData.append('uploadFile', file)
  28 + formData.append('communityId', getCommunityId())
  29 +
  30 + return new Promise((resolve, reject) => {
  31 + request({
  32 + url: '/uploadImage',
  33 + method: 'post',
  34 + data: formData,
  35 + headers: {
  36 + 'Content-Type': 'multipart/form-data'
  37 + }
  38 + }).then(response => {
  39 + resolve(response.data)
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
0 \ No newline at end of file 45 \ No newline at end of file
src/api/oa/editNoticeViewApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取公告详情
  5 +export function getNoticeDetail(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/notice.listNotices',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 更新公告
  24 +export function updateNotice(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/notice.updateNotice',
  28 + method: 'post',
  29 + data: {
  30 + ...data,
  31 + communityId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 上传图片
  43 +export function uploadNoticeImage(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: 'uploadImage',
  47 + method: 'post',
  48 + headers: {
  49 + 'Content-Type': 'multipart/form-data'
  50 + },
  51 + data: {
  52 + ...data,
  53 + communityId: getCommunityId()
  54 + }
  55 + }).then(response => {
  56 + const res = response.data
  57 + resolve(res)
  58 + }).catch(error => {
  59 + reject(error)
  60 + })
  61 + })
  62 +}
0 \ No newline at end of file 63 \ No newline at end of file
src/api/oa/noticeDetailApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * 获取公告详情
  5 + * @param {Object} params 查询参数
  6 + * @returns {Promise}
  7 + */
  8 +export function getNoticeDetail(params) {
  9 + return new Promise((resolve, reject) => {
  10 + request({
  11 + url: '/notice.listNotices',
  12 + method: 'get',
  13 + params
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
src/api/oa/noticeManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * 获取公告列表
  5 + * @param {Object} params 查询参数
  6 + * @returns {Promise}
  7 + */
  8 +export function listNotices(params) {
  9 + return new Promise((resolve, reject) => {
  10 + request({
  11 + url: '/notice.listNotices',
  12 + method: 'get',
  13 + params
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +/**
  24 + * 删除公告
  25 + * @param {Object} data 删除参数
  26 + * @returns {Promise}
  27 + */
  28 +export function deleteNotice(data) {
  29 + return new Promise((resolve, reject) => {
  30 + request({
  31 + url: '/notice.deleteNotice',
  32 + method: 'post',
  33 + data
  34 + }).then(response => {
  35 + const res = response.data
  36 + resolve(res)
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +/**
  44 + * 获取字典数据
  45 + * @param {String} dictType 字典类型
  46 + * @param {String} dictName 字典名称
  47 + * @returns {Promise}
  48 + */
  49 +export function getDict(dictType, dictName) {
  50 + return new Promise((resolve, reject) => {
  51 + request({
  52 + url: '/dict.getDict',
  53 + method: 'get',
  54 + params: {
  55 + dictType,
  56 + dictName
  57 + }
  58 + }).then(response => {
  59 + const res = response.data
  60 + resolve(res)
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
0 \ No newline at end of file 66 \ No newline at end of file
src/components/oa/deleteNotice.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('noticeManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div style="text-align:center">
  9 + <p>{{ $t('noticeManage.delete.confirmText') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="visible = false">
  13 + {{ $t('noticeManage.delete.cancelText') }}
  14 + </el-button>
  15 + <el-button type="primary" @click="handleConfirm">
  16 + {{ $t('noticeManage.delete.confirmButton') }}
  17 + </el-button>
  18 + </span>
  19 + </el-dialog>
  20 +</template>
  21 +
  22 +<script>
  23 +import { deleteNotice } from '@/api/oa/noticeManageApi'
  24 +import { getCommunityId } from '@/api/community/communityApi'
  25 +
  26 +export default {
  27 + name: 'DeleteNotice',
  28 + data() {
  29 + return {
  30 + visible: false,
  31 + currentNotice: null,
  32 + communityId: ''
  33 + }
  34 + },
  35 + created() {
  36 + this.communityId = getCommunityId()
  37 + },
  38 + methods: {
  39 + open(notice) {
  40 + this.currentNotice = notice
  41 + this.visible = true
  42 + },
  43 + async handleConfirm() {
  44 + try {
  45 + const params = {
  46 + ...this.currentNotice,
  47 + communityId: this.communityId
  48 + }
  49 + await deleteNotice(params)
  50 + this.$message.success(this.$t('noticeManage.delete.successMessage'))
  51 + this.$emit('success')
  52 + this.visible = false
  53 + } catch (error) {
  54 + this.$message.error(this.$t('noticeManage.delete.errorMessage'))
  55 + }
  56 + },
  57 + handleClose() {
  58 + this.currentNotice = null
  59 + }
  60 + }
  61 +}
  62 +</script>
0 \ No newline at end of file 63 \ No newline at end of file
src/i18n/oaI18n.js
1 import { messages as activitiesTypeManageMessages } from '../views/oa/activitiesTypeManageLang' 1 import { messages as activitiesTypeManageMessages } from '../views/oa/activitiesTypeManageLang'
2 import { messages as activitiesManageMessages } from '../views/oa/activitiesManageLang' 2 import { messages as activitiesManageMessages } from '../views/oa/activitiesManageLang'
  3 +import { messages as noticeManageMessages } from '../views/oa/noticeManageLang'
  4 +import { messages as addNoticeViewMessages } from '../views/oa/addNoticeViewLang'
  5 +import { messages as editNoticeViewMessages } from '../views/oa/editNoticeViewLang'
  6 +import { messages as noticeDetailMessages } from '../views/oa/noticeDetailLang'
3 export const messages ={ 7 export const messages ={
4 en:{ 8 en:{
5 ...activitiesTypeManageMessages.en, 9 ...activitiesTypeManageMessages.en,
6 ...activitiesManageMessages.en, 10 ...activitiesManageMessages.en,
  11 + ...noticeManageMessages.en,
  12 + ...addNoticeViewMessages.en,
  13 + ...editNoticeViewMessages.en,
  14 + ...noticeDetailMessages.en,
7 }, 15 },
8 zh:{ 16 zh:{
9 ...activitiesTypeManageMessages.zh, 17 ...activitiesTypeManageMessages.zh,
10 - ...activitiesManageMessages.zh, 18 + ...activitiesManageMessages.zh,
  19 + ...noticeManageMessages.zh,
  20 + ...addNoticeViewMessages.zh,
  21 + ...editNoticeViewMessages.zh,
  22 + ...noticeDetailMessages.zh,
11 } 23 }
12 } 24 }
13 \ No newline at end of file 25 \ No newline at end of file
src/router/oaRouter.js
@@ -5,8 +5,28 @@ export default [ @@ -5,8 +5,28 @@ export default [
5 component: () => import('@/views/oa/activitiesTypeManageList.vue') 5 component: () => import('@/views/oa/activitiesTypeManageList.vue')
6 }, 6 },
7 { 7 {
8 - path:'/pages/property/activitiesManage',  
9 - name:'/pages/property/activitiesManage', 8 + path: '/pages/property/activitiesManage',
  9 + name: '/pages/property/activitiesManage',
10 component: () => import('@/views/oa/activitiesManageList.vue') 10 component: () => import('@/views/oa/activitiesManageList.vue')
11 - }, 11 + },
  12 + {
  13 + path: '/pages/common/noticeManage',
  14 + name: '/pages/common/noticeManage',
  15 + component: () => import('@/views/oa/noticeManageList.vue')
  16 + },
  17 + {
  18 + path: '/views/oa/addNoticeView',
  19 + name: '/views/oa/addNoticeView',
  20 + component: () => import('@/views/oa/addNoticeViewList.vue')
  21 + },
  22 + {
  23 + path: '/views/oa/editNoticeView',
  24 + name: '/views/oa/editNoticeView',
  25 + component: () => import('@/views/oa/editNoticeViewList.vue')
  26 + },
  27 + {
  28 + path: '/views/oa/noticeDetail',
  29 + name: '/views/oa/noticeDetail',
  30 + component: () => import('@/views/oa/noticeDetailList.vue')
  31 + },
12 ] 32 ]
13 \ No newline at end of file 33 \ No newline at end of file
src/views/oa/addNoticeViewLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + addNoticeView: {
  4 + title: 'New Notice',
  5 + titleLabel: 'Title',
  6 + titlePlaceholder: 'Required, please fill in the title',
  7 + noticeTypeLabel: 'Notice Type',
  8 + noticeTypePlaceholder: 'Required, please select notice type',
  9 + noticeTypeOption1: 'Owner Notification (WeChat notification to followers)',
  10 + noticeTypeOption2: 'Staff Notification',
  11 + contentLabel: 'Notice Content',
  12 + contentPlaceholder: 'Required, please enter notice content',
  13 + submit: 'Submit',
  14 + cancel: 'Cancel',
  15 + validate: {
  16 + title: 'Title cannot be empty',
  17 + noticeType: 'Notice type cannot be empty',
  18 + content: 'Notice content cannot be empty'
  19 + },
  20 + saveSuccess: 'Added successfully',
  21 + saveError: 'Failed to add notice'
  22 + }
  23 + },
  24 + zh: {
  25 + addNoticeView: {
  26 + title: '新公告',
  27 + titleLabel: '标题',
  28 + titlePlaceholder: '必填,请填写标题',
  29 + noticeTypeLabel: '公告类型',
  30 + noticeTypePlaceholder: '必填,请选择公告类型',
  31 + noticeTypeOption1: '业主通知(微信通知关注用户)',
  32 + noticeTypeOption2: '员工通知',
  33 + contentLabel: '公告内容',
  34 + contentPlaceholder: '必填,请输入公告内容',
  35 + submit: '提交',
  36 + cancel: '取消',
  37 + validate: {
  38 + title: '标题不能为空',
  39 + noticeType: '公告类型不能为空',
  40 + content: '公告内容不能为空'
  41 + },
  42 + saveSuccess: '添加成功',
  43 + saveError: '添加公告失败'
  44 + }
  45 + }
  46 +}
0 \ No newline at end of file 47 \ No newline at end of file
src/views/oa/addNoticeViewList.vue 0 → 100644
  1 +<template>
  2 + <div class="add-notice-view-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('addNoticeView.title') }}</span>
  6 + </div>
  7 +
  8 + <el-form ref="form" :model="addNoticeViewInfo" label-width="120px">
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <el-form-item :label="$t('addNoticeView.titleLabel')" prop="title">
  12 + <el-input v-model="addNoticeViewInfo.title" :placeholder="$t('addNoticeView.titlePlaceholder')" clearable />
  13 + </el-form-item>
  14 + </el-col>
  15 + </el-row>
  16 +
  17 + <el-row>
  18 + <el-col :span="24">
  19 + <el-form-item :label="$t('addNoticeView.noticeTypeLabel')" prop="noticeTypeCd">
  20 + <el-select v-model="addNoticeViewInfo.noticeTypeCd" :placeholder="$t('addNoticeView.noticeTypePlaceholder')"
  21 + style="width:100%">
  22 + <el-option :label="$t('addNoticeView.noticeTypeOption1')" value="1000" />
  23 + <el-option :label="$t('addNoticeView.noticeTypeOption2')" value="1001" />
  24 + </el-select>
  25 + </el-form-item>
  26 + </el-col>
  27 + </el-row>
  28 +
  29 + <el-row>
  30 + <el-col :span="24">
  31 + <el-form-item :label="$t('addNoticeView.contentLabel')" prop="context">
  32 + <div class="editor-wrapper">
  33 + <rich-text-editor ref="richTextEditor" v-model="addNoticeViewInfo.context" />
  34 + </div>
  35 + </el-form-item>
  36 + </el-col>
  37 + </el-row>
  38 +
  39 + <el-row>
  40 + <el-col :span="24" class="button-group">
  41 +
  42 + <el-button type="warning" @click="closeNoticeInfo">
  43 + <i class="el-icon-close"></i>
  44 + {{ $t('addNoticeView.cancel') }}
  45 + </el-button>
  46 + <el-button type="primary" @click="saveNoticeInfo">
  47 + <i class="el-icon-check"></i>
  48 + {{ $t('addNoticeView.submit') }}
  49 + </el-button>
  50 + </el-col>
  51 + </el-row>
  52 + </el-form>
  53 + </el-card>
  54 + </div>
  55 +</template>
  56 +
  57 +<script>
  58 +import { saveNotice } from '@/api/oa/addNoticeViewApi'
  59 +import { getCommunityId } from '@/api/community/communityApi'
  60 +import RichTextEditor from "@/components/editor/RichTextEditor";
  61 +
  62 +export default {
  63 + name: 'AddNoticeViewList',
  64 + components: {
  65 + RichTextEditor
  66 + },
  67 + data() {
  68 + return {
  69 + addNoticeViewInfo: {
  70 + title: '',
  71 + noticeTypeCd: '',
  72 + context: '',
  73 + startTime: '',
  74 + endTime: '',
  75 + objType: '',
  76 + objId: '',
  77 + floorId: '',
  78 + unitId: '',
  79 + roomId: '',
  80 + state: '3000',
  81 + isAll: 'N'
  82 + },
  83 + }
  84 + },
  85 + created() {
  86 + this.addNoticeViewInfo.communityId = getCommunityId()
  87 + },
  88 + methods: {
  89 + onEditorChange({ quill, html, text }) {
  90 + console.log('editor change!', quill, html, text)
  91 + this.addNoticeViewInfo.context = html
  92 + },
  93 + validateForm() {
  94 + let isValid = true
  95 + if (!this.addNoticeViewInfo.title) {
  96 + this.$message.error(this.$t('addNoticeView.validate.title'))
  97 + isValid = false
  98 + }
  99 + if (!this.addNoticeViewInfo.noticeTypeCd) {
  100 + this.$message.error(this.$t('addNoticeView.validate.noticeType'))
  101 + isValid = false
  102 + }
  103 + if (!this.addNoticeViewInfo.context) {
  104 + this.$message.error(this.$t('addNoticeView.validate.content'))
  105 + isValid = false
  106 + }
  107 + return isValid
  108 + },
  109 + async saveNoticeInfo() {
  110 + if (!this.validateForm()) {
  111 + return
  112 + }
  113 +
  114 + try {
  115 + const response = await saveNotice(this.addNoticeViewInfo)
  116 + if (response.code === 0) {
  117 + this.$message.success(this.$t('addNoticeView.saveSuccess'))
  118 + this.$router.go(-1)
  119 + } else {
  120 + this.$message.error(response.msg)
  121 + }
  122 + } catch (error) {
  123 + this.$message.error(this.$t('addNoticeView.saveError'))
  124 + }
  125 + },
  126 + closeNoticeInfo() {
  127 + this.$router.go(-1)
  128 + }
  129 + }
  130 +}
  131 +</script>
  132 +
  133 +<style lang="scss" scoped>
  134 +.add-notice-view-container {
  135 + padding: 20px;
  136 +
  137 + .box-card {
  138 + margin-bottom: 20px;
  139 + }
  140 +
  141 + .button-group {
  142 + text-align: right;
  143 + margin-top: 20px;
  144 + }
  145 +
  146 + .editor-wrapper {
  147 + height: 300px;
  148 + margin-bottom: 20px;
  149 +
  150 + .ql-container {
  151 + height: 250px;
  152 + }
  153 + }
  154 +}
  155 +</style>
0 \ No newline at end of file 156 \ No newline at end of file
src/views/oa/editNoticeViewLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + editNoticeView: {
  4 + title: 'Edit Notice',
  5 + titleLabel: 'Title',
  6 + titlePlaceholder: 'Required, please enter title',
  7 + contentLabel: 'Content',
  8 + contentPlaceholder: 'Required, please enter notice content',
  9 + validate: {
  10 + titleRequired: 'Title cannot be empty',
  11 + titleLength: 'Title must be between 4 to 100 characters',
  12 + contentRequired: 'Content cannot be empty',
  13 + contentMaxLength: 'Content cannot exceed 10000 characters',
  14 + noticeIdRequired: 'Notice ID cannot be empty'
  15 + },
  16 + fetchError: 'Failed to fetch notice details',
  17 + updateSuccess: 'Notice updated successfully',
  18 + updateError: 'Failed to update notice'
  19 + }
  20 + },
  21 + zh: {
  22 + editNoticeView: {
  23 + title: '修改公告',
  24 + titleLabel: '标题',
  25 + titlePlaceholder: '必填,请填写标题',
  26 + contentLabel: '公告内容',
  27 + contentPlaceholder: '必填,请输入公告内容',
  28 + validate: {
  29 + titleRequired: '标题不能为空',
  30 + titleLength: '标题必须在4至100字符之间',
  31 + contentRequired: '公告内容不能为空',
  32 + contentMaxLength: '公告内容不能超过10000个字',
  33 + noticeIdRequired: '公告ID不能为空'
  34 + },
  35 + fetchError: '获取公告详情失败',
  36 + updateSuccess: '公告修改成功',
  37 + updateError: '公告修改失败'
  38 + }
  39 + }
  40 +}
0 \ No newline at end of file 41 \ No newline at end of file
src/views/oa/editNoticeViewList.vue 0 → 100644
  1 +<template>
  2 + <div class="edit-notice-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('editNoticeView.title') }}</span>
  6 + </div>
  7 +
  8 + <el-form ref="form" :model="editNoticeViewInfo" label-width="120px">
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <el-form-item :label="$t('editNoticeView.titleLabel')" prop="title">
  12 + <el-input v-model="editNoticeViewInfo.title" :placeholder="$t('editNoticeView.titlePlaceholder')"
  13 + clearable />
  14 + </el-form-item>
  15 + </el-col>
  16 + </el-row>
  17 +
  18 + <el-row>
  19 + <el-col :span="24">
  20 + <el-form-item :label="$t('editNoticeView.contentLabel')" prop="context">
  21 + <div class="editor-wrapper">
  22 + <rich-text-editor ref="richTextEditor" v-model="editNoticeViewInfo.context" />
  23 + </div>
  24 + </el-form-item>
  25 + </el-col>
  26 + </el-row>
  27 +
  28 + <el-row>
  29 + <el-col :span="24" class="button-group">
  30 +
  31 + <el-button type="warning" @click="closeEditNoticeInfo" style="margin-left: 20px;">
  32 + <i class="el-icon-close"></i>
  33 + {{ $t('common.cancel') }}
  34 + </el-button>
  35 + <el-button type="primary" @click="editNotice">
  36 + <i class="el-icon-check"></i>
  37 + {{ $t('common.save') }}
  38 + </el-button>
  39 + </el-col>
  40 + </el-row>
  41 + </el-form>
  42 + </el-card>
  43 + </div>
  44 +</template>
  45 +
  46 +<script>
  47 +import { updateNotice, getNoticeDetail } from '@/api/oa/editNoticeViewApi'
  48 +import { getCommunityId } from '@/api/community/communityApi'
  49 +import RichTextEditor from "@/components/editor/RichTextEditor";
  50 +
  51 +
  52 +export default {
  53 + name: 'EditNoticeViewList',
  54 + data() {
  55 + return {
  56 + editNoticeViewInfo: {
  57 + noticeId: '',
  58 + title: '',
  59 + noticeTypeCd: '',
  60 + context: '',
  61 + startTime: '',
  62 + endTime: '',
  63 + communityId: ''
  64 + }
  65 + }
  66 + },
  67 + components: {
  68 + RichTextEditor
  69 + },
  70 + created() {
  71 + this.initData()
  72 + },
  73 + methods: {
  74 + async initData() {
  75 + this.editNoticeViewInfo.noticeId = this.$route.query.noticeId
  76 + this.editNoticeViewInfo.communityId = getCommunityId()
  77 + await this._initEditNoticeInfo()
  78 + },
  79 + async _initEditNoticeInfo() {
  80 + try {
  81 + const params = {
  82 + page: 1,
  83 + row: 1,
  84 + communityId: this.editNoticeViewInfo.communityId,
  85 + noticeId: this.editNoticeViewInfo.noticeId
  86 + }
  87 + const { notices } = await getNoticeDetail(params)
  88 + this.editNoticeViewInfo = { ...notices[0] }
  89 + this.$refs.richTextEditor.setContent(notices[0].context)
  90 +
  91 + } catch (error) {
  92 + this.$message.error(this.$t('editNoticeView.fetchError'))
  93 + }
  94 + },
  95 + editNoticeValidate() {
  96 +
  97 +
  98 + return this.$refs.form.validate(valid => {
  99 + if (!valid) {
  100 + return false
  101 + }
  102 + return true
  103 + })
  104 + },
  105 + async editNotice() {
  106 +
  107 + try {
  108 + const { code, msg } = await updateNotice(this.editNoticeViewInfo)
  109 + if (code === 0) {
  110 + this.$message.success(this.$t('editNoticeView.updateSuccess'))
  111 + this.closeEditNoticeInfo()
  112 + } else {
  113 + this.$message.error(msg)
  114 + }
  115 + } catch (error) {
  116 + this.$message.error(this.$t('editNoticeView.updateError'))
  117 + }
  118 + },
  119 + closeEditNoticeInfo() {
  120 + this.$router.go(-1)
  121 + }
  122 + }
  123 +}
  124 +</script>
  125 +
  126 +<style lang="scss" scoped>
  127 +.edit-notice-container {
  128 + padding: 20px;
  129 +
  130 + .box-card {
  131 + margin-bottom: 20px;
  132 + }
  133 +
  134 + .editor-wrapper {
  135 + width: 100%;
  136 + }
  137 +
  138 + .button-group {
  139 + text-align: right;
  140 + margin-top: 20px;
  141 + }
  142 +}
  143 +</style>
0 \ No newline at end of file 144 \ No newline at end of file
src/views/oa/noticeDetailLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + noticeDetail: {
  4 + title: 'Notice Details',
  5 + back: 'Back',
  6 + titleLabel: 'Title',
  7 + noticeType: 'Notice Type',
  8 + startTime: 'Start Time',
  9 + endTime: 'End Time',
  10 + createTime: 'Create Time',
  11 + content: 'Content',
  12 + fetchError: 'Failed to fetch notice details'
  13 + }
  14 + },
  15 + zh: {
  16 + noticeDetail: {
  17 + title: '公告详情',
  18 + back: '返回',
  19 + titleLabel: '标题',
  20 + noticeType: '公告类型',
  21 + startTime: '开始时间',
  22 + endTime: '结束时间',
  23 + createTime: '创建时间',
  24 + content: '公告内容',
  25 + fetchError: '获取公告详情失败'
  26 + }
  27 + }
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
src/views/oa/noticeDetailList.vue 0 → 100644
  1 +<template>
  2 + <div class="notice-detail-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between">
  5 + <span>{{ $t('noticeDetail.title') }}</span>
  6 + <el-button type="primary" size="small" @click="_goBack">
  7 + <i class="el-icon-close"></i>
  8 + {{ $t('noticeDetail.back') }}
  9 + </el-button>
  10 + </div>
  11 +
  12 + <el-row :gutter="20">
  13 + <el-col :span="24">
  14 + <el-card shadow="never">
  15 + <el-form label-position="left" label-width="120px">
  16 + <el-form-item :label="$t('noticeDetail.titleLabel')">
  17 + <el-input v-model="noticeDetailInfo.title" readonly class="readonly-input"></el-input>
  18 + </el-form-item>
  19 +
  20 + <el-form-item :label="$t('noticeDetail.noticeType')">
  21 + <el-input v-model="noticeDetailInfo.noticeTypeCdName" readonly class="readonly-input"></el-input>
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('noticeDetail.startTime')">
  25 + <el-input v-model="noticeDetailInfo.startTime" readonly class="readonly-input"></el-input>
  26 + </el-form-item>
  27 +
  28 + <el-form-item :label="$t('noticeDetail.endTime')">
  29 + <el-input v-model="noticeDetailInfo.endTime" readonly class="readonly-input"></el-input>
  30 + </el-form-item>
  31 +
  32 + <el-form-item :label="$t('noticeDetail.createTime')">
  33 + <el-input v-model="noticeDetailInfo.createTime" readonly class="readonly-input"></el-input>
  34 + </el-form-item>
  35 +
  36 + <el-form-item :label="$t('noticeDetail.content')">
  37 + <div class="notice-content" v-html="noticeDetailInfo.context"></div>
  38 + </el-form-item>
  39 + </el-form>
  40 + </el-card>
  41 + </el-col>
  42 + </el-row>
  43 + </el-card>
  44 + </div>
  45 +</template>
  46 +
  47 +<script>
  48 +import { getNoticeDetail } from '@/api/oa/noticeDetailApi'
  49 +import { getCommunityId } from '@/api/community/communityApi'
  50 +
  51 +export default {
  52 + name: 'NoticeDetailList',
  53 + data() {
  54 + return {
  55 + noticeDetailInfo: {
  56 + noticeId: '',
  57 + title: '',
  58 + context: '',
  59 + startTime: '',
  60 + endTime: '',
  61 + noticeTypeCd: '',
  62 + noticeTypeCdName: '',
  63 + createTime: ''
  64 + },
  65 + communityId: ''
  66 + }
  67 + },
  68 + created() {
  69 + this.communityId = getCommunityId()
  70 + const noticeId = this.$route.query.noticeId
  71 + if (noticeId) {
  72 + this.noticeDetailInfo.noticeId = noticeId
  73 + this._listNotices()
  74 + }
  75 + },
  76 + methods: {
  77 + async _listNotices() {
  78 + try {
  79 + const params = {
  80 + page: 1,
  81 + row: 1,
  82 + communityId: this.communityId,
  83 + noticeId: this.noticeDetailInfo.noticeId
  84 + }
  85 + const { notices } = await getNoticeDetail(params)
  86 + if (notices && notices.length > 0) {
  87 + // 过滤XSS攻击
  88 + notices[0].context = this.filterXSS(notices[0].context)
  89 + this.noticeDetailInfo =notices[0]
  90 + }
  91 + } catch (error) {
  92 + this.$message.error(this.$t('noticeDetail.fetchError'))
  93 + }
  94 + },
  95 + filterXSS(html) {
  96 + // 这里应该实现XSS过滤逻辑
  97 + // 实际项目中应该使用专门的XSS过滤库
  98 + return html || ''
  99 + },
  100 + _goBack() {
  101 + this.$router.go(-1)
  102 + }
  103 + }
  104 +}
  105 +</script>
  106 +
  107 +<style lang="scss" scoped>
  108 +.notice-detail-container {
  109 + padding: 20px;
  110 +
  111 + .box-card {
  112 + margin-bottom: 20px;
  113 +
  114 + .float-right {
  115 + float: right;
  116 + }
  117 + }
  118 +
  119 + .readonly-input {
  120 + ::v-deep .el-input__inner {
  121 + background-color: #f5f7fa;
  122 + border-color: #e4e7ed;
  123 + color: #606266;
  124 + cursor: not-allowed;
  125 + }
  126 + }
  127 +
  128 + .notice-content {
  129 + padding: 10px;
  130 + border: 1px solid #ebeef5;
  131 + border-radius: 4px;
  132 + min-height: 100px;
  133 + background-color: #f5f7fa;
  134 + }
  135 +}
  136 +</style>
0 \ No newline at end of file 137 \ No newline at end of file
src/views/oa/noticeManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + noticeManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + noticeTypePlaceholder: 'Please select notice type',
  7 + ownerNotice: 'Owner Notice',
  8 + staffNotice: 'Staff Notice',
  9 + statePlaceholder: 'Please select status',
  10 + pendingNotice: 'Pending Notice',
  11 + notifying: 'Notifying',
  12 + noticeComplete: 'Notice Complete',
  13 + titlePlaceholder: 'Please enter notice title',
  14 + startTimePlaceholder: 'Required, please select start time',
  15 + endTimePlaceholder: 'Required, please select end time'
  16 + },
  17 + list: {
  18 + title: 'Notice Information'
  19 + },
  20 + table: {
  21 + noticeId: 'Notice ID',
  22 + title: 'Title',
  23 + noticeType: 'Notice Type',
  24 + startTime: 'Start Time',
  25 + endTime: 'End Time',
  26 + state: 'Status',
  27 + noticeRange: 'Notice Range'
  28 + },
  29 + delete: {
  30 + title: 'Please confirm your operation',
  31 + confirmText: 'Confirm to delete this notice?',
  32 + cancelText: 'Cancel',
  33 + confirmButton: 'Confirm Delete',
  34 + successMessage: 'Delete successfully',
  35 + errorMessage: 'Delete failed'
  36 + },
  37 + fetchError: 'Failed to fetch notice data'
  38 + }
  39 + },
  40 + zh: {
  41 + noticeManage: {
  42 + search: {
  43 + title: '查询条件',
  44 + noticeTypePlaceholder: '请选择公告类型',
  45 + ownerNotice: '业主通知',
  46 + staffNotice: '员工通知',
  47 + statePlaceholder: '请选择状态',
  48 + pendingNotice: '待通知',
  49 + notifying: '通知中',
  50 + noticeComplete: '通知完成',
  51 + titlePlaceholder: '请输入公告标题',
  52 + startTimePlaceholder: '必填,请填写开始时间',
  53 + endTimePlaceholder: '必填,请填写结束时间'
  54 + },
  55 + list: {
  56 + title: '公告信息'
  57 + },
  58 + table: {
  59 + noticeId: '公告ID',
  60 + title: '标题',
  61 + noticeType: '公告类型',
  62 + startTime: '开始时间',
  63 + endTime: '结束时间',
  64 + state: '状态',
  65 + noticeRange: '通知范围'
  66 + },
  67 + delete: {
  68 + title: '请确认您的操作',
  69 + confirmText: '确定删除公告?',
  70 + cancelText: '点错了',
  71 + confirmButton: '确认删除',
  72 + successMessage: '删除成功',
  73 + errorMessage: '删除失败'
  74 + },
  75 + fetchError: '获取公告数据失败'
  76 + }
  77 + }
  78 +}
0 \ No newline at end of file 79 \ No newline at end of file
src/views/oa/noticeManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="notice-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('noticeManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="4">
  10 + <el-select v-model="searchForm.noticeTypeCd" :placeholder="$t('noticeManage.search.noticeTypePlaceholder')"
  11 + style="width:100%">
  12 + <el-option :label="$t('noticeManage.search.noticeTypePlaceholder')" value="" />
  13 + <el-option :label="$t('noticeManage.search.ownerNotice')" value="1000" />
  14 + <el-option :label="$t('noticeManage.search.staffNotice')" value="1001" />
  15 + </el-select>
  16 + </el-col>
  17 + <el-col :span="4">
  18 + <el-select v-model="searchForm.state" :placeholder="$t('noticeManage.search.statePlaceholder')"
  19 + style="width:100%">
  20 + <el-option :label="$t('noticeManage.search.statePlaceholder')" value="" />
  21 + <el-option :label="$t('noticeManage.search.pendingNotice')" value="1000" />
  22 + <el-option :label="$t('noticeManage.search.notifying')" value="2000" />
  23 + <el-option :label="$t('noticeManage.search.noticeComplete')" value="3000" />
  24 + </el-select>
  25 + </el-col>
  26 + <el-col :span="4">
  27 + <el-input v-model="searchForm.title" :placeholder="$t('noticeManage.search.titlePlaceholder')" />
  28 + </el-col>
  29 + <el-col :span="4">
  30 + <el-date-picker v-model="searchForm.startTime" type="datetime"
  31 + :placeholder="$t('noticeManage.search.startTimePlaceholder')" style="width:100%" />
  32 + </el-col>
  33 + <el-col :span="4">
  34 + <el-date-picker v-model="searchForm.endTime" type="datetime"
  35 + :placeholder="$t('noticeManage.search.endTimePlaceholder')" style="width:100%" />
  36 + </el-col>
  37 + <el-col :span="4">
  38 + <el-button type="primary" @click="handleSearch">
  39 + {{ $t('common.search') }}
  40 + </el-button>
  41 + <el-button @click="handleReset">
  42 + {{ $t('common.reset') }}
  43 + </el-button>
  44 + </el-col>
  45 + </el-row>
  46 + </el-card>
  47 +
  48 + <!-- 公告列表 -->
  49 + <el-card class="list-wrapper">
  50 + <div slot="header" class="flex justify-between">
  51 + <span>{{ $t('noticeManage.list.title') }}</span>
  52 + <el-button type="primary" size="small" style="float:right" @click="handleAdd">
  53 + {{ $t('common.add') }}
  54 + </el-button>
  55 + </div>
  56 +
  57 + <el-table v-loading="loading" :data="tableData" border style="width:100%">
  58 + <el-table-column prop="noticeId" :label="$t('noticeManage.table.noticeId')" align="center" />
  59 + <el-table-column prop="title" :label="$t('noticeManage.table.title')" align="center" />
  60 + <el-table-column prop="noticeTypeCdName" :label="$t('noticeManage.table.noticeType')" align="center" />
  61 + <el-table-column prop="startTime" :label="$t('noticeManage.table.startTime')" align="center" />
  62 + <el-table-column prop="endTime" :label="$t('noticeManage.table.endTime')" align="center" />
  63 + <el-table-column prop="stateName" :label="$t('noticeManage.table.state')" align="center" />
  64 + <el-table-column prop="objName" :label="$t('noticeManage.table.noticeRange')" align="center" />
  65 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  66 + <template slot-scope="scope">
  67 + <el-button size="mini" @click="handleDetail(scope.row)">
  68 + {{ $t('common.detail') }}
  69 + </el-button>
  70 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  71 + {{ $t('common.edit') }}
  72 + </el-button>
  73 + <el-button v-if="scope.row.state !== '2000'" size="mini" type="danger" @click="handleDelete(scope.row)">
  74 + {{ $t('common.delete') }}
  75 + </el-button>
  76 + </template>
  77 + </el-table-column>
  78 + </el-table>
  79 +
  80 + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  81 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  82 + @current-change="handleCurrentChange" />
  83 + </el-card>
  84 +
  85 + <!-- 删除确认对话框 -->
  86 + <delete-notice ref="deleteNotice" @success="handleSuccess" />
  87 + </div>
  88 +</template>
  89 +
  90 +<script>
  91 +import { listNotices } from '@/api/oa/noticeManageApi'
  92 +import DeleteNotice from '@/components/oa/deleteNotice'
  93 +import { getCommunityId } from '@/api/community/communityApi'
  94 +
  95 +export default {
  96 + name: 'NoticeManageList',
  97 + components: {
  98 + DeleteNotice
  99 + },
  100 + data() {
  101 + return {
  102 + loading: false,
  103 + searchForm: {
  104 + title: '',
  105 + noticeTypeCd: '',
  106 + state: '',
  107 + startTime: '',
  108 + endTime: ''
  109 + },
  110 + tableData: [],
  111 + pagination: {
  112 + current: 1,
  113 + size: 10,
  114 + total: 0
  115 + },
  116 + communityId: ''
  117 + }
  118 + },
  119 + created() {
  120 + this.communityId = getCommunityId()
  121 + this.getList()
  122 + },
  123 + methods: {
  124 + async getList() {
  125 + try {
  126 + this.loading = true
  127 + const params = {
  128 + page: this.pagination.current,
  129 + row: this.pagination.size,
  130 + ...this.searchForm,
  131 + communityId: this.communityId
  132 + }
  133 + const { notices, total } = await listNotices(params)
  134 + this.tableData = notices
  135 + this.pagination.total = total
  136 + } catch (error) {
  137 + this.$message.error(this.$t('noticeManage.fetchError'))
  138 + } finally {
  139 + this.loading = false
  140 + }
  141 + },
  142 + handleSearch() {
  143 + this.pagination.current = 1
  144 + this.getList()
  145 + },
  146 + handleReset() {
  147 + this.searchForm = {
  148 + title: '',
  149 + noticeTypeCd: '',
  150 + state: '',
  151 + startTime: '',
  152 + endTime: ''
  153 + }
  154 + this.getList()
  155 + },
  156 + handleAdd() {
  157 + this.$router.push('/views/oa/addNoticeView')
  158 + },
  159 + handleEdit(row) {
  160 + this.$router.push(`/views/oa/editNoticeView?noticeId=${row.noticeId}`)
  161 + },
  162 + handleDetail(row) {
  163 + this.$router.push(`/views/oa/noticeDetail?noticeId=${row.noticeId}`)
  164 + },
  165 + handleDelete(row) {
  166 + this.$refs.deleteNotice.open(row)
  167 + },
  168 + handleSuccess() {
  169 + this.getList()
  170 + },
  171 + handleSizeChange(val) {
  172 + this.pagination.size = val
  173 + this.getList()
  174 + },
  175 + handleCurrentChange(val) {
  176 + this.pagination.current = val
  177 + this.getList()
  178 + }
  179 + }
  180 +}
  181 +</script>
  182 +
  183 +<style lang="scss" scoped>
  184 +.notice-manage-container {
  185 + padding: 20px;
  186 +
  187 + .search-wrapper {
  188 + margin-bottom: 20px;
  189 +
  190 + .el-row {
  191 + margin-bottom: 20px;
  192 + }
  193 + }
  194 +
  195 + .list-wrapper {
  196 + .el-pagination {
  197 + margin-top: 20px;
  198 + text-align: right;
  199 + }
  200 + }
  201 +}
  202 +</style>
0 \ No newline at end of file 203 \ No newline at end of file