Commit 7cf20db674aa70e82a7a1d43982621a51de797d4

Authored by wuxw
1 parent 18300670

完成工作单详情

src/api/oa/workDetailApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取工作单详情
  4 +export function getWorkPoolDetail(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/work.listWorkPool',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve(res)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 获取工作单任务列表
  20 +export function listWorkTask(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/work.listWorkTask',
  24 + method: 'get',
  25 + params
  26 + }).then(response => {
  27 + const res = response.data
  28 + resolve(res)
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +// 获取工作单任务项列表
  36 +export function listWorkTaskItem(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/task.listWorkTaskItem',
  40 + method: 'get',
  41 + params
  42 + }).then(response => {
  43 + const res = response.data
  44 + resolve(res)
  45 + }).catch(error => {
  46 + reject(error)
  47 + })
  48 + })
  49 +}
  50 +
  51 +// 获取工作单抄送人列表
  52 +export function listWorkCopy(params) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/work.listWorkCopy',
  56 + method: 'get',
  57 + params
  58 + }).then(response => {
  59 + const res = response.data
  60 + resolve(res)
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 获取工作单流转事件列表
  68 +export function listWorkEvent(params) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/workEvent.listWorkEvent',
  72 + method: 'get',
  73 + params
  74 + }).then(response => {
  75 + const res = response.data
  76 + resolve(res)
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 获取工作单流转附件列表
  84 +export function listWorkPoolFile(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/work.listWorkPoolFile',
  88 + method: 'get',
  89 + params
  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 listWorkType(params) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/workType.listWorkType',
  104 + method: 'get',
  105 + params
  106 + }).then(response => {
  107 + const res = response.data
  108 + resolve(res)
  109 + }).catch(error => {
  110 + reject(error)
  111 + })
  112 + })
  113 +}
  114 +
  115 +// 获取工作单周期列表
  116 +export function listWorkCycle(params) {
  117 + return new Promise((resolve, reject) => {
  118 + request({
  119 + url: '/workCycle.listWorkCycle',
  120 + method: 'get',
  121 + params
  122 + }).then(response => {
  123 + const res = response.data
  124 + resolve(res)
  125 + }).catch(error => {
  126 + reject(error)
  127 + })
  128 + })
  129 +}
0 130 \ No newline at end of file
... ...
src/components/oa/WorkDetailCopy.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-copy">
  3 + <el-row :gutter="20" class="margin-top-lg">
  4 + <el-col :span="6">
  5 + <el-input
  6 + v-model.trim="workDetailCopyInfo.staffNameLike"
  7 + :placeholder="$t('workDetailCopy.staffNamePlaceholder')"
  8 + clearable
  9 + />
  10 + </el-col>
  11 + <el-col :span="6">
  12 + <el-button type="primary" @click="queryWorkDetailCopy">
  13 + <i class="el-icon-search"></i>{{ $t('common.search') }}
  14 + </el-button>
  15 + <el-button @click="resetWorkDetailCopy">
  16 + <i class="el-icon-refresh"></i>{{ $t('common.reset') }}
  17 + </el-button>
  18 + </el-col>
  19 + </el-row>
  20 +
  21 + <div class="margin-top">
  22 + <el-table
  23 + :data="workDetailCopyInfo.copys"
  24 + border
  25 + style="width: 100%"
  26 + v-loading="loading"
  27 + >
  28 + <el-table-column
  29 + prop="copyId"
  30 + :label="$t('workDetailCopy.copyId')"
  31 + align="center"
  32 + />
  33 + <el-table-column
  34 + prop="staffName"
  35 + :label="$t('workDetailCopy.staffName')"
  36 + align="center"
  37 + />
  38 + <el-table-column
  39 + prop="createTime"
  40 + :label="$t('workDetailCopy.createTime')"
  41 + align="center"
  42 + />
  43 + <el-table-column
  44 + prop="stateName"
  45 + :label="$t('workDetailCopy.stateName')"
  46 + align="center"
  47 + />
  48 + <el-table-column
  49 + prop="remark"
  50 + :label="$t('workDetailCopy.remark')"
  51 + align="center"
  52 + />
  53 + </el-table>
  54 +
  55 + <el-pagination
  56 + :current-page.sync="page.current"
  57 + :page-sizes="[10, 20, 30, 50]"
  58 + :page-size="page.size"
  59 + :total="page.total"
  60 + layout="total, sizes, prev, pager, next, jumper"
  61 + @size-change="handleSizeChange"
  62 + @current-change="handleCurrentChange"
  63 + />
  64 + </div>
  65 + </div>
  66 +</template>
  67 +
  68 +<script>
  69 +import { listWorkCopy } from '@/api/oa/workDetailApi'
  70 +
  71 +export default {
  72 + name: 'WorkDetailCopy',
  73 + data() {
  74 + return {
  75 + workDetailCopyInfo: {
  76 + copys: [],
  77 + workId: '',
  78 + staffNameLike: ''
  79 + },
  80 + loading: false,
  81 + page: {
  82 + current: 1,
  83 + size: 10,
  84 + total: 0
  85 + }
  86 + }
  87 + },
  88 + methods: {
  89 + open(params) {
  90 + this.workDetailCopyInfo.workId = params.workId
  91 + this.loadWorkDetailCopyData(this.page.current, this.page.size)
  92 + },
  93 + async loadWorkDetailCopyData(page, size) {
  94 + try {
  95 + this.loading = true
  96 + const params = {
  97 + workId: this.workDetailCopyInfo.workId,
  98 + staffNameLike: this.workDetailCopyInfo.staffNameLike,
  99 + page,
  100 + row: size
  101 + }
  102 + const { data, total } = await listWorkCopy(params)
  103 + this.workDetailCopyInfo.copys = data
  104 + this.page.total = total
  105 + } catch (error) {
  106 + console.error('获取抄送人列表失败:', error)
  107 + } finally {
  108 + this.loading = false
  109 + }
  110 + },
  111 + queryWorkDetailCopy() {
  112 + this.page.current = 1
  113 + this.loadWorkDetailCopyData(this.page.current, this.page.size)
  114 + },
  115 + resetWorkDetailCopy() {
  116 + this.workDetailCopyInfo.staffNameLike = ''
  117 + this.queryWorkDetailCopy()
  118 + },
  119 + handleSizeChange(val) {
  120 + this.page.size = val
  121 + this.loadWorkDetailCopyData(this.page.current, this.page.size)
  122 + },
  123 + handleCurrentChange(val) {
  124 + this.page.current = val
  125 + this.loadWorkDetailCopyData(this.page.current, this.page.size)
  126 + }
  127 + }
  128 +}
  129 +</script>
  130 +
  131 +<style scoped>
  132 +.margin-top-lg {
  133 + margin-top: 20px;
  134 +}
  135 +.margin-top {
  136 + margin-top: 20px;
  137 +}
  138 +</style>
