|
|
@@ -0,0 +1,234 @@
|
|
|
+<template>
|
|
|
+ <div class="expert-step-table">
|
|
|
+ <div class="table-title">专家梯队示例</div>
|
|
|
+
|
|
|
+ <div class="table-list">
|
|
|
+ <table
|
|
|
+ v-for="row in tableData"
|
|
|
+ :key="row.teamName"
|
|
|
+ class="ladder-row-table"
|
|
|
+ :style="{ width: row.tableWidth }"
|
|
|
+ >
|
|
|
+ <colgroup>
|
|
|
+ <col :style="{ width: row.teamWidth }" />
|
|
|
+ <col
|
|
|
+ v-for="(_, index) in row.columnWidths"
|
|
|
+ :key="index"
|
|
|
+ :style="{ width: `${getColumnPercent(row, index)}%` }"
|
|
|
+ />
|
|
|
+ </colgroup>
|
|
|
+
|
|
|
+ <tbody>
|
|
|
+ <tr>
|
|
|
+ <td class="team-cell">{{ row.teamName }}</td>
|
|
|
+
|
|
|
+ <td v-for="(cell, index) in row.cells" :key="index" class="step-cell">
|
|
|
+ <template v-if="cell.type === 'members'">
|
|
|
+ <button
|
|
|
+ v-for="member in cell.members"
|
|
|
+ :key="member"
|
|
|
+ type="button"
|
|
|
+ class="member-link"
|
|
|
+ @click="handleMemberClick(member)"
|
|
|
+ >
|
|
|
+ {{ member }}
|
|
|
+ </button>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <span v-else :class="['cell-text', cell.tone === 'danger' ? 'is-danger' : '']">
|
|
|
+ {{ cell.text }}
|
|
|
+ </span>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="selectedMember" class="member-detail"> 当前查看人员:{{ selectedMember }} </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref } from 'vue'
|
|
|
+
|
|
|
+type CellItem =
|
|
|
+ | {
|
|
|
+ type: 'members'
|
|
|
+ members: string[]
|
|
|
+ }
|
|
|
+ | {
|
|
|
+ type: 'text'
|
|
|
+ text: string
|
|
|
+ tone?: 'normal' | 'danger'
|
|
|
+ }
|
|
|
+
|
|
|
+type TableRow = {
|
|
|
+ teamName: string
|
|
|
+ tableWidth: string
|
|
|
+ teamWidth: string
|
|
|
+ columnWidths: number[]
|
|
|
+ cells: CellItem[]
|
|
|
+}
|
|
|
+
|
|
|
+const tableData: TableRow[] = [
|
|
|
+ {
|
|
|
+ teamName: '第一梯队',
|
|
|
+ tableWidth: '64%',
|
|
|
+ teamWidth: '90px',
|
|
|
+ columnWidths: [1, 1, 1, 1, 1],
|
|
|
+ cells: [
|
|
|
+ { type: 'members', members: ['朱桂林', '孙乐臻', '王军', '钟国伟', '李伟伟', '张伟伟'] },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+
|
|
|
+ { type: 'text', text: '' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ teamName: '第二梯队',
|
|
|
+ tableWidth: '75%',
|
|
|
+ teamWidth: '90px',
|
|
|
+ columnWidths: [1.5, 1.5, 1.5, 1.5, 1.5],
|
|
|
+ cells: [
|
|
|
+ { type: 'members', members: ['朱桂林', '孙乐臻', '王军', '钟国伟', '李伟伟', '张伟伟'] },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ teamName: '第三梯队',
|
|
|
+ tableWidth: '100%',
|
|
|
+ teamWidth: '90px',
|
|
|
+ columnWidths: [1.8, 1.8, 1.8, 1.8, 1.8],
|
|
|
+ cells: [
|
|
|
+ {
|
|
|
+ type: 'members',
|
|
|
+ members: [
|
|
|
+ '朱桂林',
|
|
|
+ '孙乐臻',
|
|
|
+ '王军',
|
|
|
+ '钟国伟',
|
|
|
+ '李伟伟',
|
|
|
+ '张伟伟',
|
|
|
+ '张三',
|
|
|
+ '李四',
|
|
|
+ '王五',
|
|
|
+ '赵六',
|
|
|
+ '钱七',
|
|
|
+ '孙八',
|
|
|
+ '周九',
|
|
|
+ '吴十'
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' },
|
|
|
+ { type: 'text', text: '' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const selectedMember = ref('')
|
|
|
+
|
|
|
+const getColumnPercent = (row: TableRow, index: number) => {
|
|
|
+ const total = row.columnWidths.reduce((sum, width) => sum + width, 0)
|
|
|
+
|
|
|
+ return ((row.columnWidths[index] / total) * 100).toFixed(4)
|
|
|
+}
|
|
|
+
|
|
|
+const handleMemberClick = (member: string) => {
|
|
|
+ selectedMember.value = member
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.expert-step-table {
|
|
|
+ width: 100%;
|
|
|
+ padding: 24px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.table-title {
|
|
|
+ margin-bottom: 16px;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+}
|
|
|
+
|
|
|
+.table-list {
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.ladder-row-table {
|
|
|
+ max-width: 100%;
|
|
|
+ margin: 0;
|
|
|
+ table-layout: fixed;
|
|
|
+ border-collapse: collapse;
|
|
|
+ border-spacing: 0;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.ladder-row-table + .ladder-row-table {
|
|
|
+ border-top: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.ladder-row-table td {
|
|
|
+ height: 78px;
|
|
|
+ padding: 12px;
|
|
|
+ border: 1px solid #303030;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.team-cell {
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 600;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.step-cell {
|
|
|
+ text-align: center;
|
|
|
+ vertical-align: middle;
|
|
|
+ overflow-wrap: anywhere;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.member-link {
|
|
|
+ display: inline;
|
|
|
+ margin: 0 3px;
|
|
|
+ padding: 0;
|
|
|
+ border: 0;
|
|
|
+ background: transparent;
|
|
|
+ color: #409eff;
|
|
|
+ cursor: pointer;
|
|
|
+ font: inherit;
|
|
|
+ line-height: 1.8;
|
|
|
+}
|
|
|
+
|
|
|
+.member-link:hover {
|
|
|
+ color: #66b1ff;
|
|
|
+ text-decoration: underline;
|
|
|
+}
|
|
|
+
|
|
|
+.cell-text {
|
|
|
+ color: #303133;
|
|
|
+ line-height: 1.7;
|
|
|
+}
|
|
|
+
|
|
|
+.is-danger {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.member-detail {
|
|
|
+ display: inline-block;
|
|
|
+ margin-top: 16px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ background: #fff;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+</style>
|