Commit a99eb7a5b48208c7b355eb7957f16f825c5b91d5

Authored by wuxw
1 parent 0bf7e6a5

开发完成办公下功能

Showing 44 changed files with 4633 additions and 188 deletions
src/api/community/communityApi.js
... ... @@ -57,12 +57,6 @@ export function getCommunityId() {
57 57 return getCurrentCommunity().communityId
58 58 }
59 59  
60   -/************* ✨ Windsurf Command ⭐ *************/
61   -/**
62   - * Get the current community
63   - * @returns {Object} The current community object
64   - */
65   -/******* 8c78c7d7-a438-4630-a8c7-b05b9f491159 *******/
66 60  
67 61  
68 62 export function getCommunity() {
... ...
src/api/oa/addExamineStaffApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 保存考核员工信息
  5 +export function saveExamineStaff(data) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/examine.saveExamineStaff',
  9 + method: 'post',
  10 + data: {
  11 + ...data,
  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 listExamineProject(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/examine.listExamineProject',
  28 + method: 'get',
  29 + params: {
  30 + ...params,
  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 listOrgTree(params) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/org.listOrgTree',
  47 + method: 'get',
  48 + params: {
  49 + ...params,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 查询员工信息
  62 +export function queryStaffInfos(params) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/query.staff.infos',
  66 + method: 'get',
  67 + params: {
  68 + ...params,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
  79 +
  80 +// 上传图片
  81 +export function uploadImage(data) {
  82 + return new Promise((resolve, reject) => {
  83 + const formData = new FormData()
  84 + formData.append('uploadFile', data)
  85 + formData.append('communityId', getCommunityId())
  86 +
  87 + request({
  88 + url: '/uploadFile/uploadImage',
  89 + method: 'post',
  90 + data: formData,
  91 + headers: {
  92 + 'Content-Type': 'multipart/form-data'
  93 + }
  94 + }).then(response => {
  95 + const res = response.data
  96 + resolve(res)
  97 + }).catch(error => {
  98 + reject(error)
  99 + })
  100 + })
  101 +}
0 102 \ No newline at end of file
... ...
src/api/oa/addOwnerVotingApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询楼栋和单元信息
  5 +export function queryFloorAndUnits(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/floor.queryFloorAndUnits',
  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 queryRooms(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/room.queryRooms',
  28 + method: 'get',
  29 + params: {
  30 + ...params,
  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 saveOwnerVote(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/question.saveOwnerVote',
  47 + method: 'post',
  48 + data: {
  49 + ...data,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
0 60 \ No newline at end of file
... ...
src/api/oa/editExamineStaffApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 更新考核员工信息
  5 +export function updateExamineStaff(data) {
  6 + return new Promise((resolve, reject) => {
  7 + data.communityId = getCommunityId()
  8 + request({
  9 + url: '/examine.updateExamineStaff',
  10 + method: 'post',
  11 + data
  12 + }).then(response => {
  13 + const res = response.data
  14 + resolve(res)
  15 + }).catch(error => {
  16 + reject(error)
  17 + })
  18 + })
  19 +}
  20 +
  21 +// 获取考核项目列表
  22 +export function listExamineProjects(params) {
  23 + return new Promise((resolve, reject) => {
  24 + params.communityId = getCommunityId()
  25 + request({
  26 + url: '/examine.listExamineProject',
  27 + method: 'get',
  28 + params
  29 + }).then(response => {
  30 + const res = response.data
  31 + resolve(res)
  32 + }).catch(error => {
  33 + reject(error)
  34 + })
  35 + })
  36 +}
  37 +
  38 +// 获取考核员工列表
  39 +export function listExamineStaffs(params) {
  40 + return new Promise((resolve, reject) => {
  41 + params.communityId = getCommunityId()
  42 + request({
  43 + url: '/examine.listExamineStaff',
  44 + method: 'get',
  45 + params
  46 + }).then(response => {
  47 + const res = response.data
  48 + resolve(res)
  49 + }).catch(error => {
  50 + reject(error)
  51 + })
  52 + })
  53 +}
  54 +
  55 +// 上传图片
  56 +export function uploadImage(data) {
  57 + return new Promise((resolve, reject) => {
  58 + data.append('communityId', getCommunityId())
  59 + request({
  60 + url: '/uploadFile',
  61 + method: 'post',
  62 + data,
  63 + headers: {
  64 + 'Content-Type': 'multipart/form-data'
  65 + }
  66 + }).then(response => {
  67 + const res = response.data
  68 + resolve(res)
  69 + }).catch(error => {
  70 + reject(error)
  71 + })
  72 + })
  73 +}
0 74 \ No newline at end of file
... ...
src/api/oa/editOwnerVotingApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取投票详情
  5 +export function listOwnerVote(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/question.listOwnerVote',
  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 updateOwnerVote(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/question.updateOwnerVote',
  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 queryFloorAndUnits(params) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/floor.queryFloorAndUnits',
  47 + method: 'get',
  48 + params: {
  49 + ...params,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 查询房屋信息
  62 +export function queryRooms(params) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/room.queryRooms',
  66 + method: 'get',
  67 + params: {
  68 + ...params,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
0 79 \ No newline at end of file
... ...
src/api/oa/examineProjectManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取考核项目列表
  5 +export function listExamineProject(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/examine.listExamineProject',
  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 saveExamineProject(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/examine.saveExamineProject',
  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 updateExamineProject(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/examine.updateExamineProject',
  47 + method: 'post',
  48 + data: {
  49 + ...data,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 删除考核项目
  62 +export function deleteExamineProject(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/examine.deleteExamineProject',
  66 + method: 'post',
  67 + data: {
  68 + ...data,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
0 79 \ No newline at end of file
... ...
src/api/oa/examineStaffManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取考核人员列表
  5 +export function listExamineStaff(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/examine.listExamineStaff',
  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 deleteExamineStaff(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/examine.deleteExamineStaff',
  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 +}
0 41 \ No newline at end of file
... ...
src/api/oa/examineStaffValueApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * 获取员工考核记录列表
  5 + * @param {Object} params 查询参数
  6 + * @returns {Promise}
  7 + */
  8 +export function listExamineStaffValue(params) {
  9 + return new Promise((resolve, reject) => {
  10 + request({
  11 + url: '/examine.listExamineStaffValue',
  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 addExamineStaffValue(data) {
  29 + return new Promise((resolve, reject) => {
  30 + request({
  31 + url: '/examine.saveExamineStaffValue',
  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 +}
0 42 \ No newline at end of file
... ...
src/api/oa/ownerVotingApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取业主投票列表
  5 +export function listOwnerVote(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/question.listOwnerVote',
  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 getOwnerVoteDetail(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/question.getOwnerVoteDetail',
  28 + method: 'get',
  29 + params: {
  30 + ...params,
  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 addOwnerVote(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/question.addOwnerVote',
  47 + method: 'post',
  48 + data: {
  49 + ...data,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 删除投票
  62 +export function deleteOwnerVote(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/question.deleteOwnerVote',
  66 + method: 'post',
  67 + data: {
  68 + ...data,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
  79 +
  80 +// 删除问卷
  81 +export function deleteQuestionAnswer(data) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/question.deleteQuestionAnswer',
  85 + method: 'post',
  86 + data: {
  87 + ...data,
  88 + communityId: getCommunityId()
  89 + }
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
  98 +
  99 +// 发布投票
  100 +export function publishQuestion(data) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/question.publishQuestion',
  104 + method: 'post',
  105 + data: {
  106 + ...data,
  107 + communityId: getCommunityId()
  108 + }
  109 + }).then(response => {
  110 + const res = response.data
  111 + resolve(res)
  112 + }).catch(error => {
  113 + reject(error)
  114 + })
  115 + })
  116 +}
0 117 \ No newline at end of file
... ...
src/api/oa/printOwnerVotingApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取业主投票信息
  5 +export function listOwnerVote(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const defaultParams = {
  8 + communityId: getCommunityId(),
  9 + ...params
  10 + }
  11 + request({
  12 + url: '/question.listOwnerVote',
  13 + method: 'get',
  14 + params: defaultParams
  15 + }).then(response => {
  16 + const res = response.data
  17 + resolve(res)
  18 + }).catch(error => {
  19 + reject(error)
  20 + })
  21 + })
  22 +}
  23 +
  24 +// 获取用户问题答案列表
  25 +export function listUserQuestionAnswer(params) {
  26 + return new Promise((resolve, reject) => {
  27 + const defaultParams = {
  28 + communityId: getCommunityId(),
  29 + ...params
  30 + }
  31 + request({
  32 + url: '/question.listUserQuestionAnswer',
  33 + method: 'get',
  34 + params: defaultParams
  35 + }).then(response => {
  36 + const res = response.data
  37 + resolve(res)
  38 + }).catch(error => {
  39 + reject(error)
  40 + })
  41 + })
  42 +}
0 43 \ No newline at end of file
... ...
src/components/oa/addExamineProject.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('examineProjectManage.add.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + label-position="right"
  14 + >
  15 + <el-form-item
  16 + :label="$t('examineProjectManage.form.name')"
  17 + prop="name"
  18 + >
  19 + <el-input
  20 + v-model="formData.name"
  21 + :placeholder="$t('examineProjectManage.form.namePlaceholder')"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item
  25 + :label="$t('examineProjectManage.form.post')"
  26 + prop="postCd"
  27 + >
  28 + <el-select
  29 + v-model="formData.postCd"
  30 + :placeholder="$t('examineProjectManage.form.postPlaceholder')"
  31 + style="width:100%"
  32 + >
  33 + <el-option
  34 + :label="$t('examineProjectManage.form.commonPost')"
  35 + value="9999"
  36 + />
  37 + </el-select>
  38 + </el-form-item>
  39 + <el-form-item
  40 + :label="$t('examineProjectManage.form.weight')"
  41 + prop="weight"
  42 + >
  43 + <el-input
  44 + v-model="formData.weight"
  45 + :placeholder="$t('examineProjectManage.form.weightPlaceholder')"
  46 + style="width:80%"
  47 + >
  48 + <template slot="append">%</template>
  49 + </el-input>
  50 + </el-form-item>
  51 + <el-form-item
  52 + :label="$t('examineProjectManage.form.state')"
  53 + prop="state"
  54 + >
  55 + <el-select
  56 + v-model="formData.state"
  57 + :placeholder="$t('examineProjectManage.form.statePlaceholder')"
  58 + style="width:100%"
  59 + >
  60 + <el-option
  61 + :label="$t('examineProjectManage.status.enable')"
  62 + value="Y"
  63 + />
  64 + <el-option
  65 + :label="$t('examineProjectManage.status.disable')"
  66 + value="N"
  67 + />
  68 + </el-select>
  69 + </el-form-item>
  70 + </el-form>
  71 + <span slot="footer" class="dialog-footer">
  72 + <el-button @click="visible = false">
  73 + {{ $t('common.cancel') }}
  74 + </el-button>
  75 + <el-button type="primary" @click="handleSubmit">
  76 + {{ $t('common.confirm') }}
  77 + </el-button>
  78 + </span>
  79 + </el-dialog>
  80 +</template>
  81 +
  82 +<script>
  83 +import { saveExamineProject } from '@/api/oa/examineProjectManageApi'
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +
  86 +export default {
  87 + name: 'AddExamineProject',
  88 + data() {
  89 + return {
  90 + visible: false,
  91 + formData: {
  92 + name: '',
  93 + postCd: '',
  94 + post: this.$t('examineProjectManage.form.commonPost'),
  95 + weight: '',
  96 + state: '',
  97 + communityId: getCommunityId()
  98 + },
  99 + rules: {
  100 + name: [
  101 + { required: true, message: this.$t('examineProjectManage.validate.nameRequired'), trigger: 'blur' },
  102 + { max: 64, message: this.$t('examineProjectManage.validate.nameMaxLength'), trigger: 'blur' }
  103 + ],
  104 + postCd: [
  105 + { required: true, message: this.$t('examineProjectManage.validate.postRequired'), trigger: 'change' },
  106 + { max: 30, message: this.$t('examineProjectManage.validate.postMaxLength'), trigger: 'blur' }
  107 + ],
  108 + weight: [
  109 + { required: true, message: this.$t('examineProjectManage.validate.weightRequired'), trigger: 'blur' },
  110 + { max: 12, message: this.$t('examineProjectManage.validate.weightMaxLength'), trigger: 'blur' }
  111 + ],
  112 + state: [
  113 + { required: true, message: this.$t('examineProjectManage.validate.stateRequired'), trigger: 'change' },
  114 + { max: 12, message: this.$t('examineProjectManage.validate.stateMaxLength'), trigger: 'blur' }
  115 + ]
  116 + }
  117 + }
  118 + },
  119 + methods: {
  120 + open() {
  121 + this.visible = true
  122 + },
  123 + handleClose() {
  124 + this.$refs.form.resetFields()
  125 + },
  126 + handleSubmit() {
  127 + this.$refs.form.validate(async valid => {
  128 + if (valid) {
  129 + try {
  130 + await saveExamineProject(this.formData)
  131 + this.$message.success(this.$t('examineProjectManage.add.success'))
  132 + this.visible = false
  133 + this.$emit('success')
  134 + } catch (error) {
  135 + this.$message.error(error.message || this.$t('examineProjectManage.add.error'))
  136 + }
  137 + }
  138 + })
  139 + }
  140 + }
  141 +}
  142 +</script>
0 143 \ No newline at end of file
... ...
src/components/oa/addOwnerVoting.vue 0 → 100644
  1 +<template>
  2 + <div class="add-owner-voting-container">
  3 + <el-card>
  4 + <div slot="header">
  5 + <span>{{ $t('ownerVoting.add.title') }}</span>
  6 + </div>
  7 + <el-form
  8 + ref="form"
  9 + :model="form"
  10 + :rules="rules"
  11 + label-width="120px"
  12 + label-position="right"
  13 + >
  14 + <el-form-item
  15 + :label="$t('ownerVoting.form.qaName')"
  16 + prop="qaName"
  17 + >
  18 + <el-input
  19 + v-model="form.qaName"
  20 + :placeholder="$t('ownerVoting.form.qaNamePlaceholder')"
  21 + style="width: 100%"
  22 + />
  23 + </el-form-item>
  24 +
  25 + <el-form-item
  26 + :label="$t('ownerVoting.form.type')"
  27 + prop="titleType"
  28 + >
  29 + <el-select
  30 + v-model="form.titleType"
  31 + :placeholder="$t('ownerVoting.form.typePlaceholder')"
  32 + style="width: 100%"
  33 + >
  34 + <el-option
  35 + :label="$t('ownerVoting.type.single')"
  36 + value="1001"
  37 + />
  38 + <el-option
  39 + :label="$t('ownerVoting.type.multiple')"
  40 + value="2002"
  41 + />
  42 + </el-select>
  43 + </el-form-item>
  44 +
  45 + <el-form-item
  46 + :label="$t('ownerVoting.form.startTime')"
  47 + prop="startTime"
  48 + >
  49 + <el-date-picker
  50 + v-model="form.startTime"
  51 + type="datetime"
  52 + :placeholder="$t('ownerVoting.form.startTimePlaceholder')"
  53 + style="width: 100%"
  54 + />
  55 + </el-form-item>
  56 +
  57 + <el-form-item
  58 + :label="$t('ownerVoting.form.endTime')"
  59 + prop="endTime"
  60 + >
  61 + <el-date-picker
  62 + v-model="form.endTime"
  63 + type="datetime"
  64 + :placeholder="$t('ownerVoting.form.endTimePlaceholder')"
  65 + style="width: 100%"
  66 + />
  67 + </el-form-item>
  68 +
  69 + <el-form-item
  70 + :label="$t('ownerVoting.form.options')"
  71 + prop="titleValues"
  72 + >
  73 + <div
  74 + v-for="(item, index) in form.titleValues"
  75 + :key="index"
  76 + class="option-item"
  77 + >
  78 + <el-input
  79 + v-model="item.qaValue"
  80 + :placeholder="$t('ownerVoting.form.optionPlaceholder', { num: index + 1 })"
  81 + style="width: 80%; margin-right: 10px"
  82 + />
  83 + <el-button
  84 + v-if="index > 0"
  85 + type="danger"
  86 + icon="el-icon-minus"
  87 + circle
  88 + @click="removeOption(index)"
  89 + />
  90 + </div>
  91 + <el-button
  92 + type="primary"
  93 + icon="el-icon-plus"
  94 + @click="addOption"
  95 + >
  96 + {{ $t('ownerVoting.form.addOption') }}
  97 + </el-button>
  98 + </el-form-item>
  99 +
  100 + <el-form-item>
  101 + <el-button
  102 + type="primary"
  103 + @click="submitForm"
  104 + >
  105 + {{ $t('common.submit') }}
  106 + </el-button>
  107 + <el-button @click="cancel">
  108 + {{ $t('common.cancel') }}
  109 + </el-button>
  110 + </el-form-item>
  111 + </el-form>
  112 + </el-card>
  113 + </div>
  114 +</template>
  115 +
  116 +<script>
  117 +import { addOwnerVote } from '@/api/oa/ownerVotingApi'
  118 +import { getCommunityId } from '@/api/community/communityApi'
  119 +
  120 +export default {
  121 + name: 'AddOwnerVoting',
  122 + data() {
  123 + return {
  124 + form: {
  125 + qaName: '',
  126 + titleType: '1001',
  127 + startTime: '',
  128 + endTime: '',
  129 + titleValues: [
  130 + { qaValue: '', seq: 1 }
  131 + ],
  132 + communityId: getCommunityId()
  133 + },
  134 + rules: {
  135 + qaName: [
  136 + { required: true, message: this.$t('ownerVoting.validate.qaName'), trigger: 'blur' }
  137 + ],
  138 + titleType: [
  139 + { required: true, message: this.$t('ownerVoting.validate.type'), trigger: 'change' }
  140 + ],
  141 + startTime: [
  142 + { required: true, message: this.$t('ownerVoting.validate.startTime'), trigger: 'change' }
  143 + ],
  144 + endTime: [
  145 + { required: true, message: this.$t('ownerVoting.validate.endTime'), trigger: 'change' },
  146 + { validator: this.validateEndTime, trigger: 'change' }
  147 + ],
  148 + titleValues: [
  149 + { validator: this.validateOptions, trigger: 'change' }
  150 + ]
  151 + }
  152 + }
  153 + },
  154 + methods: {
  155 + validateEndTime(rule, value, callback) {
  156 + if (!value) {
  157 + callback(new Error(this.$t('ownerVoting.validate.endTime')))
  158 + return
  159 + }
  160 + if (new Date(value) <= new Date(this.form.startTime)) {
  161 + callback(new Error(this.$t('ownerVoting.validate.endTimeAfterStart')))
  162 + } else {
  163 + callback()
  164 + }
  165 + },
  166 + validateOptions(rule, value, callback) {
  167 + if (value.length < 1) {
  168 + callback(new Error(this.$t('ownerVoting.validate.atLeastOneOption')))
  169 + return
  170 + }
  171 + for (let i = 0; i < value.length; i++) {
  172 + if (!value[i].qaValue || value[i].qaValue.trim() === '') {
  173 + callback(new Error(this.$t('ownerVoting.validate.optionNotEmpty')))
  174 + return
  175 + }
  176 + }
  177 + callback()
  178 + },
  179 + addOption() {
  180 + this.form.titleValues.push({
  181 + qaValue: '',
  182 + seq: this.form.titleValues.length + 1
  183 + })
  184 + },
  185 + removeOption(index) {
  186 + this.form.titleValues.splice(index, 1)
  187 + // 重新排序
  188 + this.form.titleValues.forEach((item, i) => {
  189 + item.seq = i + 1
  190 + })
  191 + },
  192 + submitForm() {
  193 + this.$refs.form.validate(async valid => {
  194 + if (valid) {
  195 + try {
  196 + await addOwnerVote(this.form)
  197 + this.$message.success(this.$t('ownerVoting.add.success'))
  198 + this.$router.push('/views/oa/ownerVotingList')
  199 + } catch (error) {
  200 + this.$message.error(error.message || this.$t('ownerVoting.add.error'))
  201 + }
  202 + }
  203 + })
  204 + },
  205 + cancel() {
  206 + this.$router.push('/views/oa/ownerVotingList')
  207 + }
  208 + }
  209 +}
  210 +</script>
  211 +
  212 +<style lang="scss" scoped>
  213 +.add-owner-voting-container {
  214 + padding: 20px;
  215 +
  216 + .option-item {
  217 + display: flex;
  218 + align-items: center;
  219 + margin-bottom: 10px;
  220 + }
  221 +}
  222 +</style>
0 223 \ No newline at end of file
... ...
src/components/oa/deleteExamineProject.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('examineProjectManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div class="delete-content">
  9 + <i class="el-icon-warning" style="color:#E6A23C;font-size:24px;vertical-align:middle"></i>
  10 + <span style="margin-left:10px;vertical-align:middle">
  11 + {{ $t('examineProjectManage.delete.confirmText') }}
  12 + </span>
  13 + </div>
  14 + <span slot="footer" class="dialog-footer">
  15 + <el-button @click="visible = false">
  16 + {{ $t('common.cancel') }}
  17 + </el-button>
  18 + <el-button type="primary" @click="handleConfirm" :loading="loading">
  19 + {{ $t('common.confirm') }}
  20 + </el-button>
  21 + </span>
  22 + </el-dialog>
  23 +</template>
  24 +
  25 +<script>
  26 +import { deleteExamineProject } from '@/api/oa/examineProjectManageApi'
  27 +import { getCommunityId } from '@/api/community/communityApi'
  28 +
  29 +export default {
  30 + name: 'DeleteExamineProject',
  31 + data() {
  32 + return {
  33 + visible: false,
  34 + loading: false,
  35 + formData: {
  36 + projectId: '',
  37 + communityId: getCommunityId()
  38 + }
  39 + }
  40 + },
  41 + methods: {
  42 + open(data) {
  43 + this.formData.projectId = data.projectId
  44 + this.visible = true
  45 + },
  46 + handleClose() {
  47 + this.loading = false
  48 + },
  49 + async handleConfirm() {
  50 + try {
  51 + this.loading = true
  52 + await deleteExamineProject(this.formData)
  53 + this.$message.success(this.$t('examineProjectManage.delete.success'))
  54 + this.visible = false
  55 + this.$emit('success')
  56 + } catch (error) {
  57 + this.$message.error(error.message || this.$t('examineProjectManage.delete.error'))
  58 + } finally {
  59 + this.loading = false
  60 + }
  61 + }
  62 + }
  63 +}
  64 +</script>
  65 +
  66 +<style scoped>
  67 +.delete-content {
  68 + padding: 20px 0;
  69 + text-align: center;
  70 +}
  71 +</style>
0 72 \ No newline at end of file
... ...
src/components/oa/deleteExamineStaff.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('examineStaffManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div style="text-align: center;">
  9 + <p>{{ $t('examineStaffManage.delete.confirm') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="visible = false">
  13 + {{ $t('common.cancel') }}
  14 + </el-button>
  15 + <el-button type="primary" @click="handleConfirm">
  16 + {{ $t('common.confirm') }}
  17 + </el-button>
  18 + </span>
  19 + </el-dialog>
  20 +</template>
  21 +
  22 +<script>
  23 +import { deleteExamineStaff } from '@/api/oa/examineStaffManageApi'
  24 +import { getCommunityId } from '@/api/community/communityApi'
  25 +
  26 +export default {
  27 + name: 'DeleteExamineStaff',
  28 + data() {
  29 + return {
  30 + visible: false,
  31 + currentRow: null
  32 + }
  33 + },
  34 + methods: {
  35 + open(row) {
  36 + this.currentRow = row
  37 + this.visible = true
  38 + },
  39 + handleClose() {
  40 + this.currentRow = null
  41 + },
  42 + async handleConfirm() {
  43 + try {
  44 + const params = {
  45 + ...this.currentRow,
  46 + communityId: getCommunityId()
  47 + }
  48 + await deleteExamineStaff(params)
  49 + this.$emit('success')
  50 + this.visible = false
  51 + this.$message.success(this.$t('examineStaffManage.delete.success'))
  52 + } catch (error) {
  53 + this.$message.error(this.$t('examineStaffManage.delete.error'))
  54 + }
  55 + }
  56 + }
  57 +}
  58 +</script>
0 59 \ No newline at end of file
... ...
src/components/oa/deleteOwnerVoting.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('ownerVoting.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div>
  9 + <p>{{ $t('ownerVoting.delete.confirm') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="visible = false">
  13 + {{ $t('common.cancel') }}
  14 + </el-button>
  15 + <el-button
  16 + type="danger"
  17 + @click="handleConfirm"
  18 + >
  19 + {{ $t('common.confirm') }}
  20 + </el-button>
  21 + </span>
  22 + </el-dialog>
  23 +</template>
  24 +
  25 +<script>
  26 +import { deleteOwnerVote } from '@/api/oa/ownerVotingApi'
  27 +import { getCommunityId } from '@/api/community/communityApi'
  28 +
  29 +export default {
  30 + name: 'DeleteOwnerVoting',
  31 + data() {
  32 + return {
  33 + visible: false,
  34 + qaId: '',
  35 + communityId: getCommunityId()
  36 + }
  37 + },
  38 + methods: {
  39 + open(qaId) {
  40 + this.qaId = qaId
  41 + this.visible = true
  42 + },
  43 + async handleConfirm() {
  44 + try {
  45 + await deleteOwnerVote({
  46 + qaId: this.qaId,
  47 + communityId: this.communityId
  48 + })
  49 + this.$message.success(this.$t('ownerVoting.delete.success'))
  50 + this.$emit('success')
  51 + this.visible = false
  52 + } catch (error) {
  53 + this.$message.error(error.message || this.$t('ownerVoting.delete.error'))
  54 + }
  55 + },
  56 + handleClose() {
  57 + this.qaId = ''
  58 + }
  59 + }
  60 +}
  61 +</script>
0 62 \ No newline at end of file
... ...
src/components/oa/deleteQuestionAnswer.vue
1 1 <template>
2 2 <el-dialog
3   - :title="$t('questionAnswerManage.delete.title')"
  3 + :title="$t('ownerVoting.deleteQuestionAnswer.title')"
4 4 :visible.sync="visible"
5 5 width="30%"
6 6 @close="handleClose"
7 7 >
8   - <div class="delete-content">
9   - <i class="el-icon-warning" style="color: #e6a23c; font-size: 24px;"></i>
10   - <span style="margin-left: 10px;">{{ $t('questionAnswerManage.delete.confirmText') }}</span>
  8 + <div>
  9 + <p>{{ $t('ownerVoting.deleteQuestionAnswer.confirm') }}</p>
11 10 </div>
12   -
13   - <div slot="footer" class="dialog-footer">
  11 + <span slot="footer" class="dialog-footer">
14 12 <el-button @click="visible = false">
15 13 {{ $t('common.cancel') }}
16 14 </el-button>
17   - <el-button type="primary" @click="handleConfirm" :loading="loading">
  15 + <el-button
  16 + type="danger"
  17 + @click="handleConfirm"
  18 + >
18 19 {{ $t('common.confirm') }}
19 20 </el-button>
20   - </div>
  21 + </span>
21 22 </el-dialog>
22 23 </template>
23 24  
24 25 <script>
25   -import { deleteQuestionAnswer } from '@/api/oa/questionAnswerManageApi'
  26 +import { deleteQuestionAnswer } from '@/api/oa/ownerVotingApi'
26 27 import { getCommunityId } from '@/api/community/communityApi'
27 28  
28 29 export default {
... ... @@ -30,48 +31,31 @@ export default {
30 31 data() {
31 32 return {
32 33 visible: false,
33   - loading: false,
34   - currentData: null
  34 + qaId: '',
  35 + communityId: getCommunityId()
35 36 }
36 37 },
37 38 methods: {
38   - open(data) {
39   - this.currentData = data
  39 + open(qaId) {
  40 + this.qaId = qaId
40 41 this.visible = true
41 42 },
42   - handleClose() {
43   - this.currentData = null
44   - this.loading = false
45   - },
46 43 async handleConfirm() {
47   - if (!this.currentData) return
48   -
49 44 try {
50   - this.loading = true
51   - const params = {
52   - qaId: this.currentData.qaId,
53   - communityId: getCommunityId()
54   - }
55   - await deleteQuestionAnswer(params)
56   - this.$message.success(this.$t('questionAnswerManage.message.deleteSuccess'))
57   - this.visible = false
  45 + await deleteQuestionAnswer({
  46 + qaId: this.qaId,
  47 + communityId: this.communityId
  48 + })
  49 + this.$message.success(this.$t('ownerVoting.deleteQuestionAnswer.success'))
58 50 this.$emit('success')
  51 + this.visible = false
59 52 } catch (error) {
60   - this.$message.error(error.message || this.$t('questionAnswerManage.message.deleteError'))
61   - } finally {
62   - this.loading = false
  53 + this.$message.error(error.message || this.$t('ownerVoting.deleteQuestionAnswer.error'))
63 54 }
  55 + },
  56 + handleClose() {
  57 + this.qaId = ''
64 58 }
65 59 }
66 60 }
67   -</script>
68   -
69   -<style lang="scss" scoped>
70   -.delete-content {
71   - display: flex;
72   - align-items: center;
73   - justify-content: center;
74   - padding: 20px 0;
75   - font-size: 16px;
76   -}
77   -</style>
78 61 \ No newline at end of file
  62 +</script>
79 63 \ No newline at end of file
... ...
src/components/oa/editExamineProject.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('examineProjectManage.edit.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + label-position="right"
  14 + >
  15 + <el-form-item
  16 + :label="$t('examineProjectManage.form.name')"
  17 + prop="name"
  18 + >
  19 + <el-input
  20 + v-model="formData.name"
  21 + :placeholder="$t('examineProjectManage.form.namePlaceholder')"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item
  25 + :label="$t('examineProjectManage.form.post')"
  26 + prop="postCd"
  27 + >
  28 + <el-select
  29 + v-model="formData.postCd"
  30 + :placeholder="$t('examineProjectManage.form.postPlaceholder')"
  31 + style="width:100%"
  32 + >
  33 + <el-option
  34 + :label="$t('examineProjectManage.form.commonPost')"
  35 + value="9999"
  36 + />
  37 + </el-select>
  38 + </el-form-item>
  39 + <el-form-item
  40 + :label="$t('examineProjectManage.form.weight')"
  41 + prop="weight"
  42 + >
  43 + <el-input
  44 + v-model="formData.weight"
  45 + :placeholder="$t('examineProjectManage.form.weightPlaceholder')"
  46 + style="width:80%"
  47 + >
  48 + <template slot="append">%</template>
  49 + </el-input>
  50 + </el-form-item>
  51 + <el-form-item
  52 + :label="$t('examineProjectManage.form.state')"
  53 + prop="state"
  54 + >
  55 + <el-select
  56 + v-model="formData.state"
  57 + :placeholder="$t('examineProjectManage.form.statePlaceholder')"
  58 + style="width:100%"
  59 + >
  60 + <el-option
  61 + :label="$t('examineProjectManage.status.enable')"
  62 + value="Y"
  63 + />
  64 + <el-option
  65 + :label="$t('examineProjectManage.status.disable')"
  66 + value="N"
  67 + />
  68 + </el-select>
  69 + </el-form-item>
  70 + </el-form>
  71 + <span slot="footer" class="dialog-footer">
  72 + <el-button @click="visible = false">
  73 + {{ $t('common.cancel') }}
  74 + </el-button>
  75 + <el-button type="primary" @click="handleSubmit">
  76 + {{ $t('common.confirm') }}
  77 + </el-button>
  78 + </span>
  79 + </el-dialog>
  80 +</template>
  81 +
  82 +<script>
  83 +import { updateExamineProject } from '@/api/oa/examineProjectManageApi'
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +
  86 +export default {
  87 + name: 'EditExamineProject',
  88 + data() {
  89 + return {
  90 + visible: false,
  91 + formData: {
  92 + projectId: '',
  93 + name: '',
  94 + postCd: '',
  95 + post: this.$t('examineProjectManage.form.commonPost'),
  96 + weight: '',
  97 + state: '',
  98 + communityId: getCommunityId()
  99 + },
  100 + rules: {
  101 + projectId: [
  102 + { required: true, message: this.$t('examineProjectManage.validate.idRequired'), trigger: 'blur' }
  103 + ],
  104 + name: [
  105 + { required: true, message: this.$t('examineProjectManage.validate.nameRequired'), trigger: 'blur' },
  106 + { max: 64, message: this.$t('examineProjectManage.validate.nameMaxLength'), trigger: 'blur' }
  107 + ],
  108 + postCd: [
  109 + { required: true, message: this.$t('examineProjectManage.validate.postRequired'), trigger: 'change' },
  110 + { max: 30, message: this.$t('examineProjectManage.validate.postMaxLength'), trigger: 'blur' }
  111 + ],
  112 + weight: [
  113 + { required: true, message: this.$t('examineProjectManage.validate.weightRequired'), trigger: 'blur' },
  114 + { max: 12, message: this.$t('examineProjectManage.validate.weightMaxLength'), trigger: 'blur' }
  115 + ],
  116 + state: [
  117 + { required: true, message: this.$t('examineProjectManage.validate.stateRequired'), trigger: 'change' },
  118 + { max: 12, message: this.$t('examineProjectManage.validate.stateMaxLength'), trigger: 'blur' }
  119 + ]
  120 + }
  121 + }
  122 + },
  123 + methods: {
  124 + open(data) {
  125 + this.formData = {
  126 + ...data,
  127 + communityId: getCommunityId()
  128 + }
  129 + this.visible = true
  130 + },
  131 + handleClose() {
  132 + this.$refs.form.resetFields()
  133 + },
  134 + handleSubmit() {
  135 + this.$refs.form.validate(async valid => {
  136 + if (valid) {
  137 + try {
  138 + await updateExamineProject(this.formData)
  139 + this.$message.success(this.$t('examineProjectManage.edit.success'))
  140 + this.visible = false
  141 + this.$emit('success')
  142 + } catch (error) {
  143 + this.$message.error(error.message || this.$t('examineProjectManage.edit.error'))
  144 + }
  145 + }
  146 + })
  147 + }
  148 + }
  149 +}
  150 +</script>
0 151 \ No newline at end of file
... ...
src/components/oa/editOwnerVoting.vue 0 → 100644
  1 +<template>
  2 + <div class="edit-owner-voting-container">
  3 + <el-card>
  4 + <div slot="header">
  5 + <span>{{ $t('ownerVoting.edit.title') }}</span>
  6 + </div>
  7 + <el-form
  8 + ref="form"
  9 + :model="form"
  10 + :rules="rules"
  11 + label-width="120px"
  12 + label-position="right"
  13 + >
  14 + <el-form-item
  15 + :label="$t('ownerVoting.form.qaName')"
  16 + prop="qaName"
  17 + >
  18 + <el-input
  19 + v-model="form.qaName"
  20 + :placeholder="$t('ownerVoting.form.qaNamePlaceholder')"
  21 + style="width: 100%"
  22 + />
  23 + </el-form-item>
  24 +
  25 + <el-form-item
  26 + :label="$t('ownerVoting.form.type')"
  27 + prop="titleType"
  28 + >
  29 + <el-select
  30 + v-model="form.titleType"
  31 + :placeholder="$t('ownerVoting.form.typePlaceholder')"
  32 + style="width: 100%"
  33 + disabled
  34 + >
  35 + <el-option
  36 + :label="$t('ownerVoting.type.single')"
  37 + value="1001"
  38 + />
  39 + <el-option
  40 + :label="$t('ownerVoting.type.multiple')"
  41 + value="2002"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 +
  46 + <el-form-item
  47 + :label="$t('ownerVoting.form.startTime')"
  48 + prop="startTime"
  49 + >
  50 + <el-date-picker
  51 + v-model="form.startTime"
  52 + type="datetime"
  53 + :placeholder="$t('ownerVoting.form.startTimePlaceholder')"
  54 + style="width: 100%"
  55 + disabled
  56 + />
  57 + </el-form-item>
  58 +
  59 + <el-form-item
  60 + :label="$t('ownerVoting.form.endTime')"
  61 + prop="endTime"
  62 + >
  63 + <el-date-picker
  64 + v-model="form.endTime"
  65 + type="datetime"
  66 + :placeholder="$t('ownerVoting.form.endTimePlaceholder')"
  67 + style="width: 100%"
  68 + disabled
  69 + />
  70 + </el-form-item>
  71 +
  72 + <el-form-item
  73 + :label="$t('ownerVoting.form.options')"
  74 + prop="titleValues"
  75 + >
  76 + <div
  77 + v-for="(item, index) in form.titleValues"
  78 + :key="index"
  79 + class="option-item"
  80 + >
  81 + <el-input
  82 + v-model="item.qaValue"
  83 + :placeholder="$t('ownerVoting.form.optionPlaceholder', { num: index + 1 })"
  84 + style="width: 80%; margin-right: 10px"
  85 + disabled
  86 + />
  87 + </div>
  88 + </el-form-item>
  89 +
  90 + <el-form-item>
  91 + <el-button @click="cancel">
  92 + {{ $t('common.back') }}
  93 + </el-button>
  94 + </el-form-item>
  95 + </el-form>
  96 + </el-card>
  97 + </div>
  98 +</template>
  99 +
  100 +<script>
  101 +import { getOwnerVoteDetail } from '@/api/oa/ownerVotingApi'
  102 +
  103 +export default {
  104 + name: 'EditOwnerVoting',
  105 + data() {
  106 + return {
  107 + form: {
  108 + qaId: '',
  109 + qaName: '',
  110 + titleType: '',
  111 + startTime: '',
  112 + endTime: '',
  113 + titleValues: []
  114 + },
  115 + rules: {
  116 + qaName: [
  117 + { required: true, message: this.$t('ownerVoting.validate.qaName'), trigger: 'blur' }
  118 + ]
  119 + }
  120 + }
  121 + },
  122 + created() {
  123 + this.getDetail()
  124 + },
  125 + methods: {
  126 + async getDetail() {
  127 + try {
  128 + const qaId = this.$route.query.qaId
  129 + if (!qaId) {
  130 + this.$message.error(this.$t('ownerVoting.edit.noId'))
  131 + this.$router.push('/views/oa/ownerVotingList')
  132 + return
  133 + }
  134 +
  135 + const data = await getOwnerVoteDetail({ qaId })
  136 + this.form = {
  137 + ...data,
  138 + titleValues: data.titleValues.map((item, index) => ({
  139 + ...item,
  140 + seq: index + 1
  141 + }))
  142 + }
  143 + } catch (error) {
  144 + this.$message.error(error.message || this.$t('ownerVoting.edit.fetchError'))
  145 + this.$router.push('/views/oa/ownerVotingList')
  146 + }
  147 + },
  148 + cancel() {
  149 + this.$router.push('/views/oa/ownerVotingList')
  150 + }
  151 + }
  152 +}
  153 +</script>
  154 +
  155 +<style lang="scss" scoped>
  156 +.edit-owner-voting-container {
  157 + padding: 20px;
  158 +
  159 + .option-item {
  160 + display: flex;
  161 + align-items: center;
  162 + margin-bottom: 10px;
  163 + }
  164 +}
  165 +</style>
0 166 \ No newline at end of file
... ...
src/components/oa/orgTreeShow.vue 0 → 100644
  1 +<template>
  2 + <div class="org-tree-show-container">
  3 + <el-tree
  4 + ref="orgTree"
  5 + :data="orgTreeShowInfo.orgs"
  6 + :props="defaultProps"
  7 + node-key="id"
  8 + default-expand-all
  9 + highlight-current
  10 + @node-click="handleNodeClick">
  11 + </el-tree>
  12 + </div>
  13 +</template>
  14 +
  15 +<script>
  16 +import { listOrgTree } from '@/api/oa/addExamineStaffApi'
  17 +import { getCommunityId } from '@/api/community/communityApi'
  18 +
  19 +export default {
  20 + name: 'OrgTreeShow',
  21 + props: {
  22 + callBackListener: {
  23 + type: String,
  24 + default: ''
  25 + }
  26 + },
  27 + data() {
  28 + return {
  29 + orgTreeShowInfo: {
  30 + orgs: [],
  31 + orgId: '',
  32 + curOrg: {}
  33 + },
  34 + defaultProps: {
  35 + children: 'children',
  36 + label: 'text'
  37 + }
  38 + }
  39 + },
  40 + mounted() {
  41 + this._loadOrgsShow()
  42 + },
  43 + methods: {
  44 + refreshTree() {
  45 + this._loadOrgsShow()
  46 + },
  47 + async _loadOrgsShow() {
  48 + try {
  49 + const params = {
  50 + communityId: getCommunityId()
  51 + }
  52 + const res = await listOrgTree(params)
  53 + this.orgTreeShowInfo.orgs = res.data
  54 + } catch (error) {
  55 + console.error('加载组织树失败:', error)
  56 + }
  57 + },
  58 + handleNodeClick(data) {
  59 + this.orgTreeShowInfo.curOrg = data
  60 + this.orgTreeShowInfo.curOrg.orgId = data.id
  61 + this.$emit(this.callBackListener, 'switchOrg', {
  62 + orgId: data.id,
  63 + orgName: data.text
  64 + })
  65 + }
  66 + }
  67 +}
  68 +</script>
  69 +
  70 +<style lang="scss" scoped>
  71 +.org-tree-show-container {
  72 + height: 100%;
  73 +
  74 + /deep/ .el-tree {
  75 + height: 100%;
  76 + overflow-y: auto;
  77 +
  78 + .el-tree-node__content {
  79 + height: 36px;
  80 + line-height: 36px;
  81 + }
  82 +
  83 + .el-tree-node.is-current > .el-tree-node__content {
  84 + background-color: #f0f7ff;
  85 + }
  86 + }
  87 +}
  88 +</style>
0 89 \ No newline at end of file
... ...
src/components/oa/publishQuestionAnswer.vue
1 1 <template>
2 2 <el-dialog
3   - :title="$t('questionAnswerManage.publish.title')"
  3 + :title="$t('ownerVoting.publish.title')"
4 4 :visible.sync="visible"
5   - width="40%"
  5 + width="50%"
6 6 @close="handleClose"
7 7 >
8   - <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
9   - <el-form-item :label="$t('questionAnswerManage.publish.qaName')">
10   - <el-input v-model="formData.qaName" disabled />
  8 + <el-form ref="form" :model="form" :rules="rules">
  9 + <el-form-item
  10 + :label="$t('ownerVoting.publish.name')"
  11 + prop="qaName"
  12 + label-width="120px"
  13 + >
  14 + <el-input v-model="form.qaName" disabled style="width: 100%" />
11 15 </el-form-item>
12   -
13   - <el-form-item :label="$t('questionAnswerManage.publish.tip')">
  16 +
  17 + <el-form-item
  18 + :label="$t('ownerVoting.publish.tip')"
  19 + label-width="120px"
  20 + >
14 21 <el-input
15   - :value="$t('questionAnswerManage.publish.tipText')"
  22 + :value="$t('ownerVoting.publish.tipContent')"
16 23 disabled
  24 + style="width: 100%"
17 25 />
18 26 </el-form-item>
19   -
  27 +
20 28 <el-form-item
21   - :label="$t('questionAnswerManage.publish.notifyWay')"
  29 + :label="$t('ownerVoting.publish.notifyWay')"
22 30 prop="notifyWay"
  31 + label-width="120px"
23 32 >
24 33 <el-select
25   - v-model="formData.notifyWay"
26   - :placeholder="$t('questionAnswerManage.publish.notifyWayPlaceholder')"
  34 + v-model="form.notifyWay"
  35 + :placeholder="$t('ownerVoting.publish.notifyWayPlaceholder')"
27 36 style="width: 100%"
28 37 >
29 38 <el-option
  39 + :label="$t('ownerVoting.publish.sms')"
30 40 value="1001"
31   - :label="$t('questionAnswerManage.publish.notifyWay1')"
32 41 />
33 42 <el-option
  43 + :label="$t('ownerVoting.publish.wechat')"
34 44 value="2002"
35   - :label="$t('questionAnswerManage.publish.notifyWay2')"
36 45 />
37 46 <el-option
  47 + :label="$t('ownerVoting.publish.noNotify')"
38 48 value="3003"
39   - :label="$t('questionAnswerManage.publish.notifyWay3')"
40 49 />
41 50 </el-select>
42 51 </el-form-item>
43 52 </el-form>
44   -
45   - <div slot="footer" class="dialog-footer">
  53 +
  54 + <span slot="footer" class="dialog-footer">
46 55 <el-button @click="visible = false">
47 56 {{ $t('common.cancel') }}
48 57 </el-button>
49   - <el-button type="primary" @click="handlePublish" :loading="loading">
50   - {{ $t('questionAnswerManage.publish.button') }}
  58 + <el-button
  59 + type="primary"
  60 + @click="handleConfirm"
  61 + >
  62 + {{ $t('ownerVoting.publish.publishBtn') }}
51 63 </el-button>
52   - </div>
  64 + </span>
53 65 </el-dialog>
54 66 </template>
55 67  
56 68 <script>
57   -import { publishQuestionAnswer } from '@/api/oa/questionAnswerManageApi'
  69 +import { publishQuestion } from '@/api/oa/ownerVotingApi'
58 70 import { getCommunityId } from '@/api/community/communityApi'
59 71  
60 72 export default {
... ... @@ -62,59 +74,50 @@ export default {
62 74 data() {
63 75 return {
64 76 visible: false,
65   - loading: false,
66   - formData: {
  77 + form: {
67 78 qaId: '',
68 79 qaName: '',
69   - notifyWay: ''
  80 + notifyWay: '',
  81 + communityId: getCommunityId()
70 82 },
71 83 rules: {
72 84 notifyWay: [
73   - { required: true, message: this.$t('questionAnswerManage.validate.notifyWay'), trigger: 'blur' }
  85 + { required: true, message: this.$t('ownerVoting.publish.notifyWayRequired'), trigger: 'change' }
74 86 ]
75 87 }
76 88 }
77 89 },
78 90 methods: {
79 91 open(data) {
80   - this.formData = {
  92 + this.form = {
  93 + ...this.form,
81 94 qaId: data.qaId,
82   - qaName: data.qaName,
83   - notifyWay: ''
  95 + qaName: data.qaName
84 96 }
85 97 this.visible = true
86   - this.$nextTick(() => {
87   - this.$refs.form && this.$refs.form.clearValidate()
  98 + },
  99 + async handleConfirm() {
  100 + this.$refs.form.validate(async valid => {
  101 + if (valid) {
  102 + try {
  103 + await publishQuestion(this.form)
  104 + this.$message.success(this.$t('ownerVoting.publish.success'))
  105 + this.$emit('success')
  106 + this.visible = false
  107 + } catch (error) {
  108 + this.$message.error(error.message || this.$t('ownerVoting.publish.error'))
  109 + }
  110 + }
88 111 })
89 112 },
90 113 handleClose() {
91   - this.formData = {
  114 + this.$refs.form.resetFields()
  115 + this.form = {
92 116 qaId: '',
93 117 qaName: '',
94   - notifyWay: ''
  118 + notifyWay: '',
  119 + communityId: getCommunityId()
95 120 }
96   - this.loading = false
97   - },
98   - async handlePublish() {
99   - this.$refs.form.validate(async valid => {
100   - if (!valid) return
101   -
102   - try {
103   - this.loading = true
104   - const params = {
105   - ...this.formData,
106   - communityId: getCommunityId()
107   - }
108   - await publishQuestionAnswer(params)
109   - this.$message.success(this.$t('questionAnswerManage.message.publishSuccess'))
110   - this.visible = false
111   - this.$emit('success')
112   - } catch (error) {
113   - this.$message.error(error.message || this.$t('questionAnswerManage.message.publishError'))
114   - } finally {
115   - this.loading = false
116   - }
117   - })
118 121 }
119 122 }
120 123 }
... ...
src/components/oa/selectStaff.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('selectStaff.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="70%"
  6 + :close-on-click-modal="false">
  7 +
  8 + <el-row :gutter="20">
  9 + <el-col :span="12" class="border-right">
  10 + <div class="text-center section-title">
  11 + {{ $t('selectStaff.orgInfo') }}
  12 + </div>
  13 + <div class="org-tree-container">
  14 + <org-tree-show
  15 + ref="orgTree"
  16 + :call-back-listener="'selectStaff'">
  17 + </org-tree-show>
  18 + </div>
  19 + </el-col>
  20 +
  21 + <el-col :span="12">
  22 + <div class="text-center section-title">
  23 + {{ $t('selectStaff.staffInfo') }}
  24 + </div>
  25 + <div class="staff-list-container">
  26 + <div
  27 + v-for="(item, index) in selectStaffInfo.staffs"
  28 + :key="index"
  29 + class="staff-item"
  30 + :class="{ 'selected': selectStaffInfo.curStaffId === item.staffId }"
  31 + @click="_changeStaff(item)">
  32 + <div>
  33 + <i class="el-icon-user margin-right-xs"></i>
  34 + {{ item.name }}
  35 + </div>
  36 + <div>{{ item.tel }}</div>
  37 + </div>
  38 + </div>
  39 + </el-col>
  40 + </el-row>
  41 +
  42 + <div
  43 + v-if="selectStaffInfo.staff.from === 'bpmn' ||
  44 + selectStaffInfo.staff.from === 'purchase' ||
  45 + selectStaffInfo.staff.from === 'contract'"
  46 + class="dialog-footer text-right">
  47 + <el-button size="small" @click="_firstUser">
  48 + {{ $t('selectStaff.submitter') }}
  49 + </el-button>
  50 + <el-button size="small" @click="_customUser">
  51 + {{ $t('selectStaff.dynamicAssign') }}
  52 + </el-button>
  53 + </div>
  54 + </el-dialog>
  55 +</template>
  56 +
  57 +<script>
  58 +import { queryStaffInfos } from '@/api/oa/addExamineStaffApi'
  59 +import OrgTreeShow from '@/components/oa/OrgTreeShow'
  60 +
  61 +export default {
  62 + name: 'SelectStaff',
  63 + components: {
  64 + OrgTreeShow
  65 + },
  66 + data() {
  67 + return {
  68 + dialogVisible: false,
  69 + selectStaffInfo: {
  70 + staffs: [],
  71 + curStaffId: '',
  72 + curStaffName: '',
  73 + staff: {}
  74 + }
  75 + }
  76 + },
  77 + mounted() {
  78 + this.$on('selectStaff', 'switchOrg', this.loadStaff)
  79 + },
  80 + methods: {
  81 + open(staff) {
  82 + this.selectStaffInfo.staff = staff
  83 + this.dialogVisible = true
  84 + this.$refs.orgTree.refreshTree()
  85 + },
  86 + async loadStaff(org) {
  87 + try {
  88 + const params = {
  89 + page: 1,
  90 + row: 50,
  91 + orgId: org.orgId
  92 + }
  93 + const res = await queryStaffInfos(params)
  94 + this.selectStaffInfo.staffs = res.staffs
  95 + if (res.staffs.length > 0) {
  96 + this.selectStaffInfo.curStaffId = res.staffs[0].orgId
  97 + }
  98 + } catch (error) {
  99 + console.error('加载员工失败:', error)
  100 + }
  101 + },
  102 + _changeStaff(item) {
  103 + this.selectStaffInfo.staff.staffId = item.userId
  104 + this.selectStaffInfo.staff.staffName = item.userName
  105 + this.selectStaffInfo.staff.staffTel = item.tel
  106 + this.dialogVisible = false
  107 +
  108 + if (typeof this.selectStaffInfo.staff.call === 'function') {
  109 + this.selectStaffInfo.staff.call(this.selectStaffInfo.staff)
  110 + }
  111 + },
  112 + _firstUser() {
  113 + this.selectStaffInfo.staff.staffId = '${startUserId}'
  114 + this.selectStaffInfo.staff.staffName = this.$t('selectStaff.submitter')
  115 + this.dialogVisible = false
  116 +
  117 + if (typeof this.selectStaffInfo.staff.call === 'function') {
  118 + this.selectStaffInfo.staff.call(this.selectStaffInfo.staff)
  119 + }
  120 + },
  121 + _customUser() {
  122 + this.selectStaffInfo.staff.staffId = '${nextUserId}'
  123 + this.selectStaffInfo.staff.staffName = this.$t('selectStaff.dynamicAssign')
  124 + this.dialogVisible = false
  125 +
  126 + if (typeof this.selectStaffInfo.staff.call === 'function') {
  127 + this.selectStaffInfo.staff.call(this.selectStaffInfo.staff)
  128 + }
  129 + }
  130 + }
  131 +}
  132 +</script>
  133 +
  134 +<style lang="scss" scoped>
  135 +.border-right {
  136 + border-right: 1px solid #ebeef5;
  137 +}
  138 +
  139 +.section-title {
  140 + font-weight: bold;
  141 + margin-bottom: 15px;
  142 + font-size: 16px;
  143 +}
  144 +
  145 +.org-tree-container {
  146 + height: 400px;
  147 + overflow-y: auto;
  148 + padding: 10px;
  149 +}
  150 +
  151 +.staff-list-container {
  152 + height: 400px;
  153 + overflow-y: auto;
  154 + padding: 10px;
  155 +}
  156 +
  157 +.staff-item {
  158 + padding: 10px;
  159 + margin-bottom: 5px;
  160 + border: 1px solid #ebeef5;
  161 + border-radius: 4px;
  162 + cursor: pointer;
  163 +
  164 + &:hover {
  165 + background-color: #f5f7fa;
  166 + }
  167 +
  168 + &.selected {
  169 + background-color: #ecf5ff;
  170 + border-color: #d9ecff;
  171 + }
  172 +}
  173 +
  174 +.dialog-footer {
  175 + margin-top: 20px;
  176 +}
  177 +
  178 +.margin-right-xs {
  179 + margin-right: 5px;
  180 +}
  181 +
  182 +.text-center {
  183 + text-align: center;
  184 +}
  185 +
  186 +.text-right {
  187 + text-align: right;
  188 +}
  189 +</style>
0 190 \ No newline at end of file
... ...
src/components/oa/uploadImageUrl.vue
1 1 <template>
2 2 <div class="upload-image-container">
3 3 <div v-for="(image, index) in photos" :key="index" class="image-item">
4   - <el-image
5   - :src="getImageUrl(image)"
  4 + <el-image
  5 + :src="image"
6 6 fit="cover"
7   - :preview-src-list="[getImageUrl(image)]"
8   - class="image-preview"
9   - >
10   - <div slot="error" class="image-slot">
11   - <i class="el-icon-picture-outline"></i>
12   - </div>
  7 + style="width: 100px; height: 100px">
13 8 </el-image>
14   - <i class="el-icon-close remove-icon" @click="removeImage(index)"></i>
  9 + <i
  10 + class="el-icon-close remove-icon"
  11 + @click="_removeImage(image)">
  12 + </i>
15 13 </div>
16   -
17   - <el-upload
  14 +
  15 + <div
18 16 v-if="photos.length < imageCount"
19   - action=""
20   - :show-file-list="false"
21   - :before-upload="beforeUpload"
22   - :http-request="handleUpload"
23 17 class="upload-button"
24   - >
  18 + @click="_uploadPhoto">
25 19 <i class="el-icon-plus"></i>
26   - </el-upload>
  20 + </div>
  21 +
  22 + <input
  23 + type="file"
  24 + class="file-input"
  25 + accept="image/*"
  26 + ref="fileInput"
  27 + hidden
  28 + @change="_choosePhoto">
27 29 </div>
28 30 </template>
29 31  
30 32 <script>
31   -import { uploadImage } from '@/api/oa/questionAnswerManageApi'
  33 +import { uploadImage } from '@/api/oa/editExamineStaffApi'
32 34 import { getCommunityId } from '@/api/community/communityApi'
33 35  
34 36 export default {
... ... @@ -41,62 +43,116 @@ export default {
41 43 },
42 44 data() {
43 45 return {
44   - photos: [],
45   - photoUrls: []
  46 + photos: [], // 显示图片数组(base64格式)
  47 + photosUrl: [], // 向父组件传递的数组({fileId, url})
  48 + communityId: ''
46 49 }
47 50 },
  51 + created() {
  52 + this.communityId = getCommunityId()
  53 + },
48 54 methods: {
49   - getImageUrl(image) {
50   - if (typeof image === 'string') {
51   - if (image.startsWith('http') || image.startsWith('https') || image.startsWith('data:')) {
52   - return image
  55 + open(photos) {
  56 + this.photos = []
  57 + this.photosUrl = []
  58 +
  59 + if (!photos || photos.length === 0) return
  60 +
  61 + photos.forEach(photo => {
  62 + if (photo.indexOf('base64,') > -1) {
  63 + this.photos.push(photo)
  64 + return
53 65 }
54   - return `/callComponent/download/getFile/file?fileId=${image}&communityId=-1&time=${new Date().getTime()}`
55   - }
56   - return image.url || ''
57   - },
58   - setPhotos(photos) {
59   - this.photos = photos || []
60   - this.photoUrls = photos.map(photo => {
61   - return typeof photo === 'string' ? { fileId: photo } : photo
  66 +
  67 + if (photo.indexOf("https") > -1 || photo.indexOf("http") > -1) {
  68 + this.urlToBase64(photo)
  69 + const urlParams = this._getUrlParams(photo)
  70 + if (urlParams.fileId) {
  71 + this.photosUrl.push({fileId: urlParams.fileId, url: photo})
  72 + }
  73 + return
  74 + }
  75 +
  76 + const url = `/callComponent/download/getFile/file?fileId=${photo}&communityId=-1&time=${new Date()}`
  77 + this.urlToBase64(url)
  78 + this.photosUrl.push({fileId: photo, url})
62 79 })
63   - this.$emit('change', this.photoUrls)
64 80 },
65 81 clear() {
66 82 this.photos = []
67   - this.photoUrls = []
68   - this.$emit('change', [])
  83 + this.photosUrl = []
69 84 },
70   - beforeUpload(file) {
71   - const isImage = file.type.includes('image/')
72   - const isLt2M = file.size / 1024 / 1024 < 2
73   -
74   - if (!isImage) {
75   - this.$message.error(this.$t('uploadImage.validate.imageType'))
  85 + _uploadPhoto() {
  86 + this.$refs.fileInput.click()
  87 + },
  88 + _choosePhoto(event) {
  89 + const files = event.target.files
  90 + if (!files || files.length === 0) return
  91 +
  92 + const file = files[0]
  93 + if (file.size > 2 * 1024 * 1024) {
  94 + this.$message.error(this.$t('uploadImage.imageSizeLimit'))
  95 + return
76 96 }
77   - if (!isLt2M) {
78   - this.$message.error(this.$t('uploadImage.validate.imageSize'))
  97 +
  98 + const reader = new FileReader()
  99 + reader.onload = (e) => {
  100 + this.photos.push(e.target.result)
  101 + this._doUploadImageUrl(file)
79 102 }
80   - return isImage && isLt2M
  103 + reader.readAsDataURL(file)
  104 +
  105 + event.target.value = null
  106 + },
  107 + _removeImage(image) {
  108 + const index = this.photos.indexOf(image)
  109 + this.photos.splice(index, 1)
  110 + this.photosUrl.splice(index, 1)
  111 + this.$emit('notifyUploadImage', this.photosUrl)
81 112 },
82   - async handleUpload({ file }) {
  113 + async _doUploadImageUrl(file) {
83 114 try {
84 115 const formData = new FormData()
85   - formData.append('uploadFile', file)
86   - formData.append('communityId', getCommunityId())
87   -
88   - const response = await uploadImage(formData)
89   - this.photos.push(response.data)
90   - this.photoUrls.push(response.data)
91   - this.$emit('change', this.photoUrls)
  116 + formData.append("uploadFile", file)
  117 + formData.append('communityId', this.communityId)
  118 +
  119 + const data = await uploadImage(formData)
  120 + this.photosUrl.push(data)
  121 + this.$emit('notifyUploadImage', this.photosUrl)
92 122 } catch (error) {
93   - this.$message.error(error.message || this.$t('uploadImage.message.uploadError'))
  123 + this.$message.error(this.$t('uploadImage.uploadError'))
94 124 }
95 125 },
96   - removeImage(index) {
97   - this.photos.splice(index, 1)
98   - this.photoUrls.splice(index, 1)
99   - this.$emit('change', this.photoUrls)
  126 + _getUrlParams(url) {
  127 + if (url.indexOf('?') < 0) {
  128 + return { fileId: url }
  129 + }
  130 +
  131 + const urlStr = url.split('?')[1]
  132 + const obj = {}
  133 + const paramsArr = urlStr.split('&')
  134 +
  135 + for (let i = 0; i < paramsArr.length; i++) {
  136 + const arr = paramsArr[i].split('=')
  137 + obj[arr[0]] = arr[1]
  138 + }
  139 +
  140 + return obj
  141 + },
  142 + urlToBase64(url) {
  143 + const image = new Image()
  144 + image.setAttribute('crossOrigin', 'anonymous')
  145 + image.src = url
  146 +
  147 + image.onload = () => {
  148 + const canvas = document.createElement('canvas')
  149 + canvas.width = image.width
  150 + canvas.height = image.height
  151 + const ctx = canvas.getContext('2d')
  152 + ctx.drawImage(image, 0, 0, image.width, image.height)
  153 + const base64 = canvas.toDataURL('image/png')
  154 + this.photos.push(base64)
  155 + }
100 156 }
101 157 }
102 158 }
... ... @@ -107,46 +163,41 @@ export default {
107 163 display: flex;
108 164 flex-wrap: wrap;
109 165 gap: 10px;
110   -
  166 +
111 167 .image-item {
112 168 position: relative;
113   - width: 100px;
114   - height: 100px;
115   - border: 1px dashed #d9d9d9;
116   - border-radius: 6px;
117   - overflow: hidden;
118   -
119   - .image-preview {
120   - width: 100%;
121   - height: 100%;
122   - }
123   -
  169 +
124 170 .remove-icon {
125 171 position: absolute;
126   - top: 0;
127   - right: 0;
128   - padding: 5px;
129   - color: #fff;
130   - background-color: rgba(0, 0, 0, 0.5);
  172 + top: 5px;
  173 + right: 5px;
  174 + color: #f56c6c;
  175 + font-size: 16px;
131 176 cursor: pointer;
132   - z-index: 10;
  177 + background: #fff;
  178 + border-radius: 50%;
  179 + padding: 2px;
  180 +
  181 + &:hover {
  182 + color: #f00;
  183 + }
133 184 }
134 185 }
135   -
  186 +
136 187 .upload-button {
  188 + width: 100px;
  189 + height: 100px;
  190 + border: 1px dashed #dcdfe6;
137 191 display: flex;
138 192 justify-content: center;
139 193 align-items: center;
140   - width: 100px;
141   - height: 100px;
142   - border: 1px dashed #d9d9d9;
143   - border-radius: 6px;
144 194 cursor: pointer;
145   - font-size: 28px;
146   - color: #8c939d;
147   -
  195 + color: #909399;
  196 + font-size: 24px;
  197 +
148 198 &:hover {
149 199 border-color: #409eff;
  200 + color: #409eff;
150 201 }
151 202 }
152 203 }
... ...
src/components/oa/viewImage.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="visible"
  4 + fullscreen
  5 + :show-close="false"
  6 + @close="handleClose"
  7 + >
  8 + <div style="position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);">
  9 + <el-image
  10 + :src="imageUrl"
  11 + :style="imageStyle"
  12 + fit="contain"
  13 + />
  14 + <i
  15 + class="el-icon-close"
  16 + style="position: absolute; right: 20px; top: 20px; font-size: 24px; color: red; cursor: pointer;"
  17 + @click="visible = false"
  18 + />
  19 + </div>
  20 + </el-dialog>
  21 +</template>
  22 +
  23 +<script>
  24 +export default {
  25 + name: 'ViewImage',
  26 + data() {
  27 + return {
  28 + visible: false,
  29 + imageUrl: '',
  30 + imageStyle: {
  31 + width: '800px',
  32 + height: '800px'
  33 + }
  34 + }
  35 + },
  36 + methods: {
  37 + open(url) {
  38 + this.imageUrl = url
  39 + this.visible = true
  40 + this.adjustImageSize(url)
  41 + },
  42 + handleClose() {
  43 + this.imageUrl = ''
  44 + },
  45 + adjustImageSize(url) {
  46 + const img = new Image()
  47 + img.src = url
  48 + img.onload = () => {
  49 + const ratio = img.width / img.height
  50 + if (ratio > 1) {
  51 + this.imageStyle.height = `${800 / ratio}px`
  52 + this.imageStyle.width = '800px'
  53 + } else {
  54 + this.imageStyle.width = `${800 * ratio}px`
  55 + this.imageStyle.height = '800px'
  56 + }
  57 + }
  58 + }
  59 + }
  60 +}
  61 +</script>
0 62 \ No newline at end of file
... ...
src/i18n/oaI18n.js
... ... @@ -17,6 +17,16 @@ import { messages as printQuestionAnswerMessages } from &#39;../views/oa/printQuesti
17 17 import { messages as addQuestionAnswerMessages } from '../views/oa/addQuestionAnswerLang'
18 18 import { messages as editQuestionAnswerMessages } from '../views/oa/editQuestionAnswerLang'
19 19 import { messages as printQuestionAnswerDetailMessages } from '../views/oa/printQuestionAnswerDetailLang'
  20 +import { messages as ownerVotingMessages } from '../views/oa/ownerVotingLang'
  21 +import { messages as addOwnerVotingMessages } from '../views/oa/addOwnerVotingLang'
  22 +import { messages as editOwnerVotingMessages } from '../views/oa/editOwnerVotingLang'
  23 +import { messages as printOwnerVotingMessages } from '../views/oa/printOwnerVotingLang'
  24 +import { messages as examineProjectManageMessages } from '../views/oa/examineProjectManageLang'
  25 +import { messages as examineStaffManageMessages } from '../views/oa/examineStaffManageLang'
  26 +import { messages as addExamineStaffMessages } from '../views/oa/addExamineStaffLang'
  27 +import { messages as editExamineStaffMessages } from '../views/oa/editExamineStaffLang'
  28 +import { messages as examineStaffValueMessages } from '../views/oa/examineStaffValueLang'
  29 +
20 30 export const messages ={
21 31 en:{
22 32 ...activitiesTypeManageMessages.en,
... ... @@ -38,6 +48,15 @@ export const messages ={
38 48 ...addQuestionAnswerMessages.en,
39 49 ...editQuestionAnswerMessages.en,
40 50 ...printQuestionAnswerDetailMessages.en,
  51 + ...ownerVotingMessages.en,
  52 + ...addOwnerVotingMessages.en,
  53 + ...editOwnerVotingMessages.en,
  54 + ...printOwnerVotingMessages.en,
  55 + ...examineProjectManageMessages.en,
  56 + ...examineStaffManageMessages.en,
  57 + ...addExamineStaffMessages.en,
  58 + ...editExamineStaffMessages.en,
  59 + ...examineStaffValueMessages.en,
41 60 },
42 61 zh:{
43 62 ...activitiesTypeManageMessages.zh,
... ... @@ -59,5 +78,14 @@ export const messages ={
59 78 ...addQuestionAnswerMessages.zh,
60 79 ...editQuestionAnswerMessages.zh,
61 80 ...printQuestionAnswerDetailMessages.zh,
  81 + ...ownerVotingMessages.zh,
  82 + ...addOwnerVotingMessages.zh,
  83 + ...editOwnerVotingMessages.zh,
  84 + ...printOwnerVotingMessages.zh,
  85 + ...examineProjectManageMessages.zh,
  86 + ...examineStaffManageMessages.zh,
  87 + ...addExamineStaffMessages.zh,
  88 + ...editExamineStaffMessages.zh,
  89 + ...examineStaffValueMessages.zh,
62 90 }
63 91 }
64 92 \ No newline at end of file
... ...
src/router/index.js
... ... @@ -955,6 +955,11 @@ const routes = [
955 955 name: '/pages/question/printQuestionAnswerDetail',
956 956 component: () => import('@/views/oa/printQuestionAnswerDetailList.vue')
957 957 },
  958 + {
  959 + path:'/views/oa/printOwnerVoting',
  960 + name:'/views/oa/printOwnerVoting',
  961 + component: () => import('@/views/oa/printOwnerVotingList.vue')
  962 + },
958 963 ]
959 964  
960 965 const router = new VueRouter({
... ...
src/router/oaRouter.js
... ... @@ -80,9 +80,48 @@ export default [
80 80 component: () => import('@/views/oa/addQuestionAnswerList.vue')
81 81 },
82 82 {
83   - path:'/views/oa/editQuestionAnswer',
84   - name:'/views/oa/editQuestionAnswer',
  83 + path: '/views/oa/editQuestionAnswer',
  84 + name: '/views/oa/editQuestionAnswer',
85 85 component: () => import('@/views/oa/editQuestionAnswerList.vue')
86   - },
87   -
  86 + },
  87 + {
  88 + path: '/pages/question/ownerVoting',
  89 + name: '/pages/question/ownerVoting',
  90 + component: () => import('@/views/oa/ownerVotingList.vue')
  91 + },
  92 + {
  93 + path: '/views/oa/addOwnerVoting',
  94 + name: '/views/oa/addOwnerVoting',
  95 + component: () => import('@/views/oa/addOwnerVotingList.vue')
  96 + },
  97 + {
  98 + path: '/views/oa/editOwnerVoting',
  99 + name: '/views/oa/editOwnerVoting',
  100 + component: () => import('@/views/oa/editOwnerVotingList.vue')
  101 + },
  102 + {
  103 + path: '/pages/examine/examineProjectManage',
  104 + name: '/pages/examine/examineProjectManage',
  105 + component: () => import('@/views/oa/examineProjectManageList.vue')
  106 + },
  107 + {
  108 + path: '/pages/examine/examineStaffManage',
  109 + name: '/pages/examine/examineStaffManage',
  110 + component: () => import('@/views/oa/examineStaffManageList.vue')
  111 + },
  112 + {
  113 + path: '/views/oa/addExamineStaff',
  114 + name: '/views/oa/addExamineStaff',
  115 + component: () => import('@/views/oa/addExamineStaffList.vue')
  116 + },
  117 + {
  118 + path: '/views/oa/editExamineStaff',
  119 + name: '/views/oa/editExamineStaff',
  120 + component: () => import('@/views/oa/editExamineStaffList.vue')
  121 + },
  122 + {
  123 + path: '/pages/examine/examineStaffValue',
  124 + name: '/pages/examine/examineStaffValue',
  125 + component: () => import('@/views/oa/examineStaffValueList.vue')
  126 + },
88 127 ]
89 128 \ No newline at end of file
... ...
src/views/oa/addExamineStaffLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + addExamineStaff: {
  4 + title: 'Add Examine Staff',
  5 + staffName: 'Staff Name',
  6 + staffNamePlaceholder: 'Required, please fill in staff name',
  7 + select: 'Select',
  8 + projects: 'Examine Projects',
  9 + staffAvatar: 'Staff Avatar',
  10 + staffPost: 'Staff Post',
  11 + staffPostPlaceholder: 'Required, please fill in staff post',
  12 + staffIntroduction: 'Staff Introduction',
  13 + staffIntroductionPlaceholder: 'Required, please fill in staff introduction'
  14 + },
  15 + selectStaff: {
  16 + title: 'Select Staff',
  17 + orgInfo: 'Organization Information',
  18 + staffInfo: 'Staff Information',
  19 + submitter: 'Submitter',
  20 + dynamicAssign: 'Dynamic Assignment'
  21 + },
  22 + uploadImage: {
  23 + imageSizeLimit: 'Image size cannot exceed 2MB',
  24 + uploadFailed: 'Upload failed'
  25 + }
  26 + },
  27 + zh: {
  28 + addExamineStaff: {
  29 + title: '添加考核员工',
  30 + staffName: '员工名称',
  31 + staffNamePlaceholder: '必填,请填写员工名称',
  32 + select: '选择',
  33 + projects: '考核项目',
  34 + staffAvatar: '员工头像',
  35 + staffPost: '员工岗位',
  36 + staffPostPlaceholder: '必填,请填写员工岗位',
  37 + staffIntroduction: '员工简介',
  38 + staffIntroductionPlaceholder: '必填,请输入员工简介'
  39 + },
  40 + selectStaff: {
  41 + title: '选择员工',
  42 + orgInfo: '组织信息',
  43 + staffInfo: '员工信息',
  44 + submitter: '提交者',
  45 + dynamicAssign: '动态指定'
  46 + },
  47 + uploadImage: {
  48 + imageSizeLimit: '图片大小不能超过2MB',
  49 + uploadFailed: '上传失败'
  50 + }
  51 + }
  52 +}
0 53 \ No newline at end of file
... ...
src/views/oa/addExamineStaffList.vue 0 → 100644
  1 +<template>
  2 + <div class="add-examine-staff-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('addExamineStaff.title') }}</span>
  6 + <div class="header-tools">
  7 + <el-button type="primary" size="small" @click="_goBack">
  8 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  9 + </el-button>
  10 + </div>
  11 + </div>
  12 + <el-form ref="form" :model="addExamineStaffInfo" label-width="120px">
  13 + <el-row>
  14 + <el-col :span="24">
  15 + <el-form-item :label="$t('addExamineStaff.staffName')">
  16 + <el-input v-model="addExamineStaffInfo.staffName" :placeholder="$t('addExamineStaff.staffNamePlaceholder')"
  17 + disabled style="width: 60%">
  18 + </el-input>
  19 + <el-button type="primary" @click="chooseStaff" style="margin-left: 10px">
  20 + <i class="el-icon-search"></i>{{ $t('addExamineStaff.select') }}
  21 + </el-button>
  22 + </el-form-item>
  23 + </el-col>
  24 + </el-row>
  25 +
  26 + <el-row>
  27 + <el-col :span="24">
  28 + <el-form-item :label="$t('addExamineStaff.projects')">
  29 + <el-checkbox-group v-model="addExamineStaffInfo.projectIds">
  30 + <el-checkbox v-for="(item, index) in addExamineStaffInfo.projects" :key="index" :label="item.projectId">
  31 + {{ item.name }}
  32 + </el-checkbox>
  33 + </el-checkbox-group>
  34 + </el-form-item>
  35 + </el-col>
  36 + </el-row>
  37 +
  38 + <el-row>
  39 + <el-col :span="24">
  40 + <el-form-item :label="$t('addExamineStaff.staffAvatar')">
  41 + <upload-image-url ref="uploadImage" :call-back-listener="'addExamineStaff'"
  42 + :call-back-function="'notifyUploadImage'" :image-count="1">
  43 + </upload-image-url>
  44 + </el-form-item>
  45 + </el-col>
  46 + </el-row>
  47 +
  48 + <el-row>
  49 + <el-col :span="24">
  50 + <el-form-item :label="$t('addExamineStaff.staffPost')">
  51 + <el-input v-model="addExamineStaffInfo.post" :placeholder="$t('addExamineStaff.staffPostPlaceholder')"
  52 + style="width: 60%">
  53 + </el-input>
  54 + </el-form-item>
  55 + </el-col>
  56 + </el-row>
  57 +
  58 + <el-row>
  59 + <el-col :span="24">
  60 + <el-form-item :label="$t('addExamineStaff.staffIntroduction')">
  61 + <el-input type="textarea" :rows="5" v-model="addExamineStaffInfo.introduction"
  62 + :placeholder="$t('addExamineStaff.staffIntroductionPlaceholder')" style="width: 80%">
  63 + </el-input>
  64 + </el-form-item>
  65 + </el-col>
  66 + </el-row>
  67 +
  68 + <el-row>
  69 + <el-col :span="24" class="text-right">
  70 + <el-button type="warning" @click="_goBack" style="margin-right: 20px;">
  71 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  72 + </el-button>
  73 + <el-button type="primary" @click="saveExamineStaffInfo">
  74 + <i class="el-icon-check"></i>{{ $t('common.submit') }}
  75 + </el-button>
  76 + </el-col>
  77 + </el-row>
  78 + </el-form>
  79 + </el-card>
  80 +
  81 + <select-staff ref="selectStaff" @selectStaff="handleStaffSelected"></select-staff>
  82 + </div>
  83 +</template>
  84 +
  85 +<script>
  86 +import { saveExamineStaff, listExamineProject } from '@/api/oa/addExamineStaffApi'
  87 +import SelectStaff from '@/components/staff/SelectStaff'
  88 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  89 +import { getCommunityId } from '@/api/community/communityApi'
  90 +
  91 +export default {
  92 + name: 'AddExamineStaffList',
  93 + components: {
  94 + SelectStaff,
  95 + UploadImageUrl
  96 + },
  97 + data() {
  98 + return {
  99 + addExamineStaffInfo: {
  100 + esId: '',
  101 + orgName: '',
  102 + staffName: '',
  103 + staffId: '',
  104 + post: '',
  105 + introduction: '',
  106 + headerImg: '',
  107 + projects: [],
  108 + projectIds: [],
  109 + communityId: ''
  110 + }
  111 + }
  112 + },
  113 + created() {
  114 + this.addExamineStaffInfo.communityId = getCommunityId()
  115 + this._listExamineProjects()
  116 + },
  117 + mounted() {
  118 + this.$on('addExamineStaff', 'notifyUploadImage', this.notifyUploadImage)
  119 + },
  120 + methods: {
  121 + notifyUploadImage(_param) {
  122 + if (_param.length > 0) {
  123 + this.addExamineStaffInfo.headerImg = _param[0].fileId
  124 + } else {
  125 + this.addExamineStaffInfo.headerImg = ''
  126 + }
  127 + },
  128 + handleStaffSelected(staffs) {
  129 + console.log(staffs)
  130 + this.addExamineStaffInfo.staffName = staffs.staffName
  131 + this.addExamineStaffInfo.staffId = staffs.staffId
  132 + },
  133 + addExamineStaffValidate() {
  134 + return this.$refs.form.validate()
  135 + },
  136 + async saveExamineStaffInfo() {
  137 + try {
  138 + const valid = await this.addExamineStaffValidate()
  139 + if (!valid) return
  140 +
  141 + const res = await saveExamineStaff(this.addExamineStaffInfo)
  142 + if (res.code === 0) {
  143 + this.$message.success(this.$t('common.addSuccess'))
  144 + this._goBack()
  145 + } else {
  146 + this.$message.error(res.msg)
  147 + }
  148 + } catch (error) {
  149 + this.$message.error(this.$t('common.addFailed'))
  150 + }
  151 + },
  152 + chooseStaff() {
  153 + this.$refs.selectStaff.open(this.addExamineStaffInfo)
  154 + },
  155 + async _listExamineProjects() {
  156 + try {
  157 + const params = {
  158 + page: 1,
  159 + row: 100,
  160 + communityId: this.addExamineStaffInfo.communityId
  161 + }
  162 + const res = await listExamineProject(params)
  163 + this.addExamineStaffInfo.projects = res.data
  164 + } catch (error) {
  165 + console.error('获取考核项目失败:', error)
  166 + }
  167 + },
  168 + _goBack() {
  169 + this.$router.go(-1)
  170 + }
  171 + }
  172 +}
  173 +</script>
  174 +
  175 +<style lang="scss" scoped>
  176 +.add-examine-staff-container {
  177 + padding: 20px;
  178 +
  179 + .box-card {
  180 + width: 100%;
  181 +
  182 + .clearfix {
  183 + display: flex;
  184 + justify-content: space-between;
  185 + align-items: center;
  186 + }
  187 +
  188 + .header-tools {
  189 + display: flex;
  190 + align-items: center;
  191 + }
  192 +
  193 + .text-right {
  194 + text-align: right;
  195 + padding-right: 20px;
  196 + }
  197 + }
  198 +
  199 + .el-checkbox {
  200 + margin-right: 15px;
  201 + }
  202 +}
  203 +</style>
0 204 \ No newline at end of file
... ...
src/views/oa/addOwnerVotingLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + addOwnerVoting: {
  4 + title: 'Add Voting',
  5 + voteName: 'Vote Name',
  6 + voteNamePlaceholder: 'Required, please enter vote name',
  7 + type: 'Type',
  8 + typePlaceholder: 'Required, please select type',
  9 + singleChoice: 'Single Choice',
  10 + multipleChoice: 'Multiple Choice',
  11 + startTime: 'Start Time',
  12 + startTimePlaceholder: 'Required, please select start time',
  13 + endTime: 'End Time',
  14 + endTimePlaceholder: 'Required, please select end time',
  15 + option: 'Option ',
  16 + optionPlaceholder: 'Required, please enter option content',
  17 + addOption: 'Add Option',
  18 + deleteOption: 'Delete Option',
  19 + voteDescription: 'Vote Description',
  20 + voteDescriptionPlaceholder: 'Required, please enter vote description',
  21 + voteRooms: 'Vote Rooms',
  22 + validate: {
  23 + voteName: 'Vote name cannot be empty',
  24 + type: 'Please select type',
  25 + startTime: 'Please select start time',
  26 + endTime: 'Please select end time',
  27 + option: 'Please fill in all options'
  28 + }
  29 + },
  30 + selectRoom: {
  31 + buildingUnit: 'Building Unit',
  32 + roomInfo: 'Room Information',
  33 + unit: 'Unit'
  34 + }
  35 + },
  36 + zh: {
  37 + addOwnerVoting: {
  38 + title: '添加投票',
  39 + voteName: '投票名称',
  40 + voteNamePlaceholder: '必填,请填写投票名称',
  41 + type: '类型',
  42 + typePlaceholder: '必填,请选择类型',
  43 + singleChoice: '单选',
  44 + multipleChoice: '多选',
  45 + startTime: '开始时间',
  46 + startTimePlaceholder: '必填,请选择开始时间',
  47 + endTime: '结束时间',
  48 + endTimePlaceholder: '必填,请选择结束时间',
  49 + option: '选项',
  50 + optionPlaceholder: '必填,请填写选项内容',
  51 + addOption: '增加选项',
  52 + deleteOption: '删除选项',
  53 + voteDescription: '投票说明',
  54 + voteDescriptionPlaceholder: '必填,请输入投票说明',
  55 + voteRooms: '投票房屋',
  56 + validate: {
  57 + voteName: '名称不能为空',
  58 + type: '请选择类型',
  59 + startTime: '请选择开始时间',
  60 + endTime: '请选择结束时间',
  61 + option: '请填写所有选项内容'
  62 + }
  63 + },
  64 + selectRoom: {
  65 + buildingUnit: '楼栋单元',
  66 + roomInfo: '房屋信息',
  67 + unit: '单元'
  68 + }
  69 + }
  70 +}
0 71 \ No newline at end of file
... ...
src/views/oa/addOwnerVotingList.vue 0 → 100644
  1 +<template>
  2 + <div class="add-owner-voting-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('addOwnerVoting.title') }}</span>
  6 + </div>
  7 + <el-row :gutter="20">
  8 + <el-col :span="24">
  9 + <el-form ref="form" :model="addOwnerVotingInfo" label-width="120px">
  10 + <el-row :gutter="20">
  11 + <el-col :span="12">
  12 + <el-form-item :label="$t('addOwnerVoting.voteName')" prop="qaName">
  13 + <el-input v-model="addOwnerVotingInfo.qaName" :placeholder="$t('addOwnerVoting.voteNamePlaceholder')" />
  14 + </el-form-item>
  15 + </el-col>
  16 + <el-col :span="12">
  17 + <el-form-item :label="$t('addOwnerVoting.type')" prop="titleType">
  18 + <el-select v-model="addOwnerVotingInfo.titleType" :placeholder="$t('addOwnerVoting.typePlaceholder')"
  19 + style="width:100%" @change="changeAddTitleType">
  20 + <el-option :label="$t('addOwnerVoting.singleChoice')" value="1001" />
  21 + <el-option :label="$t('addOwnerVoting.multipleChoice')" value="2002" />
  22 + </el-select>
  23 + </el-form-item>
  24 + </el-col>
  25 + </el-row>
  26 +
  27 + <el-row :gutter="20">
  28 + <el-col :span="12">
  29 + <el-form-item :label="$t('addOwnerVoting.startTime')" prop="startTime">
  30 + <el-date-picker v-model="addOwnerVotingInfo.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
  31 + :placeholder="$t('addOwnerVoting.startTimePlaceholder')" style="width:100%" />
  32 + </el-form-item>
  33 + </el-col>
  34 + <el-col :span="12">
  35 + <el-form-item :label="$t('addOwnerVoting.endTime')" prop="endTime">
  36 + <el-date-picker v-model="addOwnerVotingInfo.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
  37 + :placeholder="$t('addOwnerVoting.endTimePlaceholder')" style="width:100%" />
  38 + </el-form-item>
  39 + </el-col>
  40 + </el-row>
  41 +
  42 + <el-row v-for="(item, index) in addOwnerVotingInfo.titleValues" :key="index" :gutter="20">
  43 + <el-col :span="12">
  44 + <el-form-item :label="$t('addOwnerVoting.option') + item.seq">
  45 + <el-input v-model="item.itemValue" :placeholder="$t('addOwnerVoting.optionPlaceholder')" />
  46 + </el-form-item>
  47 + </el-col>
  48 + <el-col :span="4">
  49 + <el-button v-if="index === addOwnerVotingInfo.titleValues.length - 1" type="text" @click="addTitleValue">
  50 + {{ $t('addOwnerVoting.addOption') }}
  51 + </el-button>
  52 + <el-button v-else type="text" @click="deleteTitleValue(item.seq)">
  53 + {{ $t('addOwnerVoting.deleteOption') }}
  54 + </el-button>
  55 + </el-col>
  56 + </el-row>
  57 +
  58 + <el-row :gutter="20">
  59 + <el-col :span="24">
  60 + <el-form-item :label="$t('addOwnerVoting.voteDescription')">
  61 + <el-input v-model="addOwnerVotingInfo.content" type="textarea" :rows="4"
  62 + :placeholder="$t('addOwnerVoting.voteDescriptionPlaceholder')" />
  63 + </el-form-item>
  64 + </el-col>
  65 + </el-row>
  66 +
  67 + <el-row :gutter="20">
  68 + <el-col :span="24">
  69 + <el-form>
  70 + <el-form-item :label="$t('addOwnerVoting.voteRooms')">
  71 + <SelectRooms ref="selectRooms" @notifySelectRooms="handleSelectRooms" />
  72 + </el-form-item>
  73 + </el-form>
  74 + </el-col>
  75 + </el-row>
  76 +
  77 + <el-row :gutter="20">
  78 + <el-col :span="24" class="text-right">
  79 + <el-button type="warning" @click="goBack">
  80 + {{ $t('common.cancel') }}
  81 + </el-button>
  82 + <el-button type="primary" @click="saveOwnerVoting">
  83 + <i class="el-icon-check" /> {{ $t('common.save') }}
  84 + </el-button>
  85 + </el-col>
  86 + </el-row>
  87 + </el-form>
  88 + </el-col>
  89 + </el-row>
  90 + </el-card>
  91 + </div>
  92 +</template>
  93 +
  94 +<script>
  95 +import SelectRooms from '@/components/room/selectRooms'
  96 +import { saveOwnerVote } from '@/api/oa/addOwnerVotingApi'
  97 +import { getCommunityId } from '@/api/community/communityApi'
  98 +
  99 +export default {
  100 + name: 'AddOwnerVoting',
  101 + components: {
  102 + SelectRooms
  103 + },
  104 + data() {
  105 + return {
  106 + addOwnerVotingInfo: {
  107 + qaName: '',
  108 + startTime: '',
  109 + endTime: '',
  110 + communityId: '',
  111 + content: '',
  112 + titleType: '',
  113 + titleValues: [],
  114 + roomIds: []
  115 + }
  116 + }
  117 + },
  118 + created() {
  119 + this.addOwnerVotingInfo.communityId = getCommunityId()
  120 + },
  121 + methods: {
  122 + handleSelectRooms(rooms) {
  123 + this.addOwnerVotingInfo.roomIds = rooms.map(item => item.roomId)
  124 + },
  125 + validateForm() {
  126 + if (!this.addOwnerVotingInfo.qaName) {
  127 + this.$message.error(this.$t('addOwnerVoting.validate.voteName'))
  128 + return false
  129 + }
  130 + if (!this.addOwnerVotingInfo.titleType) {
  131 + this.$message.error(this.$t('addOwnerVoting.validate.type'))
  132 + return false
  133 + }
  134 + if (!this.addOwnerVotingInfo.startTime) {
  135 + this.$message.error(this.$t('addOwnerVoting.validate.startTime'))
  136 + return false
  137 + }
  138 + if (!this.addOwnerVotingInfo.endTime) {
  139 + this.$message.error(this.$t('addOwnerVoting.validate.endTime'))
  140 + return false
  141 + }
  142 + if (this.addOwnerVotingInfo.titleValues.some(item => !item.itemValue)) {
  143 + this.$message.error(this.$t('addOwnerVoting.validate.option'))
  144 + return false
  145 + }
  146 + return true
  147 + },
  148 + async saveOwnerVoting() {
  149 + if (!this.validateForm()) return
  150 +
  151 + try {
  152 + const res = await saveOwnerVote(this.addOwnerVotingInfo)
  153 + if (res.code === 0) {
  154 + this.$message.success(this.$t('common.saveSuccess'))
  155 + this.$router.go(-1)
  156 + } else {
  157 + this.$message.error(res.msg)
  158 + }
  159 + } catch (error) {
  160 + this.$message.error(this.$t('common.saveError'))
  161 + }
  162 + },
  163 + changeAddTitleType() {
  164 + const type = this.addOwnerVotingInfo.titleType
  165 + if (type === '1001') {
  166 + this.addOwnerVotingInfo.titleValues = [{
  167 + itemValue: '',
  168 + seq: 1
  169 + }]
  170 + } else if (type === '2002') {
  171 + this.addOwnerVotingInfo.titleValues = [
  172 + {
  173 + itemValue: '',
  174 + seq: 1
  175 + },
  176 + {
  177 + itemValue: '',
  178 + seq: 2
  179 + }
  180 + ]
  181 + } else {
  182 + this.addOwnerVotingInfo.titleValues = []
  183 + }
  184 + },
  185 + addTitleValue() {
  186 + this.addOwnerVotingInfo.titleValues.push({
  187 + itemValue: '',
  188 + seq: this.addOwnerVotingInfo.titleValues.length + 1
  189 + })
  190 + },
  191 + deleteTitleValue(seq) {
  192 + this.addOwnerVotingInfo.titleValues = this.addOwnerVotingInfo.titleValues
  193 + .filter(item => item.seq !== seq)
  194 + .map((item, index) => ({
  195 + ...item,
  196 + seq: index + 1
  197 + }))
  198 + },
  199 + goBack() {
  200 + this.$router.go(-1)
  201 + }
  202 + }
  203 +}
  204 +</script>
  205 +
  206 +<style lang="scss" scoped>
  207 +.add-owner-voting-container {
  208 + padding: 20px;
  209 +
  210 + .box-card {
  211 + margin-bottom: 20px;
  212 + }
  213 +
  214 + .text-right {
  215 + text-align: right;
  216 + }
  217 +}
  218 +</style>
0 219 \ No newline at end of file
... ...
src/views/oa/editExamineStaffLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + editExamineStaff: {
  4 + title: 'Edit Examine Staff',
  5 + staffName: 'Staff Name',
  6 + staffNamePlaceholder: 'Required, please enter staff name',
  7 + projects: 'Examine Projects',
  8 + staffPhoto: 'Staff Photo',
  9 + post: 'Post',
  10 + postPlaceholder: 'Required, please enter post',
  11 + introduction: 'Introduction',
  12 + staffNameRequired: 'Staff name is required',
  13 + postRequired: 'Post is required',
  14 + fetchProjectsError: 'Failed to get examine projects',
  15 + fetchStaffError: 'Failed to get staff information'
  16 + },
  17 + uploadImage: {
  18 + imageSizeLimit: 'Image size cannot exceed 2MB',
  19 + uploadError: 'Image upload failed'
  20 + }
  21 + },
  22 + zh: {
  23 + editExamineStaff: {
  24 + title: '修改考核员工',
  25 + staffName: '员工名称',
  26 + staffNamePlaceholder: '必填,请填写员工名称',
  27 + projects: '考核项目',
  28 + staffPhoto: '员工头像',
  29 + post: '员工岗位',
  30 + postPlaceholder: '必填,请填写员工岗位',
  31 + introduction: '员工简介',
  32 + staffNameRequired: '员工名称不能为空',
  33 + postRequired: '员工岗位不能为空',
  34 + fetchProjectsError: '获取考核项目失败',
  35 + fetchStaffError: '获取员工信息失败'
  36 + },
  37 + uploadImage: {
  38 + imageSizeLimit: '图片大小不能超过2MB',
  39 + uploadError: '图片上传失败'
  40 + }
  41 + }
  42 +}
0 43 \ No newline at end of file
... ...
src/views/oa/editExamineStaffList.vue 0 → 100644
  1 +<template>
  2 + <div class="edit-examine-staff-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('editExamineStaff.title') }}</span>
  6 + <div class="header-tools">
  7 + <el-button type="primary" size="small" @click="_goBack">
  8 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  9 + </el-button>
  10 + </div>
  11 + </div>
  12 +
  13 + <el-form ref="form" :model="editExamineStaffInfo" label-width="120px">
  14 + <el-row>
  15 + <el-col :span="24">
  16 + <el-form-item :label="$t('editExamineStaff.staffName')">
  17 + <el-input v-model="editExamineStaffInfo.staffName" disabled
  18 + :placeholder="$t('editExamineStaff.staffNamePlaceholder')">
  19 + </el-input>
  20 + </el-form-item>
  21 + </el-col>
  22 + </el-row>
  23 +
  24 + <el-row>
  25 + <el-col :span="24">
  26 + <el-form-item :label="$t('editExamineStaff.projects')">
  27 + <el-checkbox-group v-model="editExamineStaffInfo.projectIds">
  28 + <el-checkbox v-for="(item, index) in editExamineStaffInfo.allProjects" :key="index"
  29 + :label="item.projectId">
  30 + {{ item.name }}
  31 + </el-checkbox>
  32 + </el-checkbox-group>
  33 + </el-form-item>
  34 + </el-col>
  35 + </el-row>
  36 +
  37 + <el-row>
  38 + <el-col :span="24">
  39 + <el-form-item :label="$t('editExamineStaff.staffPhoto')">
  40 + <upload-image-url ref="uploadImage" :image-count="1" @notifyUploadImage="handleUploadImage">
  41 + </upload-image-url>
  42 + </el-form-item>
  43 + </el-col>
  44 + </el-row>
  45 +
  46 + <el-row>
  47 + <el-col :span="24">
  48 + <el-form-item :label="$t('editExamineStaff.post')">
  49 + <el-input v-model="editExamineStaffInfo.post" :placeholder="$t('editExamineStaff.postPlaceholder')">
  50 + </el-input>
  51 + </el-form-item>
  52 + </el-col>
  53 + </el-row>
  54 +
  55 + <el-row>
  56 + <el-col :span="24">
  57 + <el-form-item :label="$t('editExamineStaff.introduction')">
  58 + <el-input type="textarea" :rows="5" v-model="editExamineStaffInfo.introduction">
  59 + </el-input>
  60 + </el-form-item>
  61 + </el-col>
  62 + </el-row>
  63 + </el-form>
  64 +
  65 + <div class="footer-buttons">
  66 + <el-button type="warning" @click="_goBack">
  67 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  68 + </el-button>
  69 + <el-button type="primary" @click="_updateExamineStaff">
  70 + <i class="el-icon-check"></i>{{ $t('common.submit') }}
  71 + </el-button>
  72 + </div>
  73 + </el-card>
  74 + </div>
  75 +</template>
  76 +
  77 +<script>
  78 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  79 +import { updateExamineStaff, listExamineProjects, listExamineStaffs } from '@/api/oa/editExamineStaffApi'
  80 +import { getCommunityId } from '@/api/community/communityApi'
  81 +
  82 +export default {
  83 + name: 'EditExamineStaffList',
  84 + components: {
  85 + UploadImageUrl
  86 + },
  87 + data() {
  88 + return {
  89 + editExamineStaffInfo: {
  90 + esId: '',
  91 + staffName: '',
  92 + staffId: '',
  93 + post: '',
  94 + introduction: '',
  95 + headerImg: '',
  96 + allProjects: [],
  97 + projectIds: []
  98 + },
  99 + communityId: ''
  100 + }
  101 + },
  102 + created() {
  103 + this.communityId = getCommunityId()
  104 + this.editExamineStaffInfo.esId = this.$route.query.esId
  105 + this._listExamineProjects()
  106 + this._listExamineStaffs()
  107 + },
  108 + methods: {
  109 + handleUploadImage(images) {
  110 + if (images.length > 0) {
  111 + this.editExamineStaffInfo.headerImg = images[0].fileId
  112 + } else {
  113 + this.editExamineStaffInfo.headerImg = ''
  114 + }
  115 + },
  116 + async _updateExamineStaff() {
  117 + try {
  118 + if (!this.validateForm()) {
  119 + return
  120 + }
  121 +
  122 + this.editExamineStaffInfo.communityId = this.communityId
  123 + const res = await updateExamineStaff(this.editExamineStaffInfo)
  124 +
  125 + if (res.code === 0) {
  126 + this.$message.success(this.$t('common.updateSuccess'))
  127 + this._goBack()
  128 + } else {
  129 + this.$message.error(res.msg)
  130 + }
  131 + } catch (error) {
  132 + this.$message.error(this.$t('common.updateError'))
  133 + }
  134 + },
  135 + validateForm() {
  136 + if (!this.editExamineStaffInfo.staffId) {
  137 + this.$message.error(this.$t('editExamineStaff.staffNameRequired'))
  138 + return false
  139 + }
  140 + if (!this.editExamineStaffInfo.post) {
  141 + this.$message.error(this.$t('editExamineStaff.postRequired'))
  142 + return false
  143 + }
  144 + return true
  145 + },
  146 + async _listExamineProjects() {
  147 + try {
  148 + const params = {
  149 + page: 1,
  150 + row: 100,
  151 + communityId: this.communityId
  152 + }
  153 + const { data } = await listExamineProjects(params)
  154 + this.editExamineStaffInfo.allProjects = data
  155 + } catch (error) {
  156 + this.$message.error(this.$t('editExamineStaff.fetchProjectsError'))
  157 + }
  158 + },
  159 + async _listExamineStaffs() {
  160 + try {
  161 + const params = {
  162 + page: 1,
  163 + row: 1,
  164 + esId: this.editExamineStaffInfo.esId,
  165 + communityId: this.communityId
  166 + }
  167 + const { data } = await listExamineStaffs(params)
  168 +
  169 + if (data && data.length > 0) {
  170 + Object.assign(this.editExamineStaffInfo, data[0])
  171 + this.editExamineStaffInfo.projectIds = data[0].projects.map(item => item.projectId)
  172 +
  173 + if (this.editExamineStaffInfo.headerImg) {
  174 + this.$refs.uploadImage.open([this.editExamineStaffInfo.headerImg])
  175 + }
  176 + }
  177 + } catch (error) {
  178 + this.$message.error(this.$t('editExamineStaff.fetchStaffError'))
  179 + }
  180 + },
  181 + _goBack() {
  182 + this.$router.go(-1)
  183 + }
  184 + }
  185 +}
  186 +</script>
  187 +
  188 +<style lang="scss" scoped>
  189 +.edit-examine-staff-container {
  190 + padding: 20px;
  191 +
  192 + .box-card {
  193 + width: 100%;
  194 +
  195 + .clearfix {
  196 + display: flex;
  197 + justify-content: space-between;
  198 + align-items: center;
  199 + }
  200 +
  201 + .header-tools {
  202 + float: right;
  203 + }
  204 +
  205 + .footer-buttons {
  206 + text-align: right;
  207 + margin-top: 20px;
  208 +
  209 + .el-button {
  210 + margin-left: 10px;
  211 + }
  212 + }
  213 + }
  214 +
  215 + .el-form-item {
  216 + margin-bottom: 22px;
  217 + }
  218 +
  219 + .el-checkbox {
  220 + margin-right: 15px;
  221 + }
  222 +}
  223 +</style>
0 224 \ No newline at end of file
... ...
src/views/oa/editOwnerVotingLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + editOwnerVoting: {
  4 + title: 'Edit Voting',
  5 + voteName: 'Vote Name',
  6 + voteNamePlaceholder: 'Required, please enter vote name',
  7 + type: 'Type',
  8 + typePlaceholder: 'Required, please select type',
  9 + singleChoice: 'Single Choice',
  10 + multipleChoice: 'Multiple Choice',
  11 + startTime: 'Start Time',
  12 + startTimePlaceholder: 'Required, please select start time',
  13 + endTime: 'End Time',
  14 + endTimePlaceholder: 'Required, please select end time',
  15 + option: 'Option',
  16 + optionPlaceholder: 'Required, please enter option content',
  17 + addOption: 'Add Option',
  18 + deleteOption: 'Delete Option',
  19 + description: 'Description',
  20 + descriptionPlaceholder: 'Required, please enter description',
  21 + voteRooms: 'Vote Rooms',
  22 + houseVote: 'house(s) voting',
  23 + reselect: 'Reselect',
  24 + validate: {
  25 + voteNameRequired: 'Vote name is required',
  26 + voteNameLength: 'Vote name length must be between 1 and 256 characters',
  27 + startTimeRequired: 'Start time is required',
  28 + endTimeRequired: 'End time is required'
  29 + },
  30 + saveSuccess: 'Save successfully',
  31 + saveFailed: 'Save failed'
  32 + },
  33 + selectRooms: {
  34 + title: 'Select Rooms',
  35 + buildingUnit: 'Building Unit',
  36 + roomInfo: 'Room Information',
  37 + unit: 'Unit'
  38 + }
  39 + },
  40 + zh: {
  41 + editOwnerVoting: {
  42 + title: '编辑投票',
  43 + voteName: '投票名称',
  44 + voteNamePlaceholder: '必填,请填写投票名称',
  45 + type: '类型',
  46 + typePlaceholder: '必填,请选择类型',
  47 + singleChoice: '单选',
  48 + multipleChoice: '多选',
  49 + startTime: '开始时间',
  50 + startTimePlaceholder: '必填,请选择开始时间',
  51 + endTime: '结束时间',
  52 + endTimePlaceholder: '必填,请选择结束时间',
  53 + option: '选项',
  54 + optionPlaceholder: '必填,请填写选项内容',
  55 + addOption: '增加选项',
  56 + deleteOption: '删除选项',
  57 + description: '投票说明',
  58 + descriptionPlaceholder: '必填,请输入投票说明',
  59 + voteRooms: '投票房屋',
  60 + houseVote: '户投票',
  61 + reselect: '重新选择',
  62 + validate: {
  63 + voteNameRequired: '名称不能为空',
  64 + voteNameLength: '名称长度必须在1位至256位',
  65 + startTimeRequired: '开始时间不能为空',
  66 + endTimeRequired: '结束时间不能为空'
  67 + },
  68 + saveSuccess: '修改成功',
  69 + saveFailed: '修改失败'
  70 + },
  71 + selectRooms: {
  72 + title: '选择房屋',
  73 + buildingUnit: '楼栋单元',
  74 + roomInfo: '房屋信息',
  75 + unit: '单元'
  76 + }
  77 + }
  78 +}
0 79 \ No newline at end of file
... ...
src/views/oa/editOwnerVotingList.vue 0 → 100644
  1 +<template>
  2 + <div class="edit-owner-voting-container">
  3 + <el-card>
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('editOwnerVoting.title') }}</span>
  6 + </div>
  7 +
  8 + <el-row :gutter="20">
  9 + <el-col :span="24">
  10 + <el-form ref="form" :model="editOwnerVotingInfo" label-width="120px">
  11 + <el-row :gutter="20">
  12 + <el-col :span="12">
  13 + <el-form-item :label="$t('editOwnerVoting.voteName')" prop="qaName">
  14 + <el-input v-model="editOwnerVotingInfo.qaName" :placeholder="$t('editOwnerVoting.voteNamePlaceholder')"
  15 + clearable />
  16 + </el-form-item>
  17 + </el-col>
  18 + <el-col :span="12">
  19 + <el-form-item :label="$t('editOwnerVoting.type')" prop="titleType">
  20 + <el-select v-model="editOwnerVotingInfo.titleType" :placeholder="$t('editOwnerVoting.typePlaceholder')"
  21 + @change="changeAddTitleType" style="width:100%">
  22 + <el-option :label="$t('editOwnerVoting.singleChoice')" value="1001" />
  23 + <el-option :label="$t('editOwnerVoting.multipleChoice')" value="2002" />
  24 + </el-select>
  25 + </el-form-item>
  26 + </el-col>
  27 + </el-row>
  28 +
  29 + <el-row :gutter="20">
  30 + <el-col :span="12">
  31 + <el-form-item :label="$t('editOwnerVoting.startTime')" prop="startTime">
  32 + <el-date-picker v-model="editOwnerVotingInfo.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
  33 + :placeholder="$t('editOwnerVoting.startTimePlaceholder')" style="width:100%" />
  34 + </el-form-item>
  35 + </el-col>
  36 + <el-col :span="12">
  37 + <el-form-item :label="$t('editOwnerVoting.endTime')" prop="endTime">
  38 + <el-date-picker v-model="editOwnerVotingInfo.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
  39 + :placeholder="$t('editOwnerVoting.endTimePlaceholder')" style="width:100%" />
  40 + </el-form-item>
  41 + </el-col>
  42 + </el-row>
  43 +
  44 + <el-form-item v-for="(item, index) in editOwnerVotingInfo.titleValues" :key="index"
  45 + :label="`${$t('editOwnerVoting.option')}${item.seq}`">
  46 + <el-row :gutter="20">
  47 + <el-col :span="18">
  48 + <el-input v-model="item.qaValue" :placeholder="$t('editOwnerVoting.optionPlaceholder')" />
  49 + </el-col>
  50 + <el-col :span="5">
  51 + <el-button v-if="index === editOwnerVotingInfo.titleValues.length - 1" type="text" @click="addTitleValue">
  52 + {{ $t('editOwnerVoting.addOption') }}
  53 + </el-button>
  54 + <el-button v-else type="text" @click="deleteTitleValue(item.seq)">
  55 + {{ $t('editOwnerVoting.deleteOption') }}
  56 + </el-button>
  57 + </el-col>
  58 + </el-row>
  59 + </el-form-item>
  60 +
  61 + <el-form-item :label="$t('editOwnerVoting.description')">
  62 + <el-input type="textarea" :rows="5" v-model="editOwnerVotingInfo.content"
  63 + :placeholder="$t('editOwnerVoting.descriptionPlaceholder')" />
  64 + </el-form-item>
  65 +
  66 + <el-form-item :label="$t('editOwnerVoting.voteRooms')">
  67 + <div v-show="editOwnerVotingInfo.updateRoomIds">
  68 + <select-rooms ref="selectRooms" @notifySelectRooms="handleSelectRooms" />
  69 + </div>
  70 + <div v-if="!editOwnerVotingInfo.updateRoomIds">
  71 + <span>{{ editOwnerVotingInfo.voteCount }}{{ $t('editOwnerVoting.houseVote') }}</span>
  72 + <el-button type="text" @click="updateRoomIdsMethod">
  73 + {{ $t('editOwnerVoting.reselect') }}
  74 + </el-button>
  75 + </div>
  76 + </el-form-item>
  77 +
  78 + <el-form-item>
  79 + <el-button type="primary" @click="saveOwnerVoting">
  80 + <i class="el-icon-check"></i>&nbsp;{{ $t('common.save') }}
  81 + </el-button>
  82 + <el-button type="warning" @click="goBack">
  83 + {{ $t('common.cancel') }}
  84 + </el-button>
  85 + </el-form-item>
  86 + </el-form>
  87 + </el-col>
  88 + </el-row>
  89 + </el-card>
  90 + </div>
  91 +</template>
  92 +
  93 +<script>
  94 +import SelectRooms from '@/components/room/selectRooms'
  95 +import { updateOwnerVote, listOwnerVote } from '@/api/oa/editOwnerVotingApi'
  96 +import { getCommunityId } from '@/api/community/communityApi'
  97 +
  98 +export default {
  99 + name: 'EditOwnerVotingList',
  100 + components: {
  101 + SelectRooms
  102 + },
  103 + data() {
  104 + return {
  105 + editOwnerVotingInfo: {
  106 + qaId: '',
  107 + qaName: '',
  108 + startTime: '',
  109 + endTime: '',
  110 + communityId: '',
  111 + content: '',
  112 + titleType: '',
  113 + titleValues: [],
  114 + roomIds: [],
  115 + updateRoomIds: false,
  116 + voteCount: 0
  117 + }
  118 + }
  119 + },
  120 + created() {
  121 + this.communityId = getCommunityId()
  122 + this.editOwnerVotingInfo.qaId = this.$route.query.qaId
  123 + this.loadOwnerVoting()
  124 + },
  125 + methods: {
  126 + async loadOwnerVoting() {
  127 + try {
  128 + const params = {
  129 + page: 1,
  130 + row: 1,
  131 + qaId: this.editOwnerVotingInfo.qaId,
  132 + communityId: this.communityId
  133 + }
  134 + const { data } = await listOwnerVote(params)
  135 + Object.assign(this.editOwnerVotingInfo, data[0])
  136 + } catch (error) {
  137 + console.error('Failed to load voting data:', error)
  138 + }
  139 + },
  140 + handleSelectRooms(selectRooms) {
  141 + this.editOwnerVotingInfo.roomIds = selectRooms.map(item => item.roomId)
  142 + },
  143 +
  144 + async saveOwnerVoting() {
  145 +
  146 +
  147 + try {
  148 + await updateOwnerVote(this.editOwnerVotingInfo)
  149 + this.$message.success(this.$t('editOwnerVoting.saveSuccess'))
  150 + this.goBack()
  151 + } catch (error) {
  152 + this.$message.error(error.message || this.$t('editOwnerVoting.saveFailed'))
  153 + }
  154 + },
  155 + changeAddTitleType() {
  156 + const type = this.editOwnerVotingInfo.titleType
  157 + if (type === '1001') {
  158 + this.editOwnerVotingInfo.titleValues = [{ qaValue: '', seq: 1 }]
  159 + } else if (type === '2002') {
  160 + this.editOwnerVotingInfo.titleValues = [
  161 + { qaValue: '', seq: 1 },
  162 + { qaValue: '', seq: 2 }
  163 + ]
  164 + }
  165 + },
  166 + addTitleValue() {
  167 + this.editOwnerVotingInfo.titleValues.push({
  168 + qaValue: '',
  169 + seq: this.editOwnerVotingInfo.titleValues.length + 1
  170 + })
  171 + },
  172 + deleteTitleValue(seq) {
  173 + this.editOwnerVotingInfo.titleValues = this.editOwnerVotingInfo.titleValues
  174 + .filter(item => item.seq !== seq)
  175 + .map((item, index) => ({ ...item, seq: index + 1 }))
  176 + },
  177 + updateRoomIdsMethod() {
  178 + this.editOwnerVotingInfo.updateRoomIds = true
  179 + this.$nextTick(() => {
  180 + this.$refs.selectRooms.open()
  181 + })
  182 + },
  183 + goBack() {
  184 + this.$router.go(-1)
  185 + }
  186 + }
  187 +}
  188 +</script>
  189 +
  190 +<style scoped>
  191 +.edit-owner-voting-container {
  192 + padding: 20px;
  193 +}
  194 +</style>
0 195 \ No newline at end of file
... ...
src/views/oa/examineProjectManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + examineProjectManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + namePlaceholder: 'Please enter project name',
  7 + postPlaceholder: 'Please enter post',
  8 + statePlaceholder: 'Please select status'
  9 + },
  10 + list: {
  11 + title: 'Examination Projects'
  12 + },
  13 + table: {
  14 + name: 'Project Name',
  15 + post: 'Post',
  16 + weight: 'Weight',
  17 + state: 'Status'
  18 + },
  19 + form: {
  20 + name: 'Project Name',
  21 + namePlaceholder: 'Required, please enter project name',
  22 + post: 'Post',
  23 + postPlaceholder: 'Required, please select post',
  24 + commonPost: 'Common Post',
  25 + weight: 'Weight',
  26 + weightPlaceholder: 'Required, please enter weight',
  27 + state: 'Status',
  28 + statePlaceholder: 'Required, please select status'
  29 + },
  30 + status: {
  31 + enable: 'Enable',
  32 + disable: 'Disable'
  33 + },
  34 + validate: {
  35 + idRequired: 'ID is required',
  36 + nameRequired: 'Project name is required',
  37 + nameMaxLength: 'Project name cannot exceed 64 characters',
  38 + postRequired: 'Post is required',
  39 + postMaxLength: 'Post cannot exceed 30 characters',
  40 + weightRequired: 'Weight is required',
  41 + weightMaxLength: 'Weight cannot exceed 12 characters',
  42 + stateRequired: 'Status is required',
  43 + stateMaxLength: 'Status cannot exceed 12 characters'
  44 + },
  45 + add: {
  46 + title: 'Add Examination Project',
  47 + success: 'Added successfully',
  48 + error: 'Failed to add'
  49 + },
  50 + edit: {
  51 + title: 'Edit Examination Project',
  52 + success: 'Updated successfully',
  53 + error: 'Failed to update'
  54 + },
  55 + delete: {
  56 + title: 'Delete Confirmation',
  57 + confirmText: 'Are you sure to delete this examination project?',
  58 + success: 'Deleted successfully',
  59 + error: 'Failed to delete'
  60 + },
  61 + fetchError: 'Failed to fetch data'
  62 + }
  63 + },
  64 + zh: {
  65 + examineProjectManage: {
  66 + search: {
  67 + title: '查询条件',
  68 + namePlaceholder: '请输入项目名称',
  69 + postPlaceholder: '请输入岗位',
  70 + statePlaceholder: '请选择状态'
  71 + },
  72 + list: {
  73 + title: '考核项目'
  74 + },
  75 + table: {
  76 + name: '项目名称',
  77 + post: '岗位',
  78 + weight: '比重',
  79 + state: '状态'
  80 + },
  81 + form: {
  82 + name: '项目名称',
  83 + namePlaceholder: '必填,请填写项目名称',
  84 + post: '岗位',
  85 + postPlaceholder: '必填,请选择岗位',
  86 + commonPost: '通用岗位',
  87 + weight: '比重',
  88 + weightPlaceholder: '必填,请填写比重',
  89 + state: '状态',
  90 + statePlaceholder: '必填,请选择状态'
  91 + },
  92 + status: {
  93 + enable: '启用',
  94 + disable: '停用'
  95 + },
  96 + validate: {
  97 + idRequired: '编号不能为空',
  98 + nameRequired: '项目名称不能为空',
  99 + nameMaxLength: '项目名称不能超过64个字符',
  100 + postRequired: '岗位不能为空',
  101 + postMaxLength: '岗位编号不能超过30个字符',
  102 + weightRequired: '比重不能为空',
  103 + weightMaxLength: '比重不能超过12个字符',
  104 + stateRequired: '状态不能为空',
  105 + stateMaxLength: '状态不能超过12个字符'
  106 + },
  107 + add: {
  108 + title: '添加考核项目',
  109 + success: '添加成功',
  110 + error: '添加失败'
  111 + },
  112 + edit: {
  113 + title: '修改考核项目',
  114 + success: '修改成功',
  115 + error: '修改失败'
  116 + },
  117 + delete: {
  118 + title: '删除确认',
  119 + confirmText: '确定删除该考核项目吗?',
  120 + success: '删除成功',
  121 + error: '删除失败'
  122 + },
  123 + fetchError: '获取数据失败'
  124 + }
  125 + }
  126 +}
0 127 \ No newline at end of file
... ...
src/views/oa/examineProjectManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="examine-project-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('examineProjectManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.name" :placeholder="$t('examineProjectManage.search.namePlaceholder')"
  11 + clearable />
  12 + </el-col>
  13 + <el-col :span="6">
  14 + <el-input v-model="searchForm.post" :placeholder="$t('examineProjectManage.search.postPlaceholder')"
  15 + clearable />
  16 + </el-col>
  17 + <el-col :span="6">
  18 + <el-select v-model="searchForm.state" :placeholder="$t('examineProjectManage.search.statePlaceholder')"
  19 + style="width:100%">
  20 + <el-option :label="$t('examineProjectManage.status.enable')" value="Y" />
  21 + <el-option :label="$t('examineProjectManage.status.disable')" value="N" />
  22 + </el-select>
  23 + </el-col>
  24 + <el-col :span="6">
  25 + <el-button type="primary" @click="handleSearch">
  26 + {{ $t('common.search') }}
  27 + </el-button>
  28 + <el-button @click="handleReset">
  29 + {{ $t('common.reset') }}
  30 + </el-button>
  31 + </el-col>
  32 + </el-row>
  33 + </el-card>
  34 +
  35 + <!-- 考核项目列表 -->
  36 + <el-card class="list-wrapper">
  37 + <div slot="header" class="flex justify-between">
  38 + <span>{{ $t('examineProjectManage.list.title') }}</span>
  39 + <el-button type="primary" size="small" style="float:right" @click="handleAdd">
  40 + {{ $t('common.add') }}
  41 + </el-button>
  42 + </div>
  43 +
  44 + <el-table v-loading="loading" :data="tableData" border style="width:100%">
  45 + <el-table-column prop="name" :label="$t('examineProjectManage.table.name')" align="center" />
  46 + <el-table-column prop="post" :label="$t('examineProjectManage.table.post')" align="center" />
  47 + <el-table-column prop="weight" :label="$t('examineProjectManage.table.weight')" align="center">
  48 + <template slot-scope="scope">
  49 + {{ scope.row.weight }}%
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column prop="state" :label="$t('examineProjectManage.table.state')" align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.state === 'Y' ? $t('examineProjectManage.status.enable') :
  55 + $t('examineProjectManage.status.disable') }}
  56 + </template>
  57 + </el-table-column>
  58 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  59 + <template slot-scope="scope">
  60 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  61 + {{ $t('common.edit') }}
  62 + </el-button>
  63 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  64 + {{ $t('common.delete') }}
  65 + </el-button>
  66 + </template>
  67 + </el-table-column>
  68 + </el-table>
  69 +
  70 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  71 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  72 + @current-change="handleCurrentChange" />
  73 + </el-card>
  74 +
  75 + <!-- 组件 -->
  76 + <add-examine-project ref="addExamineProject" @success="handleSuccess" />
  77 + <edit-examine-project ref="editExamineProject" @success="handleSuccess" />
  78 + <delete-examine-project ref="deleteExamineProject" @success="handleSuccess" />
  79 + </div>
  80 +</template>
  81 +
  82 +<script>
  83 +import { listExamineProject } from '@/api/oa/examineProjectManageApi'
  84 +import AddExamineProject from '@/components/oa/addExamineProject'
  85 +import EditExamineProject from '@/components/oa/editExamineProject'
  86 +import DeleteExamineProject from '@/components/oa/deleteExamineProject'
  87 +import { getCommunityId } from '@/api/community/communityApi'
  88 +
  89 +export default {
  90 + name: 'ExamineProjectManageList',
  91 + components: {
  92 + AddExamineProject,
  93 + EditExamineProject,
  94 + DeleteExamineProject
  95 + },
  96 + data() {
  97 + return {
  98 + loading: false,
  99 + searchForm: {
  100 + name: '',
  101 + post: '',
  102 + state: '',
  103 + communityId: getCommunityId()
  104 + },
  105 + tableData: [],
  106 + page: {
  107 + current: 1,
  108 + size: 10,
  109 + total: 0
  110 + }
  111 + }
  112 + },
  113 + created() {
  114 + this.getList()
  115 + },
  116 + methods: {
  117 + async getList() {
  118 + try {
  119 + this.loading = true
  120 + const params = {
  121 + page: this.page.current,
  122 + row: this.page.size,
  123 + ...this.searchForm
  124 + }
  125 + const { data, total } = await listExamineProject(params)
  126 + this.tableData = data
  127 + this.page.total = total
  128 + } catch (error) {
  129 + this.$message.error(this.$t('examineProjectManage.fetchError'))
  130 + } finally {
  131 + this.loading = false
  132 + }
  133 + },
  134 + handleSearch() {
  135 + this.page.current = 1
  136 + this.getList()
  137 + },
  138 + handleReset() {
  139 + this.searchForm = {
  140 + name: '',
  141 + post: '',
  142 + state: '',
  143 + communityId: getCommunityId()
  144 + }
  145 + this.handleSearch()
  146 + },
  147 + handleAdd() {
  148 + this.$refs.addExamineProject.open()
  149 + },
  150 + handleEdit(row) {
  151 + this.$refs.editExamineProject.open(row)
  152 + },
  153 + handleDelete(row) {
  154 + this.$refs.deleteExamineProject.open(row)
  155 + },
  156 + handleSuccess() {
  157 + this.getList()
  158 + },
  159 + handleSizeChange(val) {
  160 + this.page.size = val
  161 + this.getList()
  162 + },
  163 + handleCurrentChange(val) {
  164 + this.page.current = val
  165 + this.getList()
  166 + }
  167 + }
  168 +}
  169 +</script>
  170 +
  171 +<style lang="scss" scoped>
  172 +.examine-project-manage-container {
  173 + padding: 20px;
  174 +
  175 + .search-wrapper {
  176 + margin-bottom: 20px;
  177 +
  178 + .el-row {
  179 + margin-bottom: -20px;
  180 + }
  181 +
  182 + .el-col {
  183 + margin-bottom: 20px;
  184 + }
  185 + }
  186 +
  187 + .list-wrapper {
  188 + .el-pagination {
  189 + margin-top: 20px;
  190 + text-align: right;
  191 + }
  192 + }
  193 +}
  194 +</style>
0 195 \ No newline at end of file
... ...
src/views/oa/examineStaffManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + examineStaffManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + staffName: 'Please enter staff name',
  7 + projectName: 'Please enter project name'
  8 + },
  9 + list: {
  10 + title: 'Assessment Staff',
  11 + add: 'Add'
  12 + },
  13 + table: {
  14 + face: 'Face',
  15 + staffId: 'Staff ID',
  16 + staffName: 'Staff Name',
  17 + post: 'Post',
  18 + projects: 'Assessment Projects',
  19 + operation: 'Operation'
  20 + },
  21 + delete: {
  22 + title: 'Confirm Operation',
  23 + confirm: 'Are you sure to delete this assessment staff?',
  24 + success: 'Delete successfully',
  25 + error: 'Delete failed'
  26 + },
  27 + fetchError: 'Failed to fetch assessment staff data'
  28 + }
  29 + },
  30 + zh: {
  31 + examineStaffManage: {
  32 + search: {
  33 + title: '查询条件',
  34 + staffName: '请输入员工名称',
  35 + projectName: '请输入考核项目'
  36 + },
  37 + list: {
  38 + title: '考核人员',
  39 + add: '添加'
  40 + },
  41 + table: {
  42 + face: '人脸',
  43 + staffId: '员工编号',
  44 + staffName: '员工名称',
  45 + post: '岗位',
  46 + projects: '考核项目',
  47 + operation: '操作'
  48 + },
  49 + delete: {
  50 + title: '确认操作',
  51 + confirm: '确定删除该考核人员吗?',
  52 + success: '删除成功',
  53 + error: '删除失败'
  54 + },
  55 + fetchError: '获取考核人员数据失败'
  56 + }
  57 + }
  58 +}
0 59 \ No newline at end of file
... ...
src/views/oa/examineStaffManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="examine-staff-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('examineStaffManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.staffName" :placeholder="$t('examineStaffManage.search.staffName')" clearable
  11 + @keyup.enter.native="handleSearch" />
  12 + </el-col>
  13 + <el-col :span="6">
  14 + <el-input v-model="searchForm.projectName" :placeholder="$t('examineStaffManage.search.projectName')" clearable
  15 + @keyup.enter.native="handleSearch" />
  16 + </el-col>
  17 + <el-col :span="4">
  18 + <el-button type="primary" @click="handleSearch">
  19 + {{ $t('common.search') }}
  20 + </el-button>
  21 + <el-button @click="handleReset">
  22 + {{ $t('common.reset') }}
  23 + </el-button>
  24 + </el-col>
  25 + </el-row>
  26 + </el-card>
  27 +
  28 + <!-- 考核人员列表 -->
  29 + <el-card class="list-wrapper margin-top">
  30 + <div slot="header" class="flex justify-between">
  31 + <div>{{ $t('examineStaffManage.list.title') }}</div>
  32 + <el-button type="primary" size="small" @click="handleAdd">
  33 + {{ $t('common.add') }}
  34 + </el-button>
  35 + </div>
  36 +
  37 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  38 + <el-table-column :label="$t('examineStaffManage.table.face')" align="center" width="120">
  39 + <template slot-scope="scope">
  40 + <div style="position: relative; display: inline-block; cursor: pointer;"
  41 + @click="showImage(scope.row.headerImg || '/img/noPhoto.jpg')">
  42 + <el-image style="width: 50px; height: 50px;" :src="scope.row.headerImg || '/img/noPhoto.jpg'" fit="cover" />
  43 + <img src="/img/icon-bigimg.png" style="position: absolute; right: 0; bottom: 0;" width="20" height="20"
  44 + alt="">
  45 + </div>
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column prop="staffId" :label="$t('examineStaffManage.table.staffId')" align="center" />
  49 + <el-table-column prop="staffName" :label="$t('examineStaffManage.table.staffName')" align="center" />
  50 + <el-table-column prop="post" :label="$t('examineStaffManage.table.post')" align="center" />
  51 + <el-table-column :label="$t('examineStaffManage.table.projects')" align="center">
  52 + <template slot-scope="scope">
  53 + <div v-for="(item, index) in scope.row.projects" :key="index">
  54 + {{ item.projectName }}
  55 + </div>
  56 + </template>
  57 + </el-table-column>
  58 + <el-table-column :label="$t('common.operation')" align="center" width="200" fixed="right">
  59 + <template slot-scope="scope">
  60 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  61 + {{ $t('common.edit') }}
  62 + </el-button>
  63 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  64 + {{ $t('common.delete') }}
  65 + </el-button>
  66 + </template>
  67 + </el-table-column>
  68 + </el-table>
  69 +
  70 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  71 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  72 + @current-change="handleCurrentChange" />
  73 + </el-card>
  74 +
  75 + <!-- 组件 -->
  76 + <delete-examine-staff ref="deleteDialog" @success="handleSuccess" />
  77 + <view-image ref="imageViewer" />
  78 + </div>
  79 +</template>
  80 +
  81 +<script>
  82 +import { listExamineStaff } from '@/api/oa/examineStaffManageApi'
  83 +import { getCommunityId } from '@/api/community/communityApi'
  84 +import DeleteExamineStaff from '@/components/oa/deleteExamineStaff'
  85 +import ViewImage from '@/components/system/viewImage'
  86 +
  87 +export default {
  88 + name: 'ExamineStaffManageList',
  89 + components: {
  90 + DeleteExamineStaff,
  91 + ViewImage
  92 + },
  93 + data() {
  94 + return {
  95 + loading: false,
  96 + searchForm: {
  97 + staffName: '',
  98 + projectName: '',
  99 + communityId: ''
  100 + },
  101 + tableData: [],
  102 + page: {
  103 + current: 1,
  104 + size: 10,
  105 + total: 0
  106 + }
  107 + }
  108 + },
  109 + created() {
  110 + this.searchForm.communityId = getCommunityId()
  111 + this.getList()
  112 + },
  113 + methods: {
  114 + async getList() {
  115 + try {
  116 + this.loading = true
  117 + const params = {
  118 + page: this.page.current,
  119 + row: this.page.size,
  120 + ...this.searchForm
  121 + }
  122 + const { data, total } = await listExamineStaff(params)
  123 + this.tableData = data
  124 + this.page.total = total
  125 + } catch (error) {
  126 + this.$message.error(this.$t('examineStaffManage.fetchError'))
  127 + } finally {
  128 + this.loading = false
  129 + }
  130 + },
  131 + handleSearch() {
  132 + this.page.current = 1
  133 + this.getList()
  134 + },
  135 + handleReset() {
  136 + this.searchForm.staffName = ''
  137 + this.searchForm.projectName = ''
  138 + this.handleSearch()
  139 + },
  140 + handleAdd() {
  141 + this.$router.push('/views/oa/addExamineStaff')
  142 + },
  143 + handleEdit(row) {
  144 + this.$router.push(`/views/oa/editExamineStaff?esId=${row.esId}`)
  145 + },
  146 + handleDelete(row) {
  147 + this.$refs.deleteDialog.open(row)
  148 + },
  149 + showImage(url) {
  150 + this.$refs.imageViewer.open(url)
  151 + },
  152 + handleSuccess() {
  153 + this.getList()
  154 + },
  155 + handleSizeChange(val) {
  156 + this.page.size = val
  157 + this.getList()
  158 + },
  159 + handleCurrentChange(val) {
  160 + this.page.current = val
  161 + this.getList()
  162 + }
  163 + }
  164 +}
  165 +</script>
  166 +
  167 +<style lang="scss" scoped>
  168 +.examine-staff-manage-container {
  169 + padding: 20px;
  170 +
  171 + .search-wrapper {
  172 + margin-bottom: 20px;
  173 +
  174 + .el-row {
  175 + margin-bottom: -20px;
  176 + }
  177 + }
  178 +
  179 + .list-wrapper {
  180 + .el-pagination {
  181 + margin-top: 20px;
  182 + text-align: right;
  183 + }
  184 + }
  185 +}
  186 +</style>
0 187 \ No newline at end of file
... ...
src/views/oa/examineStaffValueLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + examineStaffValue: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + staffName: 'Please select staff name',
  7 + projectName: 'Please select examine project'
  8 + },
  9 + list: {
  10 + title: 'Examine Records'
  11 + },
  12 + table: {
  13 + year: 'Year',
  14 + staffId: 'Staff ID',
  15 + staffName: 'Staff Name',
  16 + projectName: 'Examine Project',
  17 + weight: 'Weight',
  18 + examineValue: 'Score',
  19 + actualScore: 'Actual Score',
  20 + ownerName: 'Rater',
  21 + roomName: 'Room',
  22 + createTime: 'Rating Time'
  23 + },
  24 + fetchError: 'Failed to fetch examine records'
  25 + }
  26 + },
  27 + zh: {
  28 + examineStaffValue: {
  29 + search: {
  30 + title: '查询条件',
  31 + staffName: '请选择员工名称',
  32 + projectName: '请选择考核项目'
  33 + },
  34 + list: {
  35 + title: '考核记录'
  36 + },
  37 + table: {
  38 + year: '年度',
  39 + staffId: '员工ID',
  40 + staffName: '员工名称',
  41 + projectName: '考核项目',
  42 + weight: '权重',
  43 + examineValue: '评分',
  44 + actualScore: '实际得分',
  45 + ownerName: '评分人',
  46 + roomName: '房屋',
  47 + createTime: '评分时间'
  48 + },
  49 + fetchError: '获取考核记录失败'
  50 + }
  51 + }
  52 +}
0 53 \ No newline at end of file
... ...
src/views/oa/examineStaffValueList.vue 0 → 100644
  1 +<template>
  2 + <div class="examine-staff-value-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('examineStaffValue.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.staffName" :placeholder="$t('examineStaffValue.search.staffName')" clearable
  11 + @keyup.enter.native="handleSearch" />
  12 + </el-col>
  13 + <el-col :span="8">
  14 + <el-input v-model="searchForm.projectName" :placeholder="$t('examineStaffValue.search.projectName')" clearable
  15 + @keyup.enter.native="handleSearch" />
  16 + </el-col>
  17 + <el-col :span="4">
  18 + <el-button type="primary" @click="handleSearch">
  19 + <i class="el-icon-search"></i>
  20 + {{ $t('common.search') }}
  21 + </el-button>
  22 + <el-button @click="handleReset">
  23 + <i class="el-icon-refresh"></i>
  24 + {{ $t('common.reset') }}
  25 + </el-button>
  26 + </el-col>
  27 + </el-row>
  28 + </el-card>
  29 +
  30 + <!-- 考核记录列表 -->
  31 + <el-card class="list-wrapper">
  32 + <div slot="header" class="flex justify-between">
  33 + <span>{{ $t('examineStaffValue.list.title') }}</span>
  34 + </div>
  35 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  36 + <el-table-column prop="esYear" :label="$t('examineStaffValue.table.year')" align="center" />
  37 + <el-table-column prop="staffId" :label="$t('examineStaffValue.table.staffId')" align="center" />
  38 + <el-table-column prop="staffName" :label="$t('examineStaffValue.table.staffName')" align="center" />
  39 + <el-table-column prop="projectName" :label="$t('examineStaffValue.table.projectName')" align="center" />
  40 + <el-table-column prop="weight" :label="$t('examineStaffValue.table.weight')" align="center">
  41 + <template slot-scope="scope">
  42 + {{ scope.row.weight }}%
  43 + </template>
  44 + </el-table-column>
  45 + <el-table-column prop="examineValue" :label="$t('examineStaffValue.table.examineValue')" align="center" />
  46 + <el-table-column prop="ownerName" :label="$t('examineStaffValue.table.ownerName')" align="center" />
  47 + <el-table-column prop="roomName" :label="$t('examineStaffValue.table.roomName')" align="center" />
  48 + <el-table-column prop="createTime" :label="$t('examineStaffValue.table.createTime')" align="center" />
  49 + </el-table>
  50 +
  51 + <!-- 分页 -->
  52 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  53 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  54 + @current-change="handleCurrentChange" />
  55 + </el-card>
  56 + </div>
  57 +</template>
  58 +
  59 +<script>
  60 +import { listExamineStaffValue } from '@/api/oa/examineStaffValueApi'
  61 +import { getCommunityId } from '@/api/community/communityApi'
  62 +
  63 +export default {
  64 + name: 'ExamineStaffValueList',
  65 + data() {
  66 + return {
  67 + loading: false,
  68 + searchForm: {
  69 + staffName: '',
  70 + projectName: '',
  71 + communityId: ''
  72 + },
  73 + tableData: [],
  74 + page: {
  75 + current: 1,
  76 + size: 10,
  77 + total: 0
  78 + }
  79 + }
  80 + },
  81 + created() {
  82 + this.searchForm.communityId = getCommunityId()
  83 + this.getList()
  84 + },
  85 + methods: {
  86 + async getList() {
  87 + try {
  88 + this.loading = true
  89 + const params = {
  90 + page: this.page.current,
  91 + row: this.page.size,
  92 + staffName: this.searchForm.staffName.trim(),
  93 + projectName: this.searchForm.projectName.trim(),
  94 + communityId: this.searchForm.communityId
  95 + }
  96 + const { data, total } = await listExamineStaffValue(params)
  97 + this.tableData = data
  98 + this.page.total = total
  99 + } catch (error) {
  100 + this.$message.error(this.$t('examineStaffValue.fetchError'))
  101 + } finally {
  102 + this.loading = false
  103 + }
  104 + },
  105 + handleSearch() {
  106 + this.page.current = 1
  107 + this.getList()
  108 + },
  109 + handleReset() {
  110 + this.searchForm.staffName = ''
  111 + this.searchForm.projectName = ''
  112 + this.handleSearch()
  113 + },
  114 + handleSizeChange(val) {
  115 + this.page.size = val
  116 + this.getList()
  117 + },
  118 + handleCurrentChange(val) {
  119 + this.page.current = val
  120 + this.getList()
  121 + }
  122 + }
  123 +}
  124 +</script>
  125 +
  126 +<style lang="scss" scoped>
  127 +.examine-staff-value-container {
  128 + padding: 20px;
  129 +
  130 + .search-wrapper {
  131 + margin-bottom: 20px;
  132 +
  133 + .el-row {
  134 + margin-bottom: -20px;
  135 + }
  136 +
  137 + .el-col {
  138 + margin-bottom: 20px;
  139 + }
  140 + }
  141 +
  142 + .list-wrapper {
  143 + .el-pagination {
  144 + margin-top: 20px;
  145 + text-align: right;
  146 + }
  147 + }
  148 +}
  149 +</style>
0 150 \ No newline at end of file
... ...
src/views/oa/ownerVotingLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerVoting: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + qaId: 'Please enter voting ID',
  7 + qaName: 'Please enter voting name'
  8 + },
  9 + list: {
  10 + title: 'Voting Information'
  11 + },
  12 + table: {
  13 + qaName: 'Voting Name',
  14 + validity: 'Validity Period',
  15 + type: 'Type',
  16 + options: 'Options',
  17 + voteCount: 'Total Votes/Voted',
  18 + state: 'Status',
  19 + createTime: 'Create Time',
  20 + operation: 'Operation',
  21 + peopleChose: ' people chose'
  22 + },
  23 + type: {
  24 + single: 'Single Choice',
  25 + multiple: 'Multiple Choice'
  26 + },
  27 + state: {
  28 + published: 'Published',
  29 + unpublished: 'Unpublished'
  30 + },
  31 + operation: {
  32 + result: 'Result',
  33 + publish: 'Publish'
  34 + },
  35 + add: {
  36 + title: 'Add Voting',
  37 + success: 'Add voting successfully',
  38 + error: 'Failed to add voting'
  39 + },
  40 + edit: {
  41 + title: 'Edit Voting',
  42 + noId: 'No voting ID provided',
  43 + fetchError: 'Failed to get voting details'
  44 + },
  45 + delete: {
  46 + title: 'Delete Voting',
  47 + confirm: 'Are you sure to delete this voting?',
  48 + success: 'Delete voting successfully',
  49 + error: 'Failed to delete voting'
  50 + },
  51 + deleteQuestionAnswer: {
  52 + title: 'Delete Questionnaire',
  53 + confirm: 'Are you sure to delete this questionnaire?',
  54 + success: 'Delete questionnaire successfully',
  55 + error: 'Failed to delete questionnaire'
  56 + },
  57 + publish: {
  58 + title: 'Publish Voting',
  59 + name: 'Name',
  60 + tip: 'Tips',
  61 + tipContent: 'After publishing, it cannot be modified again. Please confirm before publishing!',
  62 + notifyWay: 'Notification Method',
  63 + notifyWayPlaceholder: 'Required, please select notification method',
  64 + sms: 'SMS',
  65 + wechat: 'WeChat Message',
  66 + noNotify: 'No Notification',
  67 + notifyWayRequired: 'Notification method is required',
  68 + publishBtn: 'Publish',
  69 + success: 'Publish successfully',
  70 + error: 'Failed to publish'
  71 + },
  72 + form: {
  73 + qaName: 'Voting Name',
  74 + qaNamePlaceholder: 'Please enter voting name',
  75 + type: 'Type',
  76 + typePlaceholder: 'Please select type',
  77 + startTime: 'Start Time',
  78 + startTimePlaceholder: 'Please select start time',
  79 + endTime: 'End Time',
  80 + endTimePlaceholder: 'Please select end time',
  81 + options: 'Options',
  82 + optionPlaceholder: 'Option {num}',
  83 + addOption: 'Add Option'
  84 + },
  85 + validate: {
  86 + qaName: 'Voting name is required',
  87 + type: 'Type is required',
  88 + startTime: 'Start time is required',
  89 + endTime: 'End time is required',
  90 + endTimeAfterStart: 'End time must be after start time',
  91 + atLeastOneOption: 'At least one option is required',
  92 + optionNotEmpty: 'Option cannot be empty'
  93 + },
  94 + fetchError: 'Failed to get voting list'
  95 + }
  96 + },
  97 + zh: {
  98 + ownerVoting: {
  99 + search: {
  100 + title: '查询条件',
  101 + qaId: '请输入投票ID',
  102 + qaName: '请输入投票名称'
  103 + },
  104 + list: {
  105 + title: '投票信息'
  106 + },
  107 + table: {
  108 + qaName: '投票名称',
  109 + validity: '有效期',
  110 + type: '类型',
  111 + options: '选项',
  112 + voteCount: '总投票/已投票',
  113 + state: '状态',
  114 + createTime: '创建时间',
  115 + operation: '操作',
  116 + peopleChose: '人选择'
  117 + },
  118 + type: {
  119 + single: '单选',
  120 + multiple: '多选'
  121 + },
  122 + state: {
  123 + published: '已发布',
  124 + unpublished: '待发布'
  125 + },
  126 + operation: {
  127 + result: '结果',
  128 + publish: '发布'
  129 + },
  130 + add: {
  131 + title: '添加投票',
  132 + success: '添加投票成功',
  133 + error: '添加投票失败'
  134 + },
  135 + edit: {
  136 + title: '编辑投票',
  137 + noId: '未提供投票ID',
  138 + fetchError: '获取投票详情失败'
  139 + },
  140 + delete: {
  141 + title: '删除投票',
  142 + confirm: '确定删除该投票吗?',
  143 + success: '删除投票成功',
  144 + error: '删除投票失败'
  145 + },
  146 + deleteQuestionAnswer: {
  147 + title: '删除问卷',
  148 + confirm: '确定删除该问卷吗?',
  149 + success: '删除问卷成功',
  150 + error: '删除问卷失败'
  151 + },
  152 + publish: {
  153 + title: '发布投票',
  154 + name: '名称',
  155 + tip: '温馨提示',
  156 + tipContent: '发布后将无法再次修改,请确认无误后再发布!',
  157 + notifyWay: '通知方式',
  158 + notifyWayPlaceholder: '必填,请选择通知方式',
  159 + sms: '短信',
  160 + wechat: '微信消息',
  161 + noNotify: '不通知',
  162 + notifyWayRequired: '通知方式不能为空',
  163 + publishBtn: '发布',
  164 + success: '发布成功',
  165 + error: '发布失败'
  166 + },
  167 + form: {
  168 + qaName: '投票名称',
  169 + qaNamePlaceholder: '请输入投票名称',
  170 + type: '类型',
  171 + typePlaceholder: '请选择类型',
  172 + startTime: '开始时间',
  173 + startTimePlaceholder: '请选择开始时间',
  174 + endTime: '结束时间',
  175 + endTimePlaceholder: '请选择结束时间',
  176 + options: '选项',
  177 + optionPlaceholder: '选项{num}',
  178 + addOption: '添加选项'
  179 + },
  180 + validate: {
  181 + qaName: '投票名称不能为空',
  182 + type: '类型不能为空',
  183 + startTime: '开始时间不能为空',
  184 + endTime: '结束时间不能为空',
  185 + endTimeAfterStart: '结束时间必须晚于开始时间',
  186 + atLeastOneOption: '至少需要一个选项',
  187 + optionNotEmpty: '选项不能为空'
  188 + },
  189 + fetchError: '获取投票列表失败'
  190 + }
  191 + }
  192 +}
0 193 \ No newline at end of file
... ...
src/views/oa/ownerVotingList.vue 0 → 100644
  1 +<template>
  2 + <div class="owner-voting-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('ownerVoting.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.qaId" :placeholder="$t('ownerVoting.search.qaId')" clearable
  11 + @keyup.enter.native="handleSearch" />
  12 + </el-col>
  13 + <el-col :span="8">
  14 + <el-input v-model="searchForm.qaName" :placeholder="$t('ownerVoting.search.qaName')" clearable
  15 + @keyup.enter.native="handleSearch" />
  16 + </el-col>
  17 + <el-col :span="4">
  18 + <el-button type="primary" @click="handleSearch">
  19 + <i class="el-icon-search"></i>
  20 + {{ $t('common.search') }}
  21 + </el-button>
  22 + <el-button @click="handleReset">
  23 + <i class="el-icon-refresh"></i>
  24 + {{ $t('common.reset') }}
  25 + </el-button>
  26 + </el-col>
  27 + </el-row>
  28 + </el-card>
  29 +
  30 + <!-- 投票信息 -->
  31 + <el-card class="list-wrapper">
  32 + <div slot="header" class="flex justify-between">
  33 + <span>{{ $t('ownerVoting.list.title') }}</span>
  34 + <el-button type="primary" size="small" style="float: right;" @click="handleAdd">
  35 + <i class="el-icon-plus"></i>
  36 + {{ $t('common.add') }}
  37 + </el-button>
  38 + </div>
  39 +
  40 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  41 + <el-table-column prop="qaName" :label="$t('ownerVoting.table.qaName')" align="center" />
  42 + <el-table-column :label="$t('ownerVoting.table.validity')" align="center">
  43 + <template slot-scope="scope">
  44 + {{ scope.row.startTime }}<br />~{{ scope.row.endTime }}
  45 + </template>
  46 + </el-table-column>
  47 + <el-table-column prop="titleType" :label="$t('ownerVoting.table.type')" align="center">
  48 + <template slot-scope="scope">
  49 + {{ scope.row.titleType === '1001' ? $t('ownerVoting.type.single') : $t('ownerVoting.type.multiple') }}
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column :label="$t('ownerVoting.table.options')" align="center">
  53 + <template slot-scope="scope">
  54 + <div v-for="(item, index) in scope.row.titleValues" :key="index">
  55 + {{ item.seq }}、{{ item.qaValue }}({{ item.personCount }}{{ $t('ownerVoting.table.peopleChose') }})
  56 + </div>
  57 + </template>
  58 + </el-table-column>
  59 + <el-table-column :label="$t('ownerVoting.table.voteCount')" align="center">
  60 + <template slot-scope="scope">
  61 + {{ scope.row.voteCount }}/{{ scope.row.votedCount }}
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column prop="state" :label="$t('ownerVoting.table.state')" align="center">
  65 + <template slot-scope="scope">
  66 + {{ scope.row.state === 'C' ? $t('ownerVoting.state.published') : $t('ownerVoting.state.unpublished') }}
  67 + </template>
  68 + </el-table-column>
  69 + <el-table-column prop="createTime" :label="$t('ownerVoting.table.createTime')" align="center" />
  70 + <el-table-column :label="$t('common.operation')" align="center" width="250" fixed="right">
  71 + <template slot-scope="scope">
  72 + <el-button size="mini" type="primary" @click="handleDetail(scope.row)">
  73 + {{ $t('ownerVoting.operation.result') }}
  74 + </el-button>
  75 + <el-button v-if="scope.row.state === 'W'" size="mini" type="warning" @click="handleEdit(scope.row)">
  76 + {{ $t('common.edit') }}
  77 + </el-button>
  78 + <el-button v-if="scope.row.state === 'W'" size="mini" type="success" @click="handlePublish(scope.row)">
  79 + {{ $t('ownerVoting.operation.publish') }}
  80 + </el-button>
  81 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  82 + {{ $t('common.delete') }}
  83 + </el-button>
  84 + </template>
  85 + </el-table-column>
  86 + </el-table>
  87 +
  88 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  89 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  90 + @current-change="handleCurrentChange" />
  91 + </el-card>
  92 +
  93 + <!-- 组件 -->
  94 + <delete-question-answer ref="deleteQuestionAnswer" @success="handleSuccess" />
  95 + <publish-question-answer ref="publishQuestionAnswer" @success="handleSuccess" />
  96 + </div>
  97 +</template>
  98 +
  99 +<script>
  100 +import { listOwnerVote } from '@/api/oa/ownerVotingApi'
  101 +import DeleteQuestionAnswer from '@/components/oa/deleteQuestionAnswer'
  102 +import PublishQuestionAnswer from '@/components/oa/publishQuestionAnswer'
  103 +import { getCommunityId } from '@/api/community/communityApi'
  104 +
  105 +export default {
  106 + name: 'OwnerVotingList',
  107 + components: {
  108 + DeleteQuestionAnswer,
  109 + PublishQuestionAnswer
  110 + },
  111 + data() {
  112 + return {
  113 + loading: false,
  114 + searchForm: {
  115 + qaId: '',
  116 + qaName: '',
  117 + qaType: '',
  118 + communityId: ''
  119 + },
  120 + tableData: [],
  121 + page: {
  122 + current: 1,
  123 + size: 10,
  124 + total: 0
  125 + }
  126 + }
  127 + },
  128 + created() {
  129 + this.searchForm.communityId = getCommunityId()
  130 + this.getList()
  131 + },
  132 + methods: {
  133 + async getList() {
  134 + try {
  135 + this.loading = true
  136 + const params = {
  137 + page: this.page.current,
  138 + row: this.page.size,
  139 + ...this.searchForm
  140 + }
  141 + const { data, total } = await listOwnerVote(params)
  142 + this.tableData = data
  143 + this.page.total = total
  144 + } catch (error) {
  145 + this.$message.error(this.$t('ownerVoting.fetchError'))
  146 + } finally {
  147 + this.loading = false
  148 + }
  149 + },
  150 + handleSearch() {
  151 + this.page.current = 1
  152 + this.getList()
  153 + },
  154 + handleReset() {
  155 + this.searchForm = {
  156 + qaId: '',
  157 + qaName: '',
  158 + qaType: '',
  159 + communityId: getCommunityId()
  160 + }
  161 + this.handleSearch()
  162 + },
  163 + handleAdd() {
  164 + this.$router.push('/views/oa/addOwnerVoting')
  165 + },
  166 + handleEdit(row) {
  167 + this.$router.push(`/views/oa/editOwnerVoting?qaId=${row.qaId}`)
  168 + },
  169 + handleDelete(row) {
  170 + this.$refs.deleteQuestionAnswer.open(row)
  171 + },
  172 + handlePublish(row) {
  173 + this.$refs.publishQuestionAnswer.open(row)
  174 + },
  175 + handleDetail(row) {
  176 + window.open(`/#/views/oa/printOwnerVoting?qaId=${row.qaId}`)
  177 + },
  178 + handleSuccess() {
  179 + this.getList()
  180 + },
  181 + handleSizeChange(val) {
  182 + this.page.size = val
  183 + this.getList()
  184 + },
  185 + handleCurrentChange(val) {
  186 + this.page.current = val
  187 + this.getList()
  188 + }
  189 + }
  190 +}
  191 +</script>
  192 +
  193 +<style lang="scss" scoped>
  194 +.owner-voting-container {
  195 + padding: 20px;
  196 +
  197 + .search-wrapper {
  198 + margin-bottom: 20px;
  199 +
  200 + .el-row {
  201 + margin-bottom: -20px;
  202 + }
  203 +
  204 + .el-col {
  205 + margin-bottom: 20px;
  206 + }
  207 + }
  208 +
  209 + .list-wrapper {
  210 + .el-pagination {
  211 + margin-top: 20px;
  212 + text-align: right;
  213 + }
  214 + }
  215 +}
  216 +</style>
0 217 \ No newline at end of file
... ...
src/views/oa/printOwnerVotingLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + printOwnerVoting: {
  4 + room: 'Room',
  5 + totalVotes: 'Total votes',
  6 + votedCount: 'Voted count',
  7 + person: 'person'
  8 + }
  9 + },
  10 + zh: {
  11 + printOwnerVoting: {
  12 + room: '房间',
  13 + totalVotes: '投票总数',
  14 + votedCount: '已投票',
  15 + person: '人'
  16 + }
  17 + }
  18 +}
0 19 \ No newline at end of file
... ...
src/views/oa/printOwnerVotingList.vue 0 → 100644
  1 +<template>
  2 + <div class="print-owner-voting-container">
  3 + <el-card>
  4 + <el-row>
  5 + <el-col :span="24">
  6 + <div class="text-center">
  7 + <h1>{{ printOwnerVotingInfo.qaName }}</h1>
  8 + </div>
  9 + </el-col>
  10 + </el-row>
  11 +
  12 + <el-row>
  13 + <el-col :span="24">
  14 + <div v-html="printOwnerVotingInfo.content"></div>
  15 + </el-col>
  16 + </el-row>
  17 +
  18 + <el-row>
  19 + <el-col :span="24">
  20 + <table class="table vc-table-border margin-top" style="color:#000;font-size:14px">
  21 + <thead>
  22 + <tr>
  23 + <th class="text-center" width="200px">
  24 + <div style="max-width: 200px;">
  25 + {{ $t('printOwnerVoting.room') }}
  26 + </div>
  27 + </th>
  28 + <th v-for="(item, index) in printOwnerVotingInfo.titleValues" :key="index" scope="col"
  29 + class="text-center">
  30 + {{ item.qaValue }}
  31 + </th>
  32 + <th width="200px" class="text-center">
  33 + <div style="max-width: 200px;">
  34 + {{ $t('printOwnerVoting.room') }}
  35 + </div>
  36 + </th>
  37 + <th v-for="(item, index) in printOwnerVotingInfo.titleValues" :key="index" scope="col"
  38 + class="text-center">
  39 + {{ item.qaValue }}
  40 + </th>
  41 + </tr>
  42 + </thead>
  43 + <tbody>
  44 + <template v-for="(vote, index) in printOwnerVotingInfo.userVotes">
  45 + <tr :key="index" class="vc-table-border" v-if="index % 2 == 0">
  46 + <td class="text-center">
  47 + <div style="max-width: 200px;">{{ vote.roomName }}</div>
  48 + </td>
  49 + <td v-for="(item, tIndex) in printOwnerVotingInfo.titleValues" :key="tIndex" class="text-center">
  50 + {{ vote[item.qaValue] }}
  51 + </td>
  52 + <td class="text-center">
  53 + <div style="max-width: 200px;" v-if="printOwnerVotingInfo.userVotes.length > index">
  54 + {{ printOwnerVotingInfo.userVotes[index + 1].roomName }}
  55 + </div>
  56 + </td>
  57 + <td v-for="(item, tIndex) in printOwnerVotingInfo.titleValues" :key="tIndex" class="text-center">
  58 + <div v-if="printOwnerVotingInfo.userVotes.length > index">
  59 + {{ printOwnerVotingInfo.userVotes[index + 1][item.qaValue] }}
  60 + </div>
  61 + </td>
  62 + </tr>
  63 + </template>
  64 + </tbody>
  65 + </table>
  66 + </el-col>
  67 + </el-row>
  68 +
  69 + <el-row>
  70 + <el-col :span="24">
  71 + <span>{{ $t('printOwnerVoting.totalVotes') }}:{{ printOwnerVotingInfo.voteCount }}</span>;
  72 + <span>{{ $t('printOwnerVoting.votedCount') }}:{{ printOwnerVotingInfo.votedCount }}</span>;
  73 + <span v-for="(item, tIndex) in printOwnerVotingInfo.titleValues" :key="tIndex">
  74 + {{ item.qaValue }}: {{ item.personCount }}{{ $t('printOwnerVoting.person') }};
  75 + </span>
  76 + </el-col>
  77 + </el-row>
  78 +
  79 + <el-row>
  80 + <el-col :span="24" class="text-right margin-top margin-right">
  81 + {{ currentCommunity.name }}
  82 + </el-col>
  83 + </el-row>
  84 +
  85 + <el-row>
  86 + <el-col :span="24" class="text-right margin-top-sm margin-right">
  87 + {{ formatDate(new Date()) }}
  88 + </el-col>
  89 + </el-row>
  90 +
  91 + <el-row id="print-btn">
  92 + <el-col :span="24" class="text-right">
  93 + <el-button type="primary" @click="_printPurchaseApplyDiv">
  94 + <i class="el-icon-printer"></i>&nbsp;{{ $t('common.print') }}
  95 + </el-button>
  96 + <el-button type="warning" style="margin-right:20px;" @click="_closePage">
  97 + {{ $t('common.cancel') }}
  98 + </el-button>
  99 + </el-col>
  100 + </el-row>
  101 + </el-card>
  102 + </div>
  103 +</template>
  104 +
  105 +<script>
  106 +import { getCommunityId } from '@/api/community/communityApi'
  107 +import { listOwnerVote, listUserQuestionAnswer } from '@/api/oa/printOwnerVotingApi'
  108 +
  109 +export default {
  110 + name: 'PrintOwnerVotingList',
  111 + data() {
  112 + return {
  113 + printOwnerVotingInfo: {
  114 + qaName: '',
  115 + content: '',
  116 + titleValues: [],
  117 + qaId: '',
  118 + userVotes: [],
  119 + voteCount: 0,
  120 + votedCount: 0
  121 + },
  122 + currentCommunity: {
  123 + name: '',
  124 + communityId: ''
  125 + }
  126 + }
  127 + },
  128 + created() {
  129 + this.printOwnerVotingInfo.qaId = this.$route.query.qaId
  130 + this.currentCommunity.communityId = getCommunityId()
  131 + this._listOwnerVotings()
  132 + },
  133 + methods: {
  134 + async _listOwnerVotings() {
  135 + try {
  136 + const params = {
  137 + page: 1,
  138 + row: 1,
  139 + communityId: this.currentCommunity.communityId,
  140 + qaId: this.printOwnerVotingInfo.qaId
  141 + }
  142 + const { data } = await listOwnerVote(params)
  143 + this.printOwnerVotingInfo = data[0]
  144 + this._listValues()
  145 + } catch (error) {
  146 + console.error('请求失败:', error)
  147 + }
  148 + },
  149 + async _listValues() {
  150 + try {
  151 + const params = {
  152 + page: 1,
  153 + row: 500,
  154 + communityId: this.currentCommunity.communityId,
  155 + qaId: this.printOwnerVotingInfo.qaId
  156 + }
  157 + const { data } = await listUserQuestionAnswer(params)
  158 + const _titleValues = this.printOwnerVotingInfo.titleValues
  159 + data.forEach(_value => {
  160 + _titleValues.forEach(_title => {
  161 + _value[_title.qaValue] = ''
  162 + if (_value['values']) {
  163 + _value.values.forEach(tmpValue => {
  164 + if (tmpValue.qaValue === _title.qaValue) {
  165 + _value[_title.qaValue] = 'V'
  166 + }
  167 + })
  168 + }
  169 + })
  170 + })
  171 + this.printOwnerVotingInfo.userVotes = data
  172 + } catch (error) {
  173 + console.error('请求失败:', error)
  174 + }
  175 + },
  176 + _printPurchaseApplyDiv() {
  177 + document.getElementById("print-btn").style.display = "none"
  178 + window.print()
  179 + window.opener = null
  180 + window.close()
  181 + },
  182 + _closePage() {
  183 + window.opener = null
  184 + window.close()
  185 + },
  186 + formatDate(date) {
  187 + const year = date.getFullYear()
  188 + const month = String(date.getMonth() + 1).padStart(2, '0')
  189 + const day = String(date.getDate()).padStart(2, '0')
  190 + return `${year}-${month}-${day}`
  191 + }
  192 + }
  193 +}
  194 +</script>
  195 +
  196 +<style lang="scss" scoped>
  197 +.print-owner-voting-container {
  198 + padding: 20px;
  199 +
  200 + .margin-top {
  201 + margin-top: 20px;
  202 + }
  203 +
  204 + .margin-top-sm {
  205 + margin-top: 10px;
  206 + }
  207 +
  208 + .margin-right {
  209 + margin-right: 20px;
  210 + }
  211 +
  212 + .text-center {
  213 + text-align: center;
  214 + }
  215 +
  216 + .text-right {
  217 + text-align: right;
  218 + }
  219 +
  220 + .vc-table-border {
  221 + border: 1px solid #ebeef5;
  222 + border-collapse: collapse;
  223 +
  224 + th,
  225 + td {
  226 + border: 1px solid #ebeef5;
  227 + padding: 8px;
  228 + }
  229 + }
  230 +
  231 + #print-btn {
  232 + margin-top: 20px;
  233 + }
  234 +}
  235 +</style>
0 236 \ No newline at end of file
... ...