0 139 \ No newline at end of file
... ...
src/components/oa/WorkDetailCycle.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-cycle">
  3 + <div class="margin-top">
  4 + <el-table
  5 + :data="workDetailCycleInfo.cycles"
  6 + border
  7 + style="width: 100%"
  8 + v-loading="loading"
  9 + >
  10 + <el-table-column
  11 + prop="staffName"
  12 + :label="$t('workDetailCycle.staffName')"
  13 + align="center"
  14 + />
  15 + <el-table-column
  16 + :label="$t('workDetailCycle.workCycle')"
  17 + align="center"
  18 + >
  19 + <template slot-scope="scope">
  20 + {{ scope.row.workCycle === '1001' ? $t('workDetailCycle.once') : $t('workDetailCycle.periodic') }}
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="hours"
  25 + :label="$t('workDetailCycle.hours')"
  26 + align="center"
  27 + />
  28 + <el-table-column
  29 + :label="$t('workDetailCycle.period')"
  30 + align="center"
  31 + >
  32 + <template slot-scope="scope">
  33 + {{ scope.row.period === '2020022' ? $t('workDetailCycle.monthDay') : $t('workDetailCycle.weekly') }}
  34 + </template>
  35 + </el-table-column>
  36 + <el-table-column
  37 + prop="periodMonth"
  38 + :label="$t('workDetailCycle.month')"
  39 + align="center"
  40 + >
  41 + <template slot-scope="scope">
  42 + {{ scope.row.periodMonth || '-' }}
  43 + </template>
  44 + </el-table-column>
  45 + <el-table-column
  46 + prop="periodDay"
  47 + :label="$t('workDetailCycle.day')"
  48 + align="center"
  49 + >
  50 + <template slot-scope="scope">
  51 + {{ scope.row.periodDay || '-' }}
  52 + </template>
  53 + </el-table-column>
  54 + <el-table-column
  55 + prop="periodWorkday"
  56 + :label="$t('workDetailCycle.week')"
  57 + align="center"
  58 + >
  59 + <template slot-scope="scope">
  60 + {{ scope.row.periodWorkday || '-' }}
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 +
  65 + <el-pagination
  66 + :current-page.sync="page.current"
  67 + :page-sizes="[10, 20, 30, 50]"
  68 + :page-size="page.size"
  69 + :total="page.total"
  70 + layout="total, sizes, prev, pager, next, jumper"
  71 + @size-change="handleSizeChange"
  72 + @current-change="handleCurrentChange"
  73 + />
  74 + </div>
  75 + </div>
  76 +</template>
  77 +
  78 +<script>
  79 +import { listWorkCycle } from '@/api/oa/workDetailApi'
  80 +
  81 +export default {
  82 + name: 'WorkDetailCycle',
  83 + data() {
  84 + return {
  85 + workDetailCycleInfo: {
  86 + cycles: [],
  87 + workId: ''
  88 + },
  89 + loading: false,
  90 + page: {
  91 + current: 1,
  92 + size: 10,
  93 + total: 0
  94 + }
  95 + }
  96 + },
  97 + methods: {
  98 + open(params) {
  99 + this.workDetailCycleInfo.workId = params.workId
  100 + this.loadWorkDetailCycleData(this.page.current, this.page.size)
  101 + },
  102 + async loadWorkDetailCycleData(page, size) {
  103 + try {
  104 + this.loading = true
  105 + const params = {
  106 + workId: this.workDetailCycleInfo.workId,
  107 + page,
  108 + row: size
  109 + }
  110 + const { data, total } = await listWorkCycle(params)
  111 + this.workDetailCycleInfo.cycles = data
  112 + this.page.total = total
  113 + } catch (error) {
  114 + console.error('获取工作单周期列表失败:', error)
  115 + } finally {
  116 + this.loading = false
  117 + }
  118 + },
  119 + handleSizeChange(val) {
  120 + this.page.size = val
  121 + this.loadWorkDetailCycleData(this.page.current, this.page.size)
  122 + },
  123 + handleCurrentChange(val) {
  124 + this.page.current = val
  125 + this.loadWorkDetailCycleData(this.page.current, this.page.size)
  126 + }
  127 + }
  128 +}
  129 +</script>
  130 +
  131 +<style scoped>
  132 +.margin-top {
  133 + margin-top: 20px;
  134 +}
  135 +</style>
0 136 \ No newline at end of file
... ...
src/components/oa/WorkDetailEvent.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-event">
  3 + <el-row :gutter="20">
  4 + <el-col :span="4">
  5 + <div class="tree-container">
  6 + <el-scrollbar>
  7 + <ul class="content-list">
  8 + <li
  9 + v-for="(item,index) in workDetailEventInfo.contents"
  10 + :key="index"
  11 + @click="swatchEventContentId(item)"
  12 + :class="{'active-content': workDetailEventInfo.contentId === item.contentId}"
  13 + >
  14 + 问题{{ item.seqNum }}
  15 + </li>
  16 + </ul>
  17 + </el-scrollbar>
  18 + </div>
  19 + </el-col>
  20 + <el-col :span="20">
  21 + <el-row :gutter="20" class="margin-top-lg">
  22 + <el-col :span="6">
  23 + <el-input
  24 + v-model.trim="workDetailEventInfo.staffNameLike"
  25 + :placeholder="$t('workDetailEvent.staffNamePlaceholder')"
  26 + clearable
  27 + />
  28 + </el-col>
  29 + <el-col :span="6">
  30 + <el-date-picker
  31 + v-model="workDetailEventInfo.queryStartTime"
  32 + type="datetime"
  33 + :placeholder="$t('workDetailEvent.startTimePlaceholder')"
  34 + value-format="yyyy-MM-dd HH:mm:ss"
  35 + style="width: 100%"
  36 + />
  37 + </el-col>
  38 + <el-col :span="6">
  39 + <el-date-picker
  40 + v-model="workDetailEventInfo.queryEndTime"
  41 + type="datetime"
  42 + :placeholder="$t('workDetailEvent.endTimePlaceholder')"
  43 + value-format="yyyy-MM-dd HH:mm:ss"
  44 + style="width: 100%"
  45 + />
  46 + </el-col>
  47 + <el-col :span="6">
  48 + <el-button type="primary" @click="queryWorkDetailEvent">
  49 + <i class="el-icon-search"></i>{{ $t('common.search') }}
  50 + </el-button>
  51 + <el-button @click="resetWorkDetailEvent">
  52 + <i class="el-icon-refresh"></i>{{ $t('common.reset') }}
  53 + </el-button>
  54 + </el-col>
  55 + </el-row>
  56 +
  57 + <div class="margin-top">
  58 + <el-table
  59 + :data="workDetailEventInfo.events"
  60 + border
  61 + style="width: 100%"
  62 + v-loading="loading"
  63 + >
  64 + <el-table-column
  65 + prop="preStaffName"
  66 + :label="$t('workDetailEvent.preStaffName')"
  67 + align="center"
  68 + />
  69 + <el-table-column
  70 + prop="staffName"
  71 + :label="$t('workDetailEvent.staffName')"
  72 + align="center"
  73 + />
  74 + <el-table-column
  75 + :label="$t('workDetailEvent.taskValidPeriod')"
  76 + align="center"
  77 + >
  78 + <template slot-scope="scope">
  79 + {{ scope.row.startTime }}<br>~{{ scope.row.endTime }}
  80 + </template>
  81 + </el-table-column>
  82 + <el-table-column
  83 + prop="remark"
  84 + :label="$t('workDetailEvent.remark')"
  85 + align="center"
  86 + />
  87 + <el-table-column
  88 + prop="createTime"
  89 + :label="$t('workDetailEvent.createTime')"
  90 + align="center"
  91 + />
  92 + </el-table>
  93 +
  94 + <el-pagination
  95 + :current-page.sync="page.current"
  96 + :page-sizes="[10, 20, 30, 50]"
  97 + :page-size="page.size"
  98 + :total="page.total"
  99 + layout="total, sizes, prev, pager, next, jumper"
  100 + @size-change="handleSizeChange"
  101 + @current-change="handleCurrentChange"
  102 + />
  103 + </div>
  104 + </el-col>
  105 + </el-row>
  106 + </div>
  107 +</template>
  108 +
  109 +<script>
  110 +import { listWorkEvent } from '@/api/oa/workDetailApi'
  111 +
  112 +export default {
  113 + name: 'WorkDetailEvent',
  114 + data() {
  115 + return {
  116 + workDetailEventInfo: {
  117 + events: [],
  118 + contents: [],
  119 + workId: '',
  120 + contentId: '',
  121 + staffNameLike: '',
  122 + queryStartTime: '',
  123 + queryEndTime: ''
  124 + },
  125 + loading: false,
  126 + page: {
  127 + current: 1,
  128 + size: 10,
  129 + total: 0
  130 + }
  131 + }
  132 + },
  133 + methods: {
  134 + open(params) {
  135 + this.workDetailEventInfo.workId = params.workId
  136 + this.workDetailEventInfo.contents = params.contents
  137 + if (params.contents.length > 0) {
  138 + this.swatchEventContentId(params.contents[0])
  139 + }
  140 + },
  141 + async loadWorkDetailEventData(page, size) {
  142 + try {
  143 + this.loading = true
  144 + const params = {
  145 + workId: this.workDetailEventInfo.workId,
  146 + contentId: this.workDetailEventInfo.contentId,
  147 + staffNameLike: this.workDetailEventInfo.staffNameLike,
  148 + queryStartTime: this.workDetailEventInfo.queryStartTime,
  149 + queryEndTime: this.workDetailEventInfo.queryEndTime,
  150 + page,
  151 + row: size
  152 + }
  153 + const { data, total } = await listWorkEvent(params)
  154 + this.workDetailEventInfo.events = data
  155 + this.page.total = total
  156 + } catch (error) {
  157 + console.error('获取工作单流转列表失败:', error)
  158 + } finally {
  159 + this.loading = false
  160 + }
  161 + },
  162 + queryWorkDetailEvent() {
  163 + this.page.current = 1
  164 + this.loadWorkDetailEventData(this.page.current, this.page.size)
  165 + },
  166 + swatchEventContentId(content) {
  167 + this.workDetailEventInfo.contentId = content.contentId
  168 + this.loadWorkDetailEventData(this.page.current, this.page.size)
  169 + },
  170 + resetWorkDetailEvent() {
  171 + this.workDetailEventInfo.staffNameLike = ''
  172 + this.workDetailEventInfo.queryStartTime = ''
  173 + this.workDetailEventInfo.queryEndTime = ''
  174 + this.queryWorkDetailEvent()
  175 + },
  176 + handleSizeChange(val) {
  177 + this.page.size = val
  178 + this.loadWorkDetailEventData(this.page.current, this.page.size)
  179 + },
  180 + handleCurrentChange(val) {
  181 + this.page.current = val
  182 + this.loadWorkDetailEventData(this.page.current, this.page.size)
  183 + }
  184 + }
  185 +}
  186 +</script>
  187 +
  188 +<style scoped>
  189 +.tree-container {
  190 + height: 500px;
  191 + border: 1px solid #ebeef5;
  192 + border-radius: 4px;
  193 + padding: 10px;
  194 +}
  195 +
  196 +.content-list {
  197 + list-style: none;
  198 + padding: 0;
  199 + margin: 0;
  200 +}
  201 +
  202 +.content-list li {
  203 + padding: 10px;
  204 + margin-bottom: 5px;
  205 + border-radius: 4px;
  206 + cursor: pointer;
  207 + text-align: center;
  208 +}
  209 +
  210 +.content-list li:hover {
  211 + background-color: #f5f7fa;
  212 +}
  213 +
  214 +.active-content {
  215 + background-color: #ecf5ff;
  216 + color: #409eff;
  217 + border: 1px solid #d9ecff;
  218 +}
  219 +
  220 +.margin-top-lg {
  221 + margin-top: 20px;
  222 +}
  223 +.margin-top {
  224 + margin-top: 20px;
  225 +}
  226 +</style>
