完成制度管理模块页面搭建,包含发布流程等功能

This commit is contained in:
chabai 2025-07-30 10:21:02 +08:00
parent 1feb4832c5
commit 1dc321ba5c
7 changed files with 19 additions and 534 deletions

View File

@ -4,8 +4,8 @@ VITE_API_PREFIX = '/dev-api'
# 接口地址
# VITE_API_BASE_URL = 'http://pms.dtyx.net:9158/'
VITE_API_BASE_URL = 'http://localhost:8888/'
# VITE_API_BASE_URL = 'http://10.18.34.213:8888/'
# VITE_API_BASE_URL = 'http://localhost:8888/'
VITE_API_BASE_URL = 'http://10.18.34.213:8888/'
# 接口地址 (WebSocket)
VITE_API_WS_URL = 'ws://localhost:8000'

View File

@ -37,53 +37,22 @@ export const regulationApi = {
return http.del(`/regulation/proposal/${regulationId}`)
},
// 提交投票
submitVote: (regulationId: string, data: {
voteType: 'FOR' | 'AGAINST' | 'ABSTAIN'
reason?: string
}) => {
return http.post(`/regulation/${regulationId}/vote`, data)
},
// 获取投票结果
getVoteResult: (regulationId: string) => {
return http.get(`/regulation/${regulationId}/vote-result`)
},
// 发布制度
publishRegulation: (regulationId: string) => {
return http.post(`/regulation/${regulationId}/publish`)
},
// 获取讨论列表
getDiscussionList: (regulationId: string) => {
return http.get(`/regulation/${regulationId}/discussions`)
},
// 发表评论
addComment: (regulationId: string, data: {
content: string
}) => {
return http.post(`/regulation/${regulationId}/discussions`, data)
},
// 获取已发布制度列表
getPublishedRegulationList: (params: {
page: number
size: number
status: string
}) => {
return http.get('/regulation/published', params)
return http.get('/regulation', params)
},
// 确认制度知晓
confirmRegulation: (regulationId: string, data: {
agreeTerms: boolean
}) => {
return http.post(`/regulation/${regulationId}/confirm`, data)
},
// 批量确认制度
confirmAllRegulations: () => {
return http.post('/regulation/confirm-all')
confirmRegulation: (regulationId: string) => {
return http.post(`/regulation/${regulationId}/confirm`)
}
}

View File

