Pārlūkot izejas kodu

新增待审批详情抽屉

xlsea 1 gadu atpakaļ
vecāks
revīzija
eca28800de

+ 75 - 0
src/components/Flow/FlowNodeAvatar.vue

@@ -0,0 +1,75 @@
+<template>
+	<div class="avatar" :style="AvatarStyle">
+		<el-avatar v-if="user && user.avatar" :size="size" class="icon" :src="user.avatar" />
+		<el-avatar v-else :size="size" class="icon" :icon="UserFilled" />
+		<div v-if="showName && user && user.name" class="name" :style="NameStyle">{{ user.name }}</div>
+	</div>
+</template>
+
+<script setup>
+import { computed, ref, watch, onBeforeMount } from 'vue'
+import { UserFilled } from '@element-plus/icons-vue'
+
+const user = ref({})
+
+const props = defineProps({
+	size: { type: Number, default: 24 },
+	id: { type: String, default: '' },
+	showName: { type: Boolean, default: true }
+})
+
+watch(
+	() => props.id,
+	() => loadUserDetail()
+)
+
+const loadUserDetail = () => {
+	user.value = {
+		name: '艾斯'
+	}
+}
+
+const AvatarStyle = computed(() => {
+	const padding = props.showName ? 4 : 0
+	return {
+		height: props.size + padding * 2 + 'px',
+		borderRadius: (props.size + padding * 2) / 2 + 'px',
+		padding: padding + 'px'
+	}
+})
+
+const NameStyle = computed(() => {
+	return {
+		fontSize: props.size / 2 + 1 + 'px'
+	}
+})
+
+onBeforeMount(() => {
+	loadUserDetail()
+})
+</script>
+
+<style lang="scss" scoped>
+.avatar {
+	background: #f2f4f5;
+	display: flex;
+	align-items: center;
+	width: fit-content;
+
+	.icon {
+		overflow: hidden;
+		flex-shrink: 0;
+	}
+
+	.name {
+		user-select: none;
+		font-family: PingFangSC-Regular, PingFang SC;
+		color: #34383e;
+		margin: 0 4px;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		max-width: 64px;
+	}
+}
+</style>

+ 35 - 0
src/components/Flow/FlowStatusStamp.vue

@@ -0,0 +1,35 @@
+<template>
+	<div class="flow-stamp-container">
+		<img v-if="status == STATUS.APPROVED" :style="style" src="@/assets/images/flw03.svg" />
+		<img v-else-if="status == STATUS.REJECTED" :style="style" src="@/assets/images/flw04.svg" />
+		<img v-else-if="status == STATUS.UNDERWAY" :style="style" src="@/assets/images/flw01.svg" />
+		<img v-else-if="status == STATUS.CANCELLED" :style="style" src="@/assets/images/flw02.svg" />
+	</div>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue'
+import { STATUS } from './enums'
+
+const props = defineProps({
+	status: { type: Number, default: 0 },
+	size: { type: Number, default: 120 }
+})
+
+const style = computed(() => {
+	return {
+		width: props.size + 'px',
+		height: props.size + 'px'
+	}
+})
+</script>
+
+<style lang="scss" scoped>
+.flow-stamp-container {
+	img {
+		overflow: hidden;
+		background-color: transparent;
+		z-index: 999;
+	}
+}
+</style>

+ 22 - 0
src/components/Flow/FlowStatusTag.vue

@@ -0,0 +1,22 @@
+<template>
+	<div class="status">
+		<el-tag v-if="status == STATUS.APPROVED" :size="16" type="success">已通过</el-tag>
+		<el-tag v-else-if="status == STATUS.REJECTED" :size="16" type="danger">不通过</el-tag>
+		<el-tag v-else-if="status == STATUS.UNDERWAY" :size="16">审批中</el-tag>
+		<el-tag v-else-if="status == STATUS.CANCELLED" :size="16" type="warning">已撤销</el-tag>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { STATUS } from './enums'
+
+defineProps({
+	status: { type: Number, default: 0 }
+})
+</script>
+
+<style lang="scss" scoped>
+.status {
+	margin-left: 16px;
+}
+</style>

+ 11 - 0
src/components/Flow/enums.ts

@@ -0,0 +1,11 @@
+/** 流程状态 */
+export const enum STATUS {
+	/** 审批中 */
+	UNDERWAY,
+	/** 已通过 */
+	APPROVED,
+	/** 不通过 */
+	REJECTED,
+	/** 已撤销 */
+	CANCELLED
+}

+ 281 - 43
src/views/approve/pendingApproval/detail.vue

@@ -1,58 +1,167 @@
 <template>