0 227 \ No newline at end of file
... ...
src/components/oa/WorkDetailFile.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-file">
  3 + <el-row :gutter="20">
  4 + <el-col :span="4">
  5 + <div class="tree-container">
  6 + <el-scrollbar>
  7 + <ul class="content-list">
  8 + <li
  9 + v-for="(item,index) in workDetailFileInfo.contents"
  10 + :key="index"
  11 + @click="swatchFileContentId(item)"
  12 + :class="{'active-content': workDetailFileInfo.contentId === item.contentId}"
  13 + >
  14 + 问题{{ item.seqNum }}
  15 + </li>
  16 + </ul>
  17 + </el-scrollbar>
  18 + </div>
  19 + </el-col>
  20 + <el-col :span="20">
  21 + <el-row :gutter="20" class="margin-top-lg">
  22 + <el-col :span="6">
  23 + <el-input
  24 + v-model.trim="workDetailFileInfo.staffNameLike"
  25 + :placeholder="$t('workDetailFile.staffNamePlaceholder')"
  26 + clearable
  27 + />
  28 + </el-col>
  29 + <el-col :span="6">
  30 + <el-date-picker
  31 + v-model="workDetailFileInfo.queryStartTime"
  32 + type="datetime"
  33 + :placeholder="$t('workDetailFile.startTimePlaceholder')"
  34 + value-format="yyyy-MM-dd HH:mm:ss"
  35 + style="width: 100%"
  36 + />
  37 + </el-col>
  38 + <el-col :span="6">
  39 + <el-date-picker
  40 + v-model="workDetailFileInfo.queryEndTime"
  41 + type="datetime"
  42 + :placeholder="$t('workDetailFile.endTimePlaceholder')"
  43 + value-format="yyyy-MM-dd HH:mm:ss"
  44 + style="width: 100%"
  45 + />
  46 + </el-col>
  47 + <el-col :span="6">
  48 + <el-button type="primary" @click="queryWorkDetailFile">
  49 + <i class="el-icon-search"></i>{{ $t('common.search') }}
  50 + </el-button>
  51 + <el-button @click="resetWorkDetailFile">
  52 + <i class="el-icon-refresh"></i>{{ $t('common.reset') }}
  53 + </el-button>
  54 + </el-col>
  55 + </el-row>
  56 +
  57 + <div class="margin-top">
  58 + <el-table
  59 + :data="workDetailFileInfo.files"
  60 + border
  61 + style="width: 100%"
  62 + v-loading="loading"
  63 + >
  64 + <el-table-column
  65 + prop="staffName"
  66 + :label="$t('workDetailFile.staffName')"
  67 + align="center"
  68 + />
  69 + <el-table-column
  70 + :label="$t('workDetailFile.attachment')"
  71 + align="center"
  72 + >
  73 + <template slot-scope="scope">
  74 + <div v-if="scope.row.fileType !== 'S'">
  75 + <el-image
  76 + v-if="scope.row.pathUrl.endsWith('jpg') || scope.row.pathUrl.endsWith('png')"
  77 + style="width: 60px; height: 60px;"
  78 + :src="scope.row.pathUrl"
  79 + :preview-src-list="[scope.row.pathUrl]"
  80 + fit="cover"
  81 + />
  82 + <el-link v-else :href="scope.row.pathUrl" target="_blank">
  83 + {{ $t('common.download') }}
  84 + </el-link>
  85 + </div>
  86 + <span v-else>--</span>
  87 + </template>
  88 + </el-table-column>
  89 + </el-table>
  90 +
  91 + <el-pagination
  92 + :current-page.sync="page.current"
  93 + :page-sizes="[10, 20, 30, 50]"
  94 + :page-size="page.size"
  95 + :total="page.total"
  96 + layout="total, sizes, prev, pager, next, jumper"
  97 + @size-change="handleSizeChange"
  98 + @current-change="handleCurrentChange"
  99 + />
  100 + </div>
  101 + </el-col>
  102 + </el-row>
  103 + </div>
  104 +</template>
  105 +
  106 +<script>
  107 +import { listWorkPoolFile } from '@/api/oa/workDetailApi'
  108 +
  109 +export default {
  110 + name: 'WorkDetailFile',
  111 + data() {
  112 + return {
  113 + workDetailFileInfo: {
  114 + files: [],
  115 + contents: [],
  116 + workId: '',
  117 + contentId: '',
  118 + staffNameLike: '',
  119 + queryStartTime: '',
  120 + queryEndTime: ''
  121 + },
  122 + loading: false,
  123 + page: {
  124 + current: 1,
  125 + size: 10,
  126 + total: 0
  127 + }
  128 + }
  129 + },
  130 + methods: {
  131 + open(params) {
  132 + this.workDetailFileInfo.workId = params.workId
  133 + this.workDetailFileInfo.contents = params.contents
  134 + if (params.contents.length > 0) {
  135 + this.swatchFileContentId(params.contents[0])
  136 + }
  137 + },
  138 + async loadWorkDetailFileData(page, size) {
  139 + try {
  140 + this.loading = true
  141 + const params = {
  142 + workId: this.workDetailFileInfo.workId,
  143 + contentId: this.workDetailFileInfo.contentId,
  144 + staffNameLike: this.workDetailFileInfo.staffNameLike,
  145 + queryStartTime: this.workDetailFileInfo.queryStartTime,
  146 + queryEndTime: this.workDetailFileInfo.queryEndTime,
  147 + page,
  148 + row: size
  149 + }
  150 + const { data, total } = await listWorkPoolFile(params)
  151 + this.workDetailFileInfo.files = data
  152 + this.page.total = total
  153 + } catch (error) {
  154 + console.error('获取流转附件列表失败:', error)
  155 + } finally {
  156 + this.loading = false
  157 + }
  158 + },
  159 + queryWorkDetailFile() {
  160 + this.page.current = 1
  161 + this.loadWorkDetailFileData(this.page.current, this.page.size)
  162 + },
  163 + swatchFileContentId(content) {
  164 + this.workDetailFileInfo.contentId = content.contentId
  165 + this.loadWorkDetailFileData(this.page.current, this.page.size)
  166 + },
  167 + resetWorkDetailFile() {
  168 + this.workDetailFileInfo.staffNameLike = ''
  169 + this.workDetailFileInfo.queryStartTime = ''
  170 + this.workDetailFileInfo.queryEndTime = ''
  171 + this.queryWorkDetailFile()
  172 + },
  173 + handleSizeChange(val) {
  174 + this.page.size = val
  175 + this.loadWorkDetailFileData(this.page.current, this.page.size)
  176 + },
  177 + handleCurrentChange(val) {
  178 + this.page.current = val
  179 + this.loadWorkDetailFileData(this.page.current, this.page.size)
  180 + }
  181 + }
  182 +}
  183 +</script>
  184 +
  185 +<style scoped>
  186 +.tree-container {
  187 + height: 500px;
  188 + border: 1px solid #ebeef5;
  189 + border-radius: 4px;
  190 + padding: 10px;
  191 +}
  192 +
  193 +.content-list {
  194 + list-style: none;
  195 + padding: 0;
  196 + margin: 0;
  197 +}
  198 +
  199 +.content-list li {
  200 + padding: 10px;
  201 + margin-bottom: 5px;
  202 + border-radius: 4px;
  203 + cursor: pointer;
  204 + text-align: center;
  205 +}
  206 +
  207 +.content-list li:hover {
  208 + background-color: #f5f7fa;
  209 +}
  210 +
  211 +.active-content {
  212 + background-color: #ecf5ff;
  213 + color: #409eff;
  214 + border: 1px solid #d9ecff;
  215 +}
  216 +
  217 +.margin-top-lg {
  218 + margin-top: 20px;
  219 +}
  220 +.margin-top {
  221 + margin-top: 20px;
  222 +}
  223 +</style>