@ -15,13 +15,6 @@ export enum RegulationLevel {
HIGH = 'HIGH' // 高
}
// 投票类型枚举
export enum VoteType {
FOR = 'FOR', // 赞成
AGAINST = 'AGAINST', // 反对
ABSTAIN = 'ABSTAIN' // 弃权
}
// 制度信息接口
export interface Regulation {
regulationId: string
@ -45,21 +38,6 @@ export interface Regulation {
page: number
pageSize: number
delFlag: string
requirements?: string
notes?: string
confirmStatus?: 'pending' | 'confirmed'
}
// 制度列表响应接口
export interface RegulationListResponse {
status: number
data: {
records: Regulation[]
total: number
size: number
current: number
pages: number
}
}
// 创建提案请求接口
@ -72,32 +50,6 @@ export interface CreateProposalRequest {
remark?: string
}
// 投票请求接口
export interface VoteRequest {
voteType: VoteType
reason?: string
}
// 投票结果接口
export interface VoteResult {
regulationId: string
voteFor: number
voteAgainst: number
voteAbstain: number
totalVotes: number
approvalRate: number
}
// 讨论评论接口
export interface Discussion {
id: string
regulationId: string
authorId: string
authorName: string
content: string
createTime: string
}
// 分页参数接口
export interface PaginationParams {
page: number

View File

@ -1,131 +0,0 @@
import { RegulationStatus, RegulationLevel } from '@/apis/regulation/type'
// Mock数据
export const mockRegulations = [
{
regulationId: 'reg001',
title: '员工考勤管理制度优化提案',
content: '建议优化考勤管理制度增加弹性工作时间提高员工工作积极性。具体包括1. 允许员工在合理范围内调整上下班时间2. 建立完善的请假制度3. 优化加班管理流程。',
regulationType: '人事制度',
status: RegulationStatus.VOTING,
publisherId: '1',
publisherName: '张三',
publishTime: '2024-01-01T12:00:00',
effectiveTime: '2024-01-01T12:00:00',
expireTime: '2024-01-08T12:00:00',
scope: '全体员工',
level: RegulationLevel.MEDIUM,
version: '1.0',
remark: '需要与人事部门协调实施',
createBy: 'admin',
updateBy: 'admin',
createTime: '2024-01-01 10:00:00',
updateTime: '2024-01-01 10:00:00',
page: 1,
pageSize: 10,
delFlag: '0',
voteFor: 15,
voteAgainst: 3,
voteAbstain: 2
},
{
regulationId: 'reg002',
title: '财务报销流程简化提案',
content: '建议简化财务报销流程提高工作效率。具体包括1. 优化审批流程减少不必要的审批环节2. 简化单据要求使用电子化单据3. 建立快速报销通道。',
regulationType: '财务制度',
status: RegulationStatus.PUBLISHED,
publisherId: '2',
publisherName: '李四',
publishTime: '2024-01-15T14:30:00',
effectiveTime: '2024-01-15T14:30:00',
expireTime: '2024-01-22T14:30:00',
scope: '财务部门及相关员工',
level: RegulationLevel.HIGH,
version: '1.0',
remark: '已获得财务部门支持',
createBy: 'admin',
updateBy: 'admin',
createTime: '2024-01-15 14:30:00',
updateTime: '2024-01-15 14:30:00',
page: 1,
pageSize: 10,
delFlag: '0',
voteFor: 20,
voteAgainst: 1,
voteAbstain: 0
},
{
regulationId: 'reg003',
title: '安全生产管理制度',
content: '建立完善的安全生产管理制度确保员工人身安全和设备安全。具体包括1. 制定详细的安全操作规程2. 建立安全培训制度3. 完善安全检查机制。',
regulationType: '安全制度',
status: RegulationStatus.DRAFT,
publisherId: '3',
publisherName: '王五',
publishTime: '2024-01-20T09:15:00',
effectiveTime: '2024-01-20T09:15:00',
expireTime: '2024-12-31T23:59:59',
scope: '所有工作场所和员工',
level: RegulationLevel.HIGH,
version: '1.0',
remark: '需要安全部门配合',
createBy: 'admin',
updateBy: 'admin',
createTime: '2024-01-20 09:15:00',
updateTime: '2024-01-20 09:15:00',
page: 1,
pageSize: 10,
delFlag: '0'
},
{
regulationId: 'reg004',
title: '设备维护制度',
content: '为保障设备正常运行延长设备使用寿命特制定本制度。具体包括1. 建立设备维护计划2. 制定维护标准3. 建立维护记录制度。',
regulationType: '设备制度',
status: RegulationStatus.ARCHIVED,
publisherId: '1',
publisherName: '管理员',
publishTime: '2024-01-01T12:00:00',
effectiveTime: '2024-01-01T12:00:00',
expireTime: '2024-12-31T23:59:59',
scope: '设备部门',
level: RegulationLevel.MEDIUM,
version: '1.0',
remark: '已归档',
createBy: 'admin',
updateBy: 'admin',
createTime: '2024-01-01 12:00:00',
updateTime: '2024-01-01 12:00:00',
page: 1,
pageSize: 10,
delFlag: '0'
}
]
// Mock讨论数据
export const mockDiscussions = [
{
id: '1',
regulationId: 'reg001',
authorId: '2',
authorName: '李四',
content: '这个提案很有建设性,建议增加一些具体的实施细则。',
createTime: '2024-01-01 11:00:00'
},
{
id: '2',
regulationId: 'reg001',
authorId: '3',
authorName: '王五',
content: '同意这个提案,但需要考虑实施成本。',
createTime: '2024-01-01 14:30:00'
},
{
id: '3',
regulationId: 'reg002',
authorId: '1',
authorName: '张三',
content: '简化流程确实能提高效率,支持这个提案。',
createTime: '2024-01-15 16:00:00'
}
]

View File

@ -70,6 +70,6 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@ -35,17 +35,6 @@
<a-button type="text" size="small" @click="handleView(record)">
查看详情
</a-button>
<a-button type="text" size="small" @click="handleDiscuss(record)">
讨论
</a-button>
<a-button
v-if="record.status === RegulationStatus.VOTING"
type="text"
size="small"
@click="handleVote(record)"
>
投票
</a-button>
<a-button
v-if="record.status === RegulationStatus.PUBLISHED"
type="text"
@ -145,73 +134,9 @@
</a-form>
</a-modal>
<!-- 讨论弹窗 -->
<a-modal
v-model:visible="discussModalVisible"
title="提案讨论"
width="800px"
:footer="false"
>
<div class="discussion-container" v-if="currentProposal">
<div class="proposal-info">
<h4>{{ currentProposal.title }}</h4>
<p>{{ currentProposal.content }}</p>
</div>
<a-divider />
<div class="discussion-list">
<div v-for="comment in discussionList" :key="comment.id" class="comment-item">
<div class="comment-header">
<span class="comment-author">{{ comment.authorName }}</span>
<span class="comment-time">{{ formatDate(comment.createTime) }}</span>
</div>
<div class="comment-content">{{ comment.content }}</div>
</div>
</div>
<div class="add-comment">
<a-textarea
v-model="newComment"
placeholder="请输入您的评论"
:rows="3"
/>
<a-button type="primary" style="margin-top: 8px;" @click="submitComment">
发表评论
</a-button>
</div>
</div>
</a-modal>
<!-- 投票弹窗 -->
<a-modal
v-model:visible="voteModalVisible"
title="提案投票"
width="600px"
@ok="submitVote"
@cancel="voteModalVisible = false"
>
<div class="vote-container" v-if="currentProposal">
<h4>{{ currentProposal.title }}</h4>
<p>{{ currentProposal.content }}</p>
<a-divider />
<h4>请选择您的投票</h4>
<a-radio-group v-model="voteChoice">
<a-radio :value="VoteType.FOR">赞成</a-radio>
<a-radio :value="VoteType.AGAINST">反对</a-radio>
<a-radio :value="VoteType.ABSTAIN">弃权</a-radio>
</a-radio-group>
<a-textarea
v-model="voteReason"
placeholder="请说明投票理由(可选)"
:rows="3"
style="margin-top: 16px;"
/>
</div>
</a-modal>
<!-- 提案详情弹窗 -->
<a-modal
@ -245,34 +170,7 @@
<a-divider />
<div class="vote-summary" v-if="currentProposal.status === RegulationStatus.VOTING || currentProposal.status === RegulationStatus.PUBLISHED || currentProposal.status === RegulationStatus.REJECTED">
<h4>投票结果</h4>
<div class="vote-stats">
<div class="vote-item">
<span class="vote-label">赞成:</span>
<span class="vote-count">{{ currentProposal.voteFor || 0 }}</span>
</div>
<div class="vote-item">
<span class="vote-label">反对:</span>
<span class="vote-count">{{ currentProposal.voteAgainst || 0 }}</span>
</div>
<div class="vote-item">
<span class="vote-label">弃权:</span>
<span class="vote-count">{{ currentProposal.voteAbstain || 0 }}</span>
</div>
</div>
</div>
<div class="detail-footer">
<a-button type="primary" @click="handleDiscuss(currentProposal)">
参与讨论
</a-button>
<a-button
v-if="currentProposal.status === RegulationStatus.VOTING"
@click="handleVote(currentProposal)"
>
参与投票
</a-button>
<a-button
v-if="currentProposal.status === RegulationStatus.PUBLISHED"
disabled
@ -293,10 +191,7 @@ import { regulationApi } from '@/apis/regulation'
import {
RegulationStatus,
RegulationLevel,
VoteType,
type Regulation,
type VoteResult,
type Discussion
type Regulation
} from '@/apis/regulation/type'
defineOptions({ name: 'ProcessManagement' })
@ -338,22 +233,13 @@ const formData = reactive({
remark: ''
})
//
const discussModalVisible = ref(false)
const currentProposal = ref<Regulation | null>(null)
const discussionList = ref<Discussion[]>([])
const newComment = ref('')
//
const voteModalVisible = ref(false)
const voteChoice = ref<VoteType | ''>('')
const voteReason = ref('')
//
const detailModalVisible = ref(false)
//
const currentUser = ref('1') // 使ID
// -
const currentUser = ref('') // TODO: ID
// store
const regulationStore = useRegulationStore()
@ -477,29 +363,7 @@ const handleView = (record: Regulation) => {
detailModalVisible.value = true
}
//
const handleDiscuss = async (record: Regulation) => {
currentProposal.value = record
discussModalVisible.value = true
try {
const response = await regulationApi.getDiscussionList(record.regulationId)
if (response.status === 200) {
discussionList.value = response.data
}
} catch (error) {
console.error('获取讨论列表失败:', error)
Message.error('获取讨论列表失败')
}
}
//
const handleVote = (record: Regulation) => {
currentProposal.value = record
voteModalVisible.value = true
voteChoice.value = ''
voteReason.value = ''
}
//
const handleDelete = async (record: Regulation) => {
@ -513,63 +377,7 @@ const handleDelete = async (record: Regulation) => {
}
}
//
const submitComment = async () => {
if (!newComment.value.trim()) {
Message.warning('请输入评论内容')
return
}
if (!currentProposal.value) {
Message.error('当前提案信息不存在')
return
}
try {
await regulationApi.addComment(currentProposal.value.regulationId, {
content: newComment.value
})
//
const response = await regulationApi.getDiscussionList(currentProposal.value.regulationId)
if (response.status === 200) {
discussionList.value = response.data
}
newComment.value = ''
Message.success('评论发表成功')
} catch (error) {
console.error('评论发表失败:', error)
Message.error('评论发表失败')
}
}
//
const submitVote = async () => {
if (!voteChoice.value) {
Message.warning('请选择投票选项')
return
}
if (!currentProposal.value) {
Message.error('当前提案信息不存在')
return
}
try {
await regulationApi.submitVote(currentProposal.value.regulationId, {
voteType: voteChoice.value,
reason: voteReason.value
})
Message.success('投票提交成功')
voteModalVisible.value = false
getTableData()
} catch (error) {
console.error('投票提交失败:', error)
Message.error('投票提交失败')
}
}
//
const handleSubmit = async () => {
@ -652,71 +460,7 @@ onMounted(() => {
}
}
.discussion-container {
.proposal-info {
margin-bottom: 16px;
h4 {
margin-bottom: 8px;
color: var(--color-text-1);
}
p {
color: var(--color-text-2);
line-height: 1.6;
}
}
.discussion-list {
max-height: 300px;
overflow-y: auto;
.comment-item {
margin-bottom: 16px;
padding: 12px;
background: var(--color-fill-1);
border-radius: 6px;
.comment-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
.comment-author {
font-weight: 500;
color: var(--color-text-1);
}
.comment-time {
color: var(--color-text-3);
font-size: 12px;
}
}
.comment-content {
color: var(--color-text-2);
line-height: 1.5;
}
}
}
.add-comment {
margin-top: 16px;
}
}
.vote-container {
h4 {
margin-bottom: 8px;
color: var(--color-text-1);
}
p {
color: var(--color-text-2);
line-height: 1.6;
margin-bottom: 16px;
}
}
.proposal-detail {
.detail-header {
@ -753,33 +497,7 @@ onMounted(() => {
}
}
.vote-summary {
h4 {
margin: 16px 0 8px 0;
color: var(--color-text-1);
font-weight: 500;
}
.vote-stats {
display: flex;
gap: 20px;
.vote-item {
display: flex;
align-items: center;
gap: 8px;
.vote-label {
color: var(--color-text-2);
}
.vote-count {
font-weight: 500;
color: var(--color-text-1);
}
}
}
}
.detail-footer {
display: flex;

View File

@ -1,14 +1,7 @@
<template>
<div class="system-regulation">
<a-card title="已发布制度确认" :bordered="false">
<template #extra>
<a-button type="primary" @click="handleConfirmAll">
<template #icon>
<icon-check />
</template>
一键确认全部
</a-button>
</template>
<a-table
:columns="columns"
@ -162,7 +155,8 @@ const getTableData = async () => {
try {
const response = await regulationApi.getPublishedRegulationList({
page: pagination.current,
size: pagination.pageSize
size: pagination.pageSize,
status: "PUBLISHED"
})
if (response.status === 200) {
@ -254,22 +248,7 @@ ${record.notes || '请严格遵守制度规定'}
}
}
//
const handleConfirmAll = async () => {
try {
await regulationApi.confirmAllRegulations()
//
tableData.value.forEach(item => {
item.confirmStatus = 'confirmed'
})
Message.success('已确认所有待确认的制度')
} catch (error) {
console.error('批量确认失败:', error)
Message.error('确认失败')
}
}
//
const submitConfirm = async () => {
@ -280,9 +259,7 @@ const submitConfirm = async () => {
try {
if (currentRegulation.value) {
await regulationApi.confirmRegulation(currentRegulation.value.regulationId, {
agreeTerms: agreeTerms.value
})
await regulationApi.confirmRegulation(currentRegulation.value.regulationId)
Message.success('确认成功,您已承诺遵守该制度')
confirmModalVisible.value = false