-	<el-dialog class="le-dialog" v-model="visibleDialog" title="查看详情" @close="handleCancel">
-		<div>
-			<!--title-->
-			<div>
-				<div class="content-title">{{ formOptions.title }}</div>
-				<span>发布人:{{ formOptions.createBy }} 发布时间: {{ formOptions.createTime }}</span>
-
-				<div class="content-title mbt20">
-					<el-tag v-if="formOptions.category === 0" size="small" effect="plain">通知公告</el-tag>
-					<el-tag v-if="formOptions.category === 1" size="small" type="info" effect="plain">系统消息</el-tag>
-					<el-tag v-if="formOptions.category === 2" size="small" type="warning" effect="plain">待办通知</el-tag>
+	<div>
+		<el-drawer v-model="visibleDialog" class="custom-adrawer" :direction="direction" size="900" @close="handleCancel">
+			<template #header>
+				<div class="flow-header-box">
+					<div class="flow-no">编号:12138</div>
+				</div>
+			</template>
+			<div class="flow-detail-container">
+				<div class="flow-status-stamp">
+					<FlowStatusStamp :status="0" />
+				</div>
+
+				<div class="flow-detail-box">
+					<!--头部-->
+					<div class="header-box">
+						<div class="summary-info">
+							<div class="title">名片申请</div>
+							<FlowStatusTag :status="0" />
+						</div>
+						<div class="initiator-info">
+							<FlowNodeAvatar id="1" />
+							<div class="begin-time">2023-11-01 12:00:17 提交</div>
+						</div>
+					</div>
+					<div class="area-divider"></div>
+
+					<!-- 表单 -->
+					<el-descriptions :column="1" size="default">
+						<el-descriptions-item label="申请人">kooriookami</el-descriptions-item>
+						<el-descriptions-item label="日期">18100000000</el-descriptions-item>
+						<el-descriptions-item label="员工">Suzhou</el-descriptions-item>
+					</el-descriptions>
+
+					<div class="area-divider"></div>
+
+					<!--审批流-->
+					<el-timeline style="margin-left: 10px">
+						<el-timeline-item timestamp="提交" placement="top" type="success" :icon="Check">
+							<!-- 审批完成 -->
+							<div class="timeline-box flex-1">
+								<div class="flex flex-align-center">
+									<div class="timeline-box-user flex-1">
+										<FlowNodeAvatar id="1" />
+										<div v-if="false" class="comment">
+											<div class="comment-content">同意</div>
+										</div>
+									</div>
+									<span class="timeline-box-date">2018-4-12 20:46:00</span>
+								</div>
+							</div>
+						</el-timeline-item>
+
+						<el-timeline-item timestamp="审批" placement="top" type="success" :icon="Check">
+							<div class="timeline-box flex-1">
+								<div class="flex flex-align-center">
+									<div class="timeline-box-user flex-1">
+										<FlowNodeAvatar id="1" />
+										<div class="comment">
+											<div class="comment-content">同意</div>
+										</div>
+									</div>
+									<span class="timeline-box-date">2018-4-12 20:46:12</span>
+								</div>
+							</div>
+						</el-timeline-item>
+
+						<el-timeline-item timestamp="抄送" placement="top" type="success" :icon="Check">
+							<div class="timeline-box flex-1">
+								<div class="flex flex-align-center">
+									<el-space wrap>
+										<FlowNodeAvatar id="1" />
+										<FlowNodeAvatar id="1" />
+										<FlowNodeAvatar id="1" />
+									</el-space>
+
+									<span class="timeline-box-date">2018-4-12 20:46:32</span>
+								</div>
+							</div>
+						</el-timeline-item>
+					</el-timeline>
 				</div>
-				<span>通知时间: - </span>
-				<br />
-				<br />
-				<span>通知内容:{{ formOptions.content }}</span>
 			</div>
-			<!--content-->
-		</div>
-	</el-dialog>
+
+			<template #footer>
+				<div class="flow-actions">
+					<el-button :icon="ChatLineSquare" @click="openComment">评论</el-button>
+					<el-button :icon="Check" type="success">同意</el-button>
+					<el-button :icon="Close" type="danger">拒绝</el-button>
+					<el-dropdown style="margin-left: 12px">
+						<el-button :icon="More">更多</el-button>
+						<template #dropdown>
+							<el-dropdown-menu>
+								<el-dropdown-item>
+									<el-icon><DArrowLeft /></el-icon>
+									转交
+								</el-dropdown-item>
+								<el-dropdown-item>
+									<el-icon><Switch /></el-icon>
+									回退
+								</el-dropdown-item>
+								<el-dropdown-item>
+									<el-icon><Plus /></el-icon>
+									加签
+								</el-dropdown-item>
+								<el-dropdown-item>
+									<el-icon><Minus /></el-icon>
+									减签
+								</el-dropdown-item>
+							</el-dropdown-menu>
+						</template>
+					</el-dropdown>
+				</div>
+			</template>
+
+			<LeFormConfigDialog
+				v-if="visible"
+				ref="dialogCommentRef"
+				v-model="visible"
+				title="评论审批"
+				width="600px"
+				:form-data="activeData"
+				:form-options="formOptions"
+				@submit="submitHandler"
+			/>
+		</el-drawer>
+	</div>
 </template>
 
 <script setup>
 import { computed, ref } from 'vue'