0 224 \ No newline at end of file
... ...
src/components/oa/WorkDetailTask.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-task">
  3 + <el-row :gutter="20" class="margin-top-lg">
  4 + <el-col :span="6">
  5 + <el-input
  6 + v-model.trim="workDetailTaskInfo.staffNameLike"
  7 + :placeholder="$t('workDetailTask.staffNamePlaceholder')"
  8 + clearable
  9 + />
  10 + </el-col>
  11 + <el-col :span="6">
  12 + <el-date-picker
  13 + v-model="workDetailTaskInfo.queryStartTime"
  14 + type="datetime"
  15 + :placeholder="$t('workDetailTask.startTimePlaceholder')"
  16 + value-format="yyyy-MM-dd HH:mm:ss"
  17 + style="width: 100%"
  18 + />
  19 + </el-col>
  20 + <el-col :span="6">
  21 + <el-date-picker
  22 + v-model="workDetailTaskInfo.queryEndTime"
  23 + type="datetime"
  24 + :placeholder="$t('workDetailTask.endTimePlaceholder')"
  25 + value-format="yyyy-MM-dd HH:mm:ss"
  26 + style="width: 100%"
  27 + />
  28 + </el-col>
  29 + <el-col :span="6">
  30 + <el-button type="primary" @click="queryWorkDetailTask">
  31 + <i class="el-icon-search"></i>{{ $t('common.search') }}
  32 + </el-button>
  33 + <el-button @click="resetWorkDetailTask">
  34 + <i class="el-icon-refresh"></i>{{ $t('common.reset') }}
  35 + </el-button>
  36 + </el-col>
  37 + </el-row>
  38 +
  39 + <div class="margin-top">
  40 + <el-table
  41 + :data="workDetailTaskInfo.tasks"
  42 + border
  43 + style="width: 100%"
  44 + v-loading="loading"
  45 + >
  46 + <el-table-column
  47 + prop="taskId"
  48 + :label="$t('workDetailTask.taskId')"
  49 + align="center"
  50 + />
  51 + <el-table-column
  52 + prop="staffName"
  53 + :label="$t('workDetailTask.staffName')"
  54 + align="center"
  55 + />
  56 + <el-table-column
  57 + prop="startTime"
  58 + :label="$t('workDetailTask.startTime')"
  59 + align="center"
  60 + />
  61 + <el-table-column
  62 + prop="endTime"
  63 + :label="$t('workDetailTask.endTime')"
  64 + align="center"
  65 + />
  66 + <el-table-column
  67 + prop="createTime"
  68 + :label="$t('workDetailTask.createTime')"
  69 + align="center"
  70 + />
  71 + <el-table-column
  72 + prop="stateName"
  73 + :label="$t('workDetailTask.stateName')"
  74 + align="center"
  75 + />
  76 + <el-table-column
  77 + :label="$t('common.operation')"
  78 + align="center"
  79 + width="120"
  80 + >
  81 + <template slot-scope="scope">
  82 + <el-button
  83 + size="mini"
  84 + @click="openWorkTaskDetail(scope.row)"
  85 + >
  86 + {{ $t('workDetailTask.progress') }}
  87 + </el-button>
  88 + </template>
  89 + </el-table-column>
  90 + </el-table>
  91 +
  92 + <el-pagination
  93 + :current-page.sync="page.current"
  94 + :page-sizes="[10, 20, 30, 50]"
  95 + :page-size="page.size"
  96 + :total="page.total"
  97 + layout="total, sizes, prev, pager, next, jumper"
  98 + @size-change="handleSizeChange"
  99 + @current-change="handleCurrentChange"
  100 + />
  101 + </div>
  102 + </div>
  103 +</template>
  104 +
  105 +<script>
  106 +import { listWorkTask } from '@/api/oa/workDetailApi'
  107 +
  108 +export default {
  109 + name: 'WorkDetailTask',
  110 + data() {
  111 + return {
  112 + workDetailTaskInfo: {
  113 + tasks: [],
  114 + workId: '',
  115 + staffNameLike: '',
  116 + queryStartTime: '',
  117 + queryEndTime: ''
  118 + },
  119 + loading: false,
  120 + page: {
  121 + current: 1,
  122 + size: 10,
  123 + total: 0
  124 + }
  125 + }
  126 + },
  127 + methods: {
  128 + open(params) {
  129 + this.workDetailTaskInfo.workId = params.workId
  130 + this.loadWorkDetailTaskData(this.page.current, this.page.size)
  131 + },
  132 + async loadWorkDetailTaskData(page, size) {
  133 + try {
  134 + this.loading = true
  135 + const params = {
  136 + workId: this.workDetailTaskInfo.workId,
  137 + staffNameLike: this.workDetailTaskInfo.staffNameLike,
  138 + queryStartTime: this.workDetailTaskInfo.queryStartTime,
  139 + queryEndTime: this.workDetailTaskInfo.queryEndTime,
  140 + page,
  141 + row: size
  142 + }
  143 + const { data, total } = await listWorkTask(params)
  144 + this.workDetailTaskInfo.tasks = data
  145 + this.page.total = total
  146 + } catch (error) {
  147 + console.error('获取任务列表失败:', error)
  148 + } finally {
  149 + this.loading = false
  150 + }
  151 + },
  152 + queryWorkDetailTask() {
  153 + this.page.current = 1
  154 + this.loadWorkDetailTaskData(this.page.current, this.page.size)
  155 + },
  156 + resetWorkDetailTask() {
  157 + this.workDetailTaskInfo.staffNameLike = ''
  158 + this.workDetailTaskInfo.queryStartTime = ''
  159 + this.workDetailTaskInfo.queryEndTime = ''
  160 + this.queryWorkDetailTask()
  161 + },
  162 + openWorkTaskDetail(work) {
  163 + this.$router.push({
  164 + path: '/oa/workTaskDetail',
  165 + query: {
  166 + workId: work.workId,
  167 + taskId: work.taskId
  168 + }
  169 + })
  170 + },
  171 + handleSizeChange(val) {
  172 + this.page.size = val
  173 + this.loadWorkDetailTaskData(this.page.current, this.page.size)
  174 + },
  175 + handleCurrentChange(val) {
  176 + this.page.current = val
  177 + this.loadWorkDetailTaskData(this.page.current, this.page.size)
  178 + }
  179 + }
  180 +}
  181 +</script>
  182 +
  183 +<style scoped>
  184 +.margin-top-lg {
  185 + margin-top: 20px;
  186 +}
  187 +.margin-top {
  188 + margin-top: 20px;
  189 +}
  190 +</style>
0 191 \ No newline at end of file
... ...
src/components/oa/WorkDetailTaskItem.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-task-item">
  3 + <el-row :gutter="20">
  4 + <el-col :span="4">
  5 + <div class="tree-container">
  6 + <el-scrollbar>
  7 + <ul class="task-list">
  8 + <li v-for="(item, index) in workDetailTaskItemInfo.tasks" :key="index" @click="swatchTaskItemTaskId(item)"
  9 + :class="{ 'active-task': workDetailTaskItemInfo.taskId === item.taskId }">
  10 + <div>{{ item.staffName }}</div>
  11 + <div>({{ formatDate(item.startTime) }} ~ {{ formatDate(item.endTime) }})</div>
  12 + </li>
  13 + </ul>
  14 + </el-scrollbar>
  15 + </div>
  16 + </el-col>
  17 + <el-col :span="20">
  18 + <el-table :data="workDetailTaskItemInfo.items" border style="width: 100%" v-loading="loading">
  19 + <el-table-column prop="content" :label="$t('workDetailTaskItem.content')" width="400" />
  20 + <el-table-column prop="finishTime" :label="$t('workDetailTaskItem.finishTime')" align="center" />
  21 + <el-table-column :label="$t('workDetailTaskItem.state')" align="center">
  22 + <template slot-scope="scope">
  23 + <span v-if="scope.row.state === 'CC'">{{ $t('workDetailTaskItem.copyProcessed') }}</span>
  24 + <span v-else-if="scope.row.state === 'C'">{{ $t('workDetailTaskItem.handlerProcessed') }}</span>
  25 + <span v-else>{{ $t('workDetailTaskItem.pending') }}</span>
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column prop="remark" :label="$t('workDetailTaskItem.remark')" align="center" />
  29 + <el-table-column :label="$t('workDetailTaskItem.attachment')" align="center">
  30 + <template slot-scope="scope">
  31 + <div v-if="scope.row.pathUrls">
  32 + <div v-for="(url, index) in scope.row.pathUrls" :key="index">
  33 + <div v-if="url.endsWith('jpg') || url.endsWith('png')">
  34 + <el-image style="width: 60px; height: 60px;" :src="url" :preview-src-list="[url]" fit="cover" />
  35 + </div>
  36 + <div v-else>
  37 + <el-link :href="url" target="_blank">{{ $t('common.download') }}</el-link>
  38 + </div>
  39 + </div>
  40 + </div>
  41 + <div v-else>-</div>
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column prop="score" :label="$t('workDetailTaskItem.score')" align="center" />
  45 + <el-table-column prop="deductionMoney" :label="$t('workDetailTaskItem.deductionMoney')" align="center" />
  46 + <el-table-column prop="deductionReason" :label="$t('workDetailTaskItem.deductionReason')" align="center" />
  47 + <el-table-column prop="deductionPersonName" :label="$t('workDetailTaskItem.deductionPerson')"
  48 + align="center" />
  49 + <el-table-column prop="createTime" :label="$t('workDetailTaskItem.createTime')" align="center" />
  50 + </el-table>
  51 + </el-col>
  52 + </el-row>
  53 + </div>
  54 +</template>
  55 +
  56 +<script>
  57 +import { listWorkTask, listWorkTaskItem } from '@/api/oa/workDetailApi'
  58 +import { dateFormat } from '@/utils/dateUtil'
  59 +
  60 +export default {
  61 + name: 'WorkDetailTaskItem',
  62 + data() {
  63 + return {
  64 + workDetailTaskItemInfo: {
  65 + tasks: [],
  66 + workId: '',
  67 + taskId: '',
  68 + items: []
  69 + },
  70 + loading: false
  71 + }
  72 + },
  73 + methods: {
  74 + open(params) {
  75 + this.workDetailTaskItemInfo.workId = params.workId
  76 + this.queryWorkDetailTaskData()
  77 + },
  78 + async queryWorkDetailTaskData() {
  79 + try {
  80 + this.loading = true
  81 + const params = {
  82 + workId: this.workDetailTaskItemInfo.workId,
  83 + page: 1,
  84 + row: 100
  85 + }
  86 + const { data } = await listWorkTask(params)
  87 + this.workDetailTaskItemInfo.tasks = data
  88 + if (data.length > 0) {
  89 + this.swatchTaskItemTaskId(data[0])
  90 + }
  91 + } catch (error) {
  92 + console.error('获取任务列表失败:', error)
  93 + } finally {
  94 + this.loading = false
  95 + }
  96 + },
  97 + async loadWorkDetailTaskItemData() {
  98 + try {
  99 + this.loading = true
  100 + const params = {
  101 + workId: this.workDetailTaskItemInfo.workId,
  102 + taskId: this.workDetailTaskItemInfo.taskId,
  103 + page: 1,
  104 + row: 100
  105 + }
  106 + const { data } = await listWorkTaskItem(params)
  107 + this.workDetailTaskItemInfo.items = data
  108 + } catch (error) {
  109 + console.error('获取任务项列表失败:', error)
  110 + } finally {
  111 + this.loading = false
  112 + }
  113 + },
  114 + swatchTaskItemTaskId(task) {
  115 + this.workDetailTaskItemInfo.taskId = task.taskId
  116 + this.loadWorkDetailTaskItemData()
  117 + },
  118 + formatDate(date) {
  119 + return dateFormat(date)
  120 + }
  121 + }
  122 +}
  123 +</script>
  124 +
  125 +<style scoped>
  126 +.tree-container {
  127 + height: 500px;
  128 + border: 1px solid #ebeef5;
  129 + border-radius: 4px;
  130 + padding: 10px;
  131 +}
  132 +
  133 +.task-list {
  134 + list-style: none;
  135 + padding: 0;
  136 + margin: 0;
  137 +}
  138 +
  139 +.task-list li {
  140 + padding: 10px;
  141 + margin-bottom: 5px;
  142 + border-radius: 4px;
  143 + cursor: pointer;
  144 + text-align: center;
  145 +}
  146 +
  147 +.task-list li:hover {
  148 + background-color: #f5f7fa;
  149 +}
  150 +
  151 +.active-task {
  152 + background-color: #ecf5ff;
  153 + color: #409eff;
  154 + border: 1px solid #d9ecff;
  155 +}
  156 +</style>
0 157 \ No newline at end of file
... ...
src/components/oa/WorkDetailType.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-type">
  3 + <div class="margin-top">
  4 + <el-table
  5 + :data="workDetailTypeInfo.types"
  6 + border
  7 + style="width: 100%"
  8 + v-loading="loading"
  9 + >
  10 + <el-table-column
  11 + prop="typeName"
  12 + :label="$t('workDetailType.typeName')"
  13 + align="center"
  14 + />
  15 + <el-table-column
  16 + :label="$t('workDetailType.notifyWay')"
  17 + align="center"
  18 + >
  19 + <template slot-scope="scope">
  20 + <span v-if="scope.row.smsWay === 'WECHAT'">{{ $t('workDetailType.wechat') }}</span>
  21 + <span v-else-if="scope.row.smsWay === 'ALI_SMS'">{{ $t('workDetailType.aliSms') }}</span>
  22 + <span v-else>{{ $t('workDetailType.unknown') }}</span>
  23 + </template>
  24 + </el-table-column>
  25 + <el-table-column
  26 + prop="createTime"
  27 + :label="$t('workDetailType.createTime')"
  28 + align="center"
  29 + />
  30 + <el-table-column
  31 + prop="remark"
  32 + :label="$t('workDetailType.remark')"
  33 + align="center"
  34 + >
  35 + <template slot-scope="scope">
  36 + {{ scope.row.remark || '-' }}
  37 + </template>
  38 + </el-table-column>
  39 + </el-table>
  40 +
  41 + <el-pagination
  42 + :current-page.sync="page.current"
  43 + :page-sizes="[10, 20, 30, 50]"
  44 + :page-size="page.size"
  45 + :total="page.total"
  46 + layout="total, sizes, prev, pager, next, jumper"
  47 + @size-change="handleSizeChange"
  48 + @current-change="handleCurrentChange"
  49 + />
  50 + </div>
  51 + </div>
  52 +</template>
  53 +
  54 +<script>
  55 +import { listWorkType } from '@/api/oa/workDetailApi'
  56 +import { getCommunityId } from '@/api/community/communityApi'
  57 +
  58 +export default {
  59 + name: 'WorkDetailType',
  60 + data() {
  61 + return {
  62 + workDetailTypeInfo: {
  63 + types: [],
  64 + wtId: ''
  65 + },
  66 + loading: false,
  67 + page: {
  68 + current: 1,
  69 + size: 10,
  70 + total: 0
  71 + },
  72 + communityId: ''
  73 + }
  74 + },
  75 + created() {
  76 + this.communityId = getCommunityId()
  77 + },
  78 + methods: {
  79 + open(params) {
  80 + this.workDetailTypeInfo.wtId = params.wtId
  81 + this.loadWorkDetailTypeData(this.page.current, this.page.size)
  82 + },
  83 + async loadWorkDetailTypeData(page, size) {
  84 + try {
  85 + this.loading = true
  86 + const params = {
  87 + wtId: this.workDetailTypeInfo.wtId,
  88 + communityId: this.communityId,
  89 + page,
  90 + row: size
  91 + }
  92 + const { data, total } = await listWorkType(params)
  93 + this.workDetailTypeInfo.types = data
  94 + this.page.total = total
  95 + } catch (error) {
  96 + console.error('获取工作单类型列表失败:', error)
  97 + } finally {
  98 + this.loading = false
  99 + }
  100 + },
  101 + handleSizeChange(val) {
  102 + this.page.size = val
  103 + this.loadWorkDetailTypeData(this.page.current, this.page.size)
  104 + },
  105 + handleCurrentChange(val) {
  106 + this.page.current = val
  107 + this.loadWorkDetailTypeData(this.page.current, this.page.size)
  108 + }
  109 + }
  110 +}
  111 +</script>
  112 +
  113 +<style scoped>
  114 +.margin-top {
  115 + margin-top: 20px;
  116 +}
  117 +</style>