-import message from '@/api/system/message'
-
-// 同步值
-const $myEmit = defineEmits(['update:modelValue'])
+import FlowStatusStamp from '@/components/Flow/FlowStatusStamp.vue'
+import FlowStatusTag from '@/components/Flow/FlowStatusTag.vue'
+import FlowNodeAvatar from '@/components/Flow/FlowNodeAvatar.vue'
+import { ChatLineSquare, Check, Close, Switch, DArrowLeft, Plus, Minus, More } from '@element-plus/icons-vue'
 
+const direction = ref('rtl')
 const myProps = defineProps({
 	modelValue: {
 		type: Boolean,
 		default: false
 	},
-	messageId: {
-		type: String,
-		default: null
+	userIds: {
+		type: Array,
+		default: () => []
 	}
 })
 
-const formOptions = ref({})
-const handleCancel = () => {
+const visible = ref(false) // 弹窗显示隐藏
+const activeData = ref({})
+
+// 同步值
+const $myEmit = defineEmits(['update:modelValue', 'successFn'])
+
+// 关闭按钮
+const closeDrawer = () => {
+	$myEmit('successFn')
 	$myEmit('update:modelValue', false)
 }
 
-const getMessageInfoDetail = async () => {
-	const { messageId } = myProps
-	const res = await message.getMessageInfoById(messageId)
-	formOptions.value = res
+const handleCancel = () => {
+	closeDrawer()
 }
 
-getMessageInfoDetail()
-
-// computed
 const visibleDialog = computed({
 	get() {
 		return myProps.modelValue
@@ -61,19 +170,148 @@ const visibleDialog = computed({
 		$myEmit('update:modelValue', val)
 	}
 })
+
+const formsDialog = [
+	{
+		prop: 'username',
+		label: '评论',
+		itemType: 'input',
+		placeholder: '请输入评论',
+		rules: [{ required: true, message: '请输入评论', trigger: 'blur' }]
+	}
+]
+
+const formOptions = computed(() => {
+	return {
+		forms: formsDialog,
+		labelWidth: 120,
+		span: 30,
+		formConfig: {
+			showCancelBtn: true,
+			submitLoading: false
+		}
+	}
+})
+
+const submitHandler = () => {}
+
+const openComment = () => {
+	visible.value = !visible.value
+}
 </script>
 
 <style scoped lang="scss">
-.content-title {
+::v-deep .el-drawer__header {
+	padding: 0px;
+	margin-bottom: 0 !important;
+}
+
+::v-deep .el-drawer__footer {
+	padding-top: 20px;
+	border-top: 1px solid rgba(229, 230, 235, 1);
+}
+
+.flow-detail-container {
+	height: 100%;
+}
+
+.flow-status-stamp {
+	position: absolute;
+	right: 50px;
+	top: 30px;
+}
+
+.flow-header-box {
+	font-weight: 400;
+	font-size: 14px;
+	border-bottom: 1px solid #e5e6ec;
+	padding: 0 16px;
+	height: 39px;
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	color: #86909c;
+}
+.flow-detail-box {
+	height: calc(100% - 92px);
 	overflow: hidden;
-	color: #000000d9;
-	font-weight: 500;
-	font-size: 16px;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	margin-bottom: 20px;
-	&.mbt20 {
-		margin-top: 20px;
+	overflow-y: auto;
+	padding: 0 20px;
+	.header-box {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		// padding-top: 20px;
+		.summary-info {
+			display: flex;
+			align-items: center;
+			.title {
+				font-size: 24px;
+				font-family: PingFangSC-Semibold, PingFang SC;
+				color: #1d2129;
+			}
+		}
+		.initiator-info {
+			display: flex;
+			align-items: center;
+			margin-top: 16px;
+			.begin-time {
+				margin-left: 16px;
+				font-weight: 350;
+				color: #86909c;
+				font-size: 13px;
+				-webkit-user-select: none;
+				user-select: none;
+			}
+		}
+	}
+	.area-divider {
+		border-bottom: 1px solid rgba(229, 230, 235, 1);
+		margin: 20px 0;
+		position: relative;
+	}
+}
+
+.flow-actions {
+	display: flex;
+	align-items: center;
+	justify-content: flex-end;
+}
+
+// 时间线样式
+.timeline-box {
+	&-user {
+		.name {
+			color: #1d2129;
+			font-weight: 400;
+		}
+		.comment {
+			width: 100%;
+			-webkit-user-select: none;
+			user-select: none;
+			margin: 4px 0 16px;
+			padding: 8px 16px;
+			border-radius: 4px;
+			background-color: #f8f8fa;
+			.comment-content {
+				font-weight: 500;
+				color: #1d2129;
+			}
+		}
+	}
+	&-date {
+		margin-left: 10px;
+		left: 0;
+		padding-right: 16px;
+		text-align: right;
+		transform: translate(-100%);
+		position: absolute;
+		top: 0;
+		box-sizing: border-box;
+		max-width: 100px;
+		color: #86909c;
+		font-size: 12px;
+		line-height: 1.667;
 	}
 }
 </style>