0 118 \ No newline at end of file
... ...
src/i18n/oaI18n.js
... ... @@ -41,6 +41,7 @@ import { messages as workTypeMessages } from &#39;../views/oa/workTypeLang&#39;
41 41 import { messages as startWorkMessages } from '../views/oa/startWorkLang'
42 42 import { messages as addWorkMessages } from '../views/oa/addWorkLang'
43 43 import { messages as editWorkMessages } from '../views/oa/editWorkLang'
  44 +import { messages as workDetailMessages } from '../views/oa/workDetailLang'
44 45 export const messages ={
45 46 en:{
46 47 ...activitiesTypeManageMessages.en,
... ... @@ -85,6 +86,7 @@ export const messages ={
85 86 ...startWorkMessages.en,
86 87 ...addWorkMessages.en,
87 88 ...editWorkMessages.en,
  89 + ...workDetailMessages.en,
88 90 },
89 91 zh:{
90 92 ...activitiesTypeManageMessages.zh,
... ... @@ -129,5 +131,6 @@ export const messages ={
129 131 ...startWorkMessages.zh,
130 132 ...addWorkMessages.zh,
131 133 ...editWorkMessages.zh,
  134 + ...workDetailMessages.zh,
132 135 }
133 136 }
134 137 \ No newline at end of file
... ...
src/router/oaRouter.js
... ... @@ -185,13 +185,18 @@ export default [
185 185 component: () => import('@/views/oa/startWorkList.vue')
186 186 },
187 187 {
188   - path:'/views/oa/addWork',
189   - name:'/views/oa/addWork',
  188 + path: '/views/oa/addWork',
  189 + name: '/views/oa/addWork',
190 190 component: () => import('@/views/oa/addWorkList.vue')
191   - },
192   - {
193   - path:'/views/oa/editWork',
194   - name:'/views/oa/editWork',
195   - component: () => import('@/views/oa/editWorkList.vue')
196   - },
  191 + },
  192 + {
  193 + path: '/views/oa/editWork',
  194 + name: '/views/oa/editWork',
  195 + component: () => import('@/views/oa/editWorkList.vue')
  196 + },
  197 + {
  198 + path: '/views/oa/workDetail',
  199 + name: '/views/oa/workDetail',
  200 + component: () => import('@/views/oa/workDetailList.vue')
  201 + },
197 202 ]
198 203 \ No newline at end of file
... ...
src/views/oa/startWorkList.vue
... ... @@ -201,7 +201,7 @@ export default {
201 201 this.$router.push(`/views/oa/editWork?workId=${row.workId}`)
202 202 },
203 203 handleDetail(row) {
204   - this.$router.push(`/oa/workDetail?workId=${row.workId}`)
  204 + this.$router.push(`/views/oa/workDetail?workId=${row.workId}`)
205 205 },
206 206 handleDelete(row) {
207 207 this.$refs.deleteWork.open(row)
... ...
src/views/oa/workDetailLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + workDetail: {
  4 + title: 'Work Order Details',
  5 + workId: 'Work Order ID',
  6 + workName: 'Work Order Name',
  7 + typeName: 'Type Name',
  8 + workCycle: 'Mark',
  9 + once: 'One-time Work Order',
  10 + periodic: 'Periodic Work Order',
  11 + startTime: 'Start Time',
  12 + endTime: 'End Time',
  13 + createUserName: 'Initiator',
  14 + curStaffName: 'Handler',
  15 + curCopyName: 'Copy Person',
  16 + stateName: 'Status',
  17 + createTime: 'Create Time',
  18 + attachment: 'Attachment',
  19 + content: 'Content',
  20 + handler: 'Handler',
  21 + handlerContent: 'Handler Content',
  22 + copyPerson: 'Copy Person',
  23 + workFlow: 'Work Order Flow',
  24 + flowAttachment: 'Flow Attachment',
  25 + workType: 'Work Order Type',
  26 + workCycleTab: 'Work Order Cycle'
  27 + },
  28 + workDetailTask: {
  29 + taskId: 'Task ID',
  30 + staffName: 'Handler',
  31 + startTime: 'Start Time',
  32 + endTime: 'End Time',
  33 + createTime: 'Create Time',
  34 + stateName: 'Status',
  35 + operation: 'Operation',
  36 + progress: 'Progress',
  37 + staffNamePlaceholder: 'Please enter handler',
  38 + startTimePlaceholder: 'Start time',
  39 + endTimePlaceholder: 'End time'
  40 + },
  41 + workDetailTaskItem: {
  42 + content: 'Work Content',
  43 + finishTime: 'Finish Time',
  44 + state: 'Status',
  45 + remark: 'Remark',
  46 + attachment: 'Attachment',
  47 + score: 'Score',
  48 + deductionMoney: 'Deduction Amount',
  49 + deductionReason: 'Deduction Reason',
  50 + deductionPerson: 'Deduction Person',
  51 + createTime: 'Create Time',
  52 + copyProcessed: 'Copy Person Processed',
  53 + handlerProcessed: 'Handler Processed',
  54 + pending: 'Pending'
  55 + },
  56 + workDetailCopy: {
  57 + copyId: 'Task ID',
  58 + staffName: 'Copy Person',
  59 + createTime: 'Create Time',
  60 + stateName: 'Status',
  61 + remark: 'Remark',
  62 + staffNamePlaceholder: 'Please enter copy person'
  63 + },
  64 + workDetailEvent: {
  65 + preStaffName: 'Previous Handler',
  66 + staffName: 'Handler',
  67 + taskValidPeriod: 'Task Valid Period',
  68 + remark: 'Remark',
  69 + createTime: 'Time',
  70 + staffNamePlaceholder: 'Please enter handler',
  71 + startTimePlaceholder: 'Start time',
  72 + endTimePlaceholder: 'End time'
  73 + },
  74 + workDetailFile: {
  75 + staffName: 'Handler',
  76 + attachment: 'Attachment',
  77 + staffNamePlaceholder: 'Please enter handler',
  78 + startTimePlaceholder: 'Start time',
  79 + endTimePlaceholder: 'End time'
  80 + },
  81 + workDetailType: {
  82 + typeName: 'Type Name',
  83 + notifyWay: 'Notification Method',
  84 + createTime: 'Create Time',
  85 + remark: 'Remark',
  86 + wechat: 'WeChat',
  87 + aliSms: 'Ali SMS',
  88 + unknown: 'Unknown'
  89 + },
  90 + workDetailCycle: {
  91 + staffName: 'Handler',
  92 + workCycle: 'Mark',
  93 + hours: 'Completion Hours',
  94 + period: 'Cycle',
  95 + month: 'Month',
  96 + day: 'Day',
  97 + week: 'Week',
  98 + once: 'One-time Work Order',
  99 + periodic: 'Periodic Work Order',
  100 + monthDay: 'Month/Day',
  101 + weekly: 'Weekly'
  102 + }
  103 + },
  104 + zh: {
  105 + workDetail: {
  106 + title: '工作单详情',
  107 + workId: '工单编号',
  108 + workName: '工单名称',
  109 + typeName: '类型名称',
  110 + workCycle: '标识',
  111 + once: '一次性工单',
  112 + periodic: '周期性工单',
  113 + startTime: '开始时间',
  114 + endTime: '结束时间',
  115 + createUserName: '发起人',
  116 + curStaffName: '处理人',
  117 + curCopyName: '抄送人',
  118 + stateName: '状态',
  119 + createTime: '创建时间',
  120 + attachment: '附件',
  121 + content: '内容',
  122 + handler: '处理人',
  123 + handlerContent: '处理内容',
  124 + copyPerson: '抄送人',
  125 + workFlow: '工作单流转',
  126 + flowAttachment: '流转附件',
  127 + workType: '工作单类型',
  128 + workCycleTab: '工作单周期'
  129 + },
  130 + workDetailTask: {
  131 + taskId: '任务编号',
  132 + staffName: '处理人',
  133 + startTime: '开始时间',
  134 + endTime: '结束时间',
  135 + createTime: '创建时间',
  136 + stateName: '状态',
  137 + operation: '操作',
  138 + progress: '进度',
  139 + staffNamePlaceholder: '请填写处理人',
  140 + startTimePlaceholder: '开始时间',
  141 + endTimePlaceholder: '结束时间'
  142 + },
  143 + workDetailTaskItem: {
  144 + content: '工作内容',
  145 + finishTime: '完成时间',
  146 + state: '状态',
  147 + remark: '说明',
  148 + attachment: '附件',
  149 + score: '评分',
  150 + deductionMoney: '扣款金额',
  151 + deductionReason: '扣款原因',
  152 + deductionPerson: '扣款人',
  153 + createTime: '创建时间',
  154 + copyProcessed: '抄送人已办理',
  155 + handlerProcessed: '处理人已办理',
  156 + pending: '待处理'
  157 + },
  158 + workDetailCopy: {
  159 + copyId: '任务编号',
  160 + staffName: '抄送人',
  161 + createTime: '创建时间',
  162 + stateName: '状态',
  163 + remark: '说明',
  164 + staffNamePlaceholder: '请填写抄送人'
  165 + },
  166 + workDetailEvent: {
  167 + preStaffName: '前处理人',
  168 + staffName: '处理人',
  169 + taskValidPeriod: '任务有效期',
  170 + remark: '说明',
  171 + createTime: '时间',
  172 + staffNamePlaceholder: '请填写处理人',
  173 + startTimePlaceholder: '开始时间',
  174 + endTimePlaceholder: '结束时间'
  175 + },
  176 + workDetailFile: {
  177 + staffName: '处理人',
  178 + attachment: '附件',
  179 + staffNamePlaceholder: '请填写处理人',
  180 + startTimePlaceholder: '开始时间',
  181 + endTimePlaceholder: '结束时间'
  182 + },
  183 + workDetailType: {
  184 + typeName: '类型名称',
  185 + notifyWay: '通知方式',
  186 + createTime: '创建时间',
  187 + remark: '备注',
  188 + wechat: '微信',
  189 + aliSms: '阿里短信',
  190 + unknown: '未知'
  191 + },
  192 + workDetailCycle: {
  193 + staffName: '处理人',
  194 + workCycle: '标识',
  195 + hours: '完成小时',
  196 + period: '周期',
  197 + month: '月',
  198 + day: '日',
  199 + week: '周',
  200 + once: '一次性工单',
  201 + periodic: '周期性工单',
  202 + monthDay: '月/天',
  203 + weekly: '按周'
  204 + }
  205 + }
  206 +}
0 207 \ No newline at end of file
... ...
src/views/oa/workDetailList.vue 0 → 100644
  1 +<template>
  2 + <div class="work-detail-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <div class="flex justify-between">
  6 + <div class="text-title">{{ $t('workDetail.title') }}</div>
  7 + <div>
  8 + <el-button type="primary" size="small" @click="goBack">
  9 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  10 + </el-button>
  11 + </div>
  12 + </div>
  13 + </div>
  14 +
  15 + <!-- 业主信息 -->
  16 + <div class="margin-top">
  17 + <el-row :gutter="20" >
  18 + <el-col :span="24" class="text-left">
  19 + <el-row :gutter="20">
  20 + <el-col :span="6">
  21 + <div class="form-group">
  22 + <label class="col-form-label">
  23 + {{ $t('workDetail.workId') }}:
  24 + </label>
  25 + <label>{{ workDetailInfo.workId }}</label>
  26 + </div>
  27 + </el-col>
  28 + <el-col :span="6">
  29 + <div class="form-group">
  30 + <label class="col-form-label">
  31 + {{ $t('workDetail.workName') }}:
  32 + </label>
  33 + <label>{{ workDetailInfo.workName }}</label>
  34 + </div>
  35 + </el-col>
  36 + <el-col :span="6">
  37 + <div class="form-group">
  38 + <label class="col-form-label">
  39 + {{ $t('workDetail.typeName') }}:
  40 + </label>
  41 + <label>{{ workDetailInfo.typeName }}</label>
  42 + </div>
  43 + </el-col>
  44 + <el-col :span="6">
  45 + <div class="form-group">
  46 + <label class="col-form-label">
  47 + {{ $t('workDetail.workCycle') }}:
  48 + </label>
  49 + <label>{{ workDetailInfo.workCycle == '1001' ? $t('workDetail.once') : $t('workDetail.periodic')
  50 + }}</label>
  51 + </div>
  52 + </el-col>
  53 + </el-row>
  54 + <el-row :gutter="20">
  55 + <el-col :span="6">
  56 + <div class="form-group">
  57 + <label class="col-form-label">
  58 + {{ $t('workDetail.startTime') }}:
  59 + </label>
  60 + <label>{{ workDetailInfo.startTime }}</label>
  61 + </div>
  62 + </el-col>
  63 + <el-col :span="6">
  64 + <div class="form-group">
  65 + <label class="col-form-label">
  66 + {{ $t('workDetail.endTime') }}:
  67 + </label>
  68 + <label>{{ workDetailInfo.endTime }}</label>
  69 + </div>
  70 + </el-col>
  71 + <el-col :span="6">
  72 + <div class="form-group">
  73 + <label class="col-form-label">
  74 + {{ $t('workDetail.createUserName') }}:
  75 + </label>
  76 + <label>{{ workDetailInfo.createUserName }}</label>
  77 + </div>
  78 + </el-col>
  79 + <el-col :span="6">
  80 + <div class="form-group">
  81 + <label class="col-form-label">
  82 + {{ $t('workDetail.curStaffName') }}:
  83 + </label>
  84 + <label>{{ workDetailInfo.curStaffName }}</label>
  85 + </div>
  86 + </el-col>
  87 + <el-col :span="6">
  88 + <div class="form-group">
  89 + <label class="col-form-label">
  90 + {{ $t('workDetail.curCopyName') }}:
  91 + </label>
  92 + <label>{{ workDetailInfo.curCopyName }}</label>
  93 + </div>
  94 + </el-col>
  95 + <el-col :span="6">
  96 + <div class="form-group">
  97 + <label class="col-form-label">
  98 + {{ $t('workDetail.stateName') }}:
  99 + </label>
  100 + <label>{{ workDetailInfo.stateName }}</label>
  101 + </div>
  102 + </el-col>
  103 + <el-col :span="6">
  104 + <div class="form-group">
  105 + <label class="col-form-label">
  106 + {{ $t('workDetail.createTime') }}:
  107 + </label>
  108 + <label>{{ workDetailInfo.createTime }}</label>
  109 + </div>
  110 + </el-col>
  111 + <el-col :span="6">
  112 + <div class="form-group flex justify-start">
  113 + <label class="col-form-label">
  114 + {{ $t('workDetail.attachment') }}:
  115 + </label>
  116 + <div class="flex justify-start" v-if="workDetailInfo.pathUrls">
  117 + <div v-for="(url, index) in workDetailInfo.pathUrls" :key="index">
  118 + <div v-if="url.endsWith('jpg') || url.endsWith('png')">
  119 + <img style="width: 60px; height: 60px;" class="border-radius" :src="url"
  120 + @click="viewTaskFileImg(url)" />
  121 + </div>
  122 + <div v-else>
  123 + <a :href="url" target="_blank">{{ $t('common.download') }}</a>
  124 + </div>
  125 + </div>
  126 + </div>
  127 + </div>
  128 + </el-col>
  129 + </el-row>
  130 + </el-col>
  131 + </el-row>
  132 + </div>
  133 +
  134 + <divider></divider>
  135 +
  136 + <div class="margin-top-sm">
  137 + <el-tabs v-model="workDetailInfo._currentTab" @tab-click="changeTab(workDetailInfo._currentTab)">
  138 + <el-tab-pane :label="$t('workDetail.content')" name="workDetailContent"></el-tab-pane>
  139 + <el-tab-pane :label="$t('workDetail.handler')" name="workDetailTask"></el-tab-pane>
  140 + <el-tab-pane :label="$t('workDetail.handlerContent')" name="workDetailTaskItem"></el-tab-pane>
  141 + <el-tab-pane :label="$t('workDetail.copyPerson')" name="workDetailCopy"></el-tab-pane>
  142 + <el-tab-pane :label="$t('workDetail.workFlow')" name="workDetailEvent"></el-tab-pane>
  143 + <el-tab-pane :label="$t('workDetail.flowAttachment')" name="workDetailFile"></el-tab-pane>
  144 + <el-tab-pane :label="$t('workDetail.workType')" name="workDetailType"></el-tab-pane>
  145 + <el-tab-pane v-if="workDetailInfo.workCycle == '2002'" :label="$t('workDetail.workCycle')"
  146 + name="workDetailCycle"></el-tab-pane>
  147 + </el-tabs>
  148 + </div>
  149 +
  150 + <div v-if="workDetailInfo._currentTab == 'workDetailContent'">
  151 + <div class="padding flex justify-start" v-for="(item, index) in workDetailInfo.contents" :key="index">
  152 + <div>{{ item.seqNum }}、</div>
  153 + <div v-html="item.content" style="width: 80%;"></div>
  154 + </div>
  155 + </div>
  156 + <div v-if="workDetailInfo._currentTab == 'workDetailTask'">
  157 + <work-detail-task ref="workDetailTask"></work-detail-task>
  158 + </div>
  159 + <div v-if="workDetailInfo._currentTab == 'workDetailTaskItem'">
  160 + <work-detail-task-item ref="workDetailTaskItem"></work-detail-task-item>
  161 + </div>
  162 + <div v-if="workDetailInfo._currentTab == 'workDetailCopy'">
  163 + <work-detail-copy ref="workDetailCopy"></work-detail-copy>
  164 + </div>
  165 + <div v-if="workDetailInfo._currentTab == 'workDetailEvent'">
  166 + <work-detail-event ref="workDetailEvent"></work-detail-event>
  167 + </div>
  168 + <div v-if="workDetailInfo._currentTab == 'workDetailFile'">
  169 + <work-detail-file ref="workDetailFile"></work-detail-file>
  170 + </div>
  171 + <div v-if="workDetailInfo._currentTab == 'workDetailType'">
  172 + <work-detail-type ref="workDetailType"></work-detail-type>
  173 + </div>
  174 + <div v-if="workDetailInfo._currentTab == 'workDetailCycle'">
  175 + <work-detail-cycle ref="workDetailCycle"></work-detail-cycle>
  176 + </div>
  177 + </el-card>
  178 + </div>
  179 +</template>
  180 +
  181 +<script>
  182 +import { getWorkPoolDetail } from '@/api/oa/workDetailApi'
  183 +import WorkDetailTask from '@/components/oa/WorkDetailTask'
  184 +import WorkDetailTaskItem from '@/components/oa/WorkDetailTaskItem'
  185 +import WorkDetailCopy from '@/components/oa/WorkDetailCopy'
  186 +import WorkDetailEvent from '@/components/oa/WorkDetailEvent'
  187 +import WorkDetailFile from '@/components/oa/WorkDetailFile'
  188 +import WorkDetailType from '@/components/oa/WorkDetailType'
  189 +import WorkDetailCycle from '@/components/oa/WorkDetailCycle'
  190 +import Divider from '@/components/system/divider'
  191 +
  192 +export default {
  193 + name: 'WorkDetailList',
  194 + components: {
  195 + WorkDetailTask,
  196 + WorkDetailTaskItem,
  197 + WorkDetailCopy,
  198 + WorkDetailEvent,
  199 + WorkDetailFile,
  200 + WorkDetailType,
  201 + WorkDetailCycle,
  202 + Divider
  203 + },
  204 + data() {
  205 + return {
  206 + workDetailInfo: {
  207 + viewWorkFlag: '',
  208 + workId: "",
  209 + wtId: '',
  210 + workName: '',
  211 + typeName: "",
  212 + workCycle: "",
  213 + startTime: "",
  214 + endTime: "",
  215 + createUserName: "",
  216 + curStaffName: "",
  217 + curCopyName: "",
  218 + stateName: "",
  219 + createTime: '',
  220 + content: '',
  221 + pathUrls: [],
  222 + _currentTab: 'workDetailContent',
  223 + contents: []
  224 + }
  225 + }
  226 + },
  227 + created() {
  228 + this.workDetailInfo.workId = this.$route.query.workId
  229 + if (!this.workDetailInfo.workId) {
  230 + return
  231 + }
  232 + const currentTab = this.$route.query.currentTab
  233 + if (currentTab) {
  234 + this.workDetailInfo._currentTab = currentTab
  235 + }
  236 + this.loadWorkInfo()
  237 + this.changeTab(this.workDetailInfo._currentTab)
  238 + },
  239 + methods: {
  240 + async loadWorkInfo() {
  241 + try {
  242 + const params = {
  243 + workId: this.workDetailInfo.workId,
  244 + page: 1,
  245 + row: 1,
  246 + }
  247 + const { data } = await getWorkPoolDetail(params)
  248 + this.workDetailInfo = { ...this.workDetailInfo, ...data[0] }
  249 + } catch (error) {
  250 + console.error('获取工作单详情失败:', error)
  251 + }
  252 + },
  253 + changeTab(tab) {
  254 + this.workDetailInfo._currentTab = tab
  255 + setTimeout(() => {
  256 + if (this.$refs[tab]) {
  257 + this.$refs[tab].open({
  258 + taskId: this.workDetailInfo.taskId,
  259 + workId: this.workDetailInfo.workId,
  260 + wtId: this.workDetailInfo.wtId,
  261 + contents: this.workDetailInfo.contents
  262 + })
  263 + }
  264 + }, 500)
  265 + },
  266 + viewTaskFileImg(url) {
  267 + this.$emit('viewImage', { url })
  268 + },
  269 + goBack() {
  270 + this.$router.go(-1)
  271 + }
  272 + }
  273 +}
  274 +</script>
  275 +
  276 +<style lang="scss" scoped>
  277 +.work-detail-container {
  278 + padding: 20px;
  279 +
  280 + .box-card {
  281 + margin-bottom: 20px;
  282 + }
  283 +
  284 + .text-title {
  285 + font-size: 18px;
  286 + font-weight: bold;
  287 + }
  288 +
  289 + .margin-top {
  290 + margin-top: 20px;
  291 + }
  292 +
  293 + .margin-top-sm {
  294 + margin-top: 10px;
  295 + }
  296 +
  297 + .padding {
  298 + padding: 10px;
  299 + }
  300 +
  301 + .border-radius {
  302 + border-radius: 4px;
  303 + }
  304 +
  305 + .flex {
  306 + display: flex;
  307 + }
  308 +
  309 + .justify-between {
  310 + justify-content: space-between;
  311 + }
  312 +
  313 + .justify-start {
  314 + justify-content: flex-start;
  315 + }
  316 +
  317 + .form-group {
  318 + margin-bottom: 15px;
  319 +
  320 + .col-form-label {
  321 + display: inline-block;
  322 + margin-right: 10px;
  323 + }
  324 + }
  325 +}
  326 +</style>
0 327 \ No newline at end of file
... ...