|
@@ -1,29 +1,9 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="personnel-config-container">
|
|
<div class="personnel-config-container">
|
|
|
- <!-- 操作按钮区域 -->
|
|
|
|
|
- <div class="action-section">
|
|
|
|
|
- <el-button v-if="!hasTitle" type="primary" @click="handleCreateTitle"> 创建标题 </el-button>
|
|
|
|
|
- <el-button type="primary" @click="openCreateDialog"> 创建人员 </el-button>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 表格区域 -->
|
|
|
|
|
|
|
+ <!-- 表格区域:工具栏在表格上方左侧 -->
|
|
|
<div class="table-box button-table">
|
|
<div class="table-box button-table">
|
|
|
- <div class="table-header-title">
|
|
|
|
|
- <span class="table-title">演出人员</span>
|
|
|
|
|
- <el-dropdown v-if="hasTitle" trigger="click" @command="handleTitleCommand">
|
|
|
|
|
- <el-icon class="table-icon">
|
|
|
|
|
- <ArrowDown />
|
|
|
|
|
- </el-icon>
|
|
|
|
|
- <template #dropdown>
|
|
|
|
|
- <el-dropdown-menu>
|
|
|
|
|
- <el-dropdown-item command="edit"> 编辑标题 </el-dropdown-item>
|
|
|
|
|
- <el-dropdown-item command="delete"> 删除标题 </el-dropdown-item>
|
|
|
|
|
- </el-dropdown-menu>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-dropdown>
|
|
|
|
|
- <el-icon v-else class="table-icon">
|
|
|
|
|
- <ArrowDown />
|
|
|
|
|
- </el-icon>
|
|
|
|
|
|
|
+ <div class="personnel-table-toolbar">
|
|
|
|
|
+ <el-button type="primary"> 人员 </el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<ProTable
|
|
<ProTable
|
|
|
ref="proTable"
|
|
ref="proTable"
|
|
@@ -32,6 +12,11 @@
|
|
|
:init-param="initParam"
|
|
:init-param="initParam"
|
|
|
:data-callback="dataCallback"
|
|
:data-callback="dataCallback"
|
|
|
>
|
|
>
|
|
|
|
|
+ <template #tableHeader>
|
|
|
|
|
+ <div class="personnel-table-header-actions">
|
|
|
|
|
+ <el-button type="primary" @click="openCreateDialog"> 新增人员 </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
<template #empty>
|
|
<template #empty>
|
|
|
<div class="personnel-config-empty">暂无数据</div>
|
|
<div class="personnel-config-empty">暂无数据</div>
|
|
|
</template>
|
|
</template>
|
|
@@ -44,7 +29,7 @@
|
|
|
<!-- 已驳回(status === 2):显示编辑、删除、查看详情 -->
|
|
<!-- 已驳回(status === 2):显示编辑、删除、查看详情 -->
|
|
|
<template v-else-if="scope.row.status === 2 || scope.row.status === '2'">
|
|
<template v-else-if="scope.row.status === 2 || scope.row.status === '2'">
|
|
|
<el-button type="primary" link @click="editPersonnel(scope.row, 0)"> 编辑 </el-button>
|
|
<el-button type="primary" link @click="editPersonnel(scope.row, 0)"> 编辑 </el-button>
|
|
|
- <el-button type="primary" link @click="deletePersonnelHandler(scope.row.id!, 0)"> 删除 </el-button>
|
|
|
|
|
|
|
+ <el-button type="danger" link @click="deletePersonnelHandler(scope.row.id!, 0)"> 删除 </el-button>
|
|
|
<el-button type="primary" link @click="handleViewDetail(scope.row)"> 查看详情 </el-button>
|
|
<el-button type="primary" link @click="handleViewDetail(scope.row)"> 查看详情 </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -76,7 +61,7 @@
|
|
|
取消置顶
|
|
取消置顶
|
|
|
</el-button>
|
|
</el-button>
|
|
|
<el-button v-else type="primary" link @click="handlePin(scope.row)"> 置顶 </el-button>
|
|
<el-button v-else type="primary" link @click="handlePin(scope.row)"> 置顶 </el-button>
|
|
|
- <el-button type="primary" link @click="deletePersonnelHandler(scope.row.id!, 0)"> 删除 </el-button>
|
|
|
|
|
|
|
+ <el-button type="danger" link @click="deletePersonnelHandler(scope.row.id!, 0)"> 删除 </el-button>
|
|
|
<el-button type="primary" link @click="handleViewDetail(scope.row)"> 查看详情 </el-button>
|
|
<el-button type="primary" link @click="handleViewDetail(scope.row)"> 查看详情 </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -110,7 +95,13 @@
|
|
|
<div class="detail-item">
|
|
<div class="detail-item">
|
|
|
<div class="detail-label">头像:</div>
|
|
<div class="detail-label">头像:</div>
|
|
|
<div class="detail-value">
|
|
<div class="detail-value">
|
|
|
- <img v-if="personnelDetail.staffImage" :src="personnelDetail.staffImage" alt="头像" class="detail-avatar" />
|
|
|
|
|
|
|
+ <img
|
|
|
|
|
+ v-if="personnelDetail.staffImage"
|
|
|
|
|
+ :src="personnelDetail.staffImage"
|
|
|
|
|
+ alt="头像"
|
|
|
|
|
+ class="detail-avatar"
|
|
|
|
|
+ @click="previewBackgroundImage(personnelDetail.staffImage)"
|
|
|
|
|
+ />
|
|
|
<span v-else>—</span>
|
|
<span v-else>—</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -174,18 +165,44 @@
|
|
|
<div class="detail-item">
|
|
<div class="detail-item">
|
|
|
<div class="detail-label">在线状态:</div>
|
|
<div class="detail-label">在线状态:</div>
|
|
|
<div class="detail-value">
|
|
<div class="detail-value">
|
|
|
- <span v-if="personnelDetail.onlineStatus === 0 || personnelDetail.onlineStatus === '0'">上线</span>
|
|
|
|
|
- <span v-else-if="personnelDetail.onlineStatus === 1 || personnelDetail.onlineStatus === '1'">下线</span>
|
|
|
|
|
- <span v-else>—</span>
|
|
|
|
|
|
|
+ <template
|
|
|
|
|
+ v-if="
|
|
|
|
|
+ personnelDetail.status === 0 ||
|
|
|
|
|
+ personnelDetail.status === '0' ||
|
|
|
|
|
+ personnelDetail.status === 2 ||
|
|
|
|
|
+ personnelDetail.status === '2'
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="personnel-cell-dash">—</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <span
|
|
|
|
|
+ v-if="personnelDetail.onlineStatus === 1 || personnelDetail.onlineStatus === '1'"
|
|
|
|
|
+ class="personnel-cell-dash"
|
|
|
|
|
+ >—</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span
|
|
|
|
|
+ v-else-if="personnelDetail.onlineStatus === 0 || personnelDetail.onlineStatus === '0'"
|
|
|
|
|
+ class="personnel-cell-online-up"
|
|
|
|
|
+ >在线</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span v-else class="personnel-cell-dash">—</span>
|
|
|
|
|
+ </template>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="detail-item">
|
|
<div class="detail-item">
|
|
|
<div class="detail-label">审核状态:</div>
|
|
<div class="detail-label">审核状态:</div>
|
|
|
<div class="detail-value">
|
|
<div class="detail-value">
|
|
|
- <el-tag v-if="personnelDetail.status === 1 || personnelDetail.status === '1'" type="success"> 已通过 </el-tag>
|
|
|
|
|
- <el-tag v-else-if="personnelDetail.status === 2 || personnelDetail.status === '2'" type="danger"> 已驳回 </el-tag>
|
|
|
|
|
- <el-tag v-else-if="personnelDetail.status === 0 || personnelDetail.status === '0'" type="info"> 待审核 </el-tag>
|
|
|
|
|
- <span v-else>—</span>
|
|
|
|
|
|
|
+ <span v-if="personnelDetail.status === 1 || personnelDetail.status === '1'" class="personnel-cell-pass"
|
|
|
|
|
+ >已通过</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span v-else-if="personnelDetail.status === 2 || personnelDetail.status === '2'" class="personnel-cell-reject"
|
|
|
|
|
+ >已驳回</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span v-else-if="personnelDetail.status === 0 || personnelDetail.status === '0'" class="personnel-cell-pending"
|
|
|
|
|
+ >待审核</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span v-else class="personnel-cell-dash">—</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div v-if="personnelDetail.status === 2 || personnelDetail.status === '2'" class="detail-item">
|
|
<div v-if="personnelDetail.status === 2 || personnelDetail.status === '2'" class="detail-item">
|
|
@@ -217,22 +234,19 @@
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
|
|
|
<!-- 背景图片预览弹窗 -->
|
|
<!-- 背景图片预览弹窗 -->
|
|
|
- <el-image-viewer v-if="previewImageVisible" :url-list="[previewImageUrl]" @close="previewImageVisible = false" />
|
|
|
|
|
|
|
+ <PcImagePreviewViewer
|
|
|
|
|
+ v-model:visible="previewImageVisible"
|
|
|
|
|
+ :url-list="previewImageUrl ? [previewImageUrl] : []"
|
|
|
|
|
+ :initial-index="0"
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
- <!-- 背景视频放大预览弹窗 -->
|
|
|
|
|
- <el-dialog
|
|
|
|
|
|
|
+ <PcVideoPreviewDialog
|
|
|
v-model="previewVideoVisible"
|
|
v-model="previewVideoVisible"
|
|
|
|
|
+ :src="previewVideoUrl"
|
|
|
title="视频预览"
|
|
title="视频预览"
|
|
|
- width="70%"
|
|
|
|
|
- top="5vh"
|
|
|
|
|
- destroy-on-close
|
|
|
|
|
- align-center
|
|
|
|
|
- @close="previewVideoUrl = ''"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="video-preview-wrap">
|
|
|
|
|
- <video v-if="previewVideoUrl" :src="previewVideoUrl" controls autoplay class="video-preview-player" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-dialog>
|
|
|
|
|
|
|
+ :autoplay="true"
|
|
|
|
|
+ @closed="previewVideoUrl = ''"
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
<!-- 新建/编辑人员弹窗 -->
|
|
<!-- 新建/编辑人员弹窗 -->
|
|
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="720px" @close="resetForm">
|
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="720px" @close="resetForm">
|
|
@@ -252,7 +266,9 @@
|
|
|
<el-input v-model="formData.name" placeholder="请输入" maxlength="20" show-word-limit clearable />
|
|
<el-input v-model="formData.name" placeholder="请输入" maxlength="20" show-word-limit clearable />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item label="人员职位*" prop="position">
|
|
<el-form-item label="人员职位*" prop="position">
|
|
|
- <el-input v-model="formData.position" placeholder="请输入" maxlength="50" clearable />
|
|
|
|
|
|
|
+ <el-select v-model="formData.position" placeholder="请选择" filterable clearable style="width: 100%">
|
|
|
|
|
+ <el-option v-for="opt in staffPositionOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
|
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item label="背景*" prop="backgroundImages">
|
|
<el-form-item label="背景*" prop="backgroundImages">
|
|
|
<div class="background-upload-three-col">
|
|
<div class="background-upload-three-col">
|
|
@@ -325,7 +341,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, computed, onMounted, watch, nextTick } from "vue";
|
|
|
|
|
|
|
+import { ref, reactive, computed, onMounted, watch, nextTick, h } from "vue";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
import type { FormInstance, FormRules } from "element-plus";
|
|
import type { FormInstance, FormRules } from "element-plus";
|
|
|
import { Picture, Plus, Delete, ArrowDown, VideoPlay } from "@element-plus/icons-vue";
|
|
import { Picture, Plus, Delete, ArrowDown, VideoPlay } from "@element-plus/icons-vue";
|
|
@@ -336,6 +352,8 @@ import UploadImgs from "@/components/Upload/Imgs.vue";
|
|
|
import { uploadFileToOss, uploadFilesToOss } from "@/api/upload.js";
|
|
import { uploadFileToOss, uploadFilesToOss } from "@/api/upload.js";
|
|
|
import type { UploadUserFile } from "element-plus";
|
|
import type { UploadUserFile } from "element-plus";
|
|
|
import { localGet } from "@/utils";
|
|
import { localGet } from "@/utils";
|
|
|
|
|
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
|
|
|
|
|
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
|
|
|
import {
|
|
import {
|
|
|
getPersonnelList,
|
|
getPersonnelList,
|
|
|
getStaffConfigList,
|
|
getStaffConfigList,
|
|
@@ -348,7 +366,8 @@ import {
|
|
|
getTitleDetail,
|
|
getTitleDetail,
|
|
|
deleteTitle,
|
|
deleteTitle,
|
|
|
setTopStatus,
|
|
setTopStatus,
|
|
|
- setOnlineStatus
|
|
|
|
|
|
|
+ setOnlineStatus,
|
|
|
|
|
+ queryStaffTitle
|
|
|
} from "@/api/modules/storeDecoration";
|
|
} from "@/api/modules/storeDecoration";
|
|
|
|
|
|
|
|
// 人员接口
|
|
// 人员接口
|
|
@@ -403,10 +422,10 @@ const titleRules = reactive<FormRules>({
|
|
|
// 标题弹窗标题
|
|
// 标题弹窗标题
|
|
|
const titleDialogTitle = computed(() => (titleEditId.value !== null ? "修改标题" : "创建标题"));
|
|
const titleDialogTitle = computed(() => (titleEditId.value !== null ? "修改标题" : "创建标题"));
|
|
|
|
|
|
|
|
-// 在线状态枚举 - 0: 上线, 1: 下线
|
|
|
|
|
|
|
+// 在线状态枚举 - 0: 在线, 1: 离线(列表展示为「—」)
|
|
|
const onlineStatusEnum = [
|
|
const onlineStatusEnum = [
|
|
|
- { label: "上线", value: 0 },
|
|
|
|
|
- { label: "下线", value: 1 }
|
|
|
|
|
|
|
+ { label: "在线", value: 0 },
|
|
|
|
|
+ { label: "离线", value: 1 }
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
// 审核状态枚举
|
|
// 审核状态枚举
|
|
@@ -433,6 +452,29 @@ const formatTime = (time: string | null | undefined) => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+/** ProTable「职位」筛选项:GET alienStore/storeStaffTitle/query?storeId= */
|
|
|
|
|
+async function fetchPositionSearchEnum() {
|
|
|
|
|
+ const storeId = localGet("geeker-user")?.userInfo?.storeId || localGet("createdId");
|
|
|
|
|
+ if (!storeId) return { data: [] as { label: string; value: string }[] };
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res: any = await queryStaffTitle({ storeId });
|
|
|
|
|
+ const inner = res?.data;
|
|
|
|
|
+ const raw = Array.isArray(inner) ? inner : (inner?.records ?? inner?.list ?? []);
|
|
|
|
|
+ const arr = Array.isArray(raw) ? raw : [];
|
|
|
|
|
+ const seen = new Set<string>();
|
|
|
|
|
+ const list: { label: string; value: string }[] = [];
|
|
|
|
|
+ for (const item of arr) {
|
|
|
|
|
+ const title = String(item.titleName ?? item.name ?? item.positionName ?? "").trim();
|
|
|
|
|
+ if (!title || seen.has(title)) continue;
|
|
|
|
|
+ seen.add(title);
|
|
|
|
|
+ list.push({ label: title, value: title });
|
|
|
|
|
+ }
|
|
|
|
|
+ return { data: list };
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return { data: [] };
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 表格配置项
|
|
// 表格配置项
|
|
|
const columns = reactive<ColumnProps<any>[]>([
|
|
const columns = reactive<ColumnProps<any>[]>([
|
|
|
{
|
|
{
|
|
@@ -457,9 +499,11 @@ const columns = reactive<ColumnProps<any>[]>([
|
|
|
prop: "position",
|
|
prop: "position",
|
|
|
label: "职位",
|
|
label: "职位",
|
|
|
minWidth: 100,
|
|
minWidth: 100,
|
|
|
|
|
+ fieldNames: { label: "label", value: "value" },
|
|
|
|
|
+ enum: fetchPositionSearchEnum,
|
|
|
search: {
|
|
search: {
|
|
|
- el: "input",
|
|
|
|
|
- props: { placeholder: "请输入" },
|
|
|
|
|
|
|
+ el: "select",
|
|
|
|
|
+ props: { placeholder: "请选择", filterable: true, clearable: true },
|
|
|
order: 2
|
|
order: 2
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
@@ -486,9 +530,17 @@ const columns = reactive<ColumnProps<any>[]>([
|
|
|
order: 3
|
|
order: 3
|
|
|
},
|
|
},
|
|
|
render: (scope: any) => {
|
|
render: (scope: any) => {
|
|
|
- if (scope.row.onlineStatus === 0 || scope.row.onlineStatus === "0") return "上线";
|
|
|
|
|
- if (scope.row.onlineStatus === 1 || scope.row.onlineStatus === "1") return "下线";
|
|
|
|
|
- return "—";
|
|
|
|
|
|
|
+ const audit = scope.row.status ?? scope.row.approvalStatus;
|
|
|
|
|
+ if (audit === 0 || audit === "0" || audit === 2 || audit === "2") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-dash" }, "—");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (scope.row.onlineStatus === 1 || scope.row.onlineStatus === "1") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-dash" }, "—");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (scope.row.onlineStatus === 0 || scope.row.onlineStatus === "0") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-online-up" }, "在线");
|
|
|
|
|
+ }
|
|
|
|
|
+ return h("span", { class: "personnel-cell-dash" }, "—");
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -497,17 +549,22 @@ const columns = reactive<ColumnProps<any>[]>([
|
|
|
width: 120,
|
|
width: 120,
|
|
|
enum: approvalStatusEnum,
|
|
enum: approvalStatusEnum,
|
|
|
fieldNames: { label: "label", value: "value" },
|
|
fieldNames: { label: "label", value: "value" },
|
|
|
- tag: true,
|
|
|
|
|
search: {
|
|
search: {
|
|
|
el: "select",
|
|
el: "select",
|
|
|
props: { placeholder: "请选择" },
|
|
props: { placeholder: "请选择" },
|
|
|
order: 4
|
|
order: 4
|
|
|
},
|
|
},
|
|
|
render: (scope: any) => {
|
|
render: (scope: any) => {
|
|
|
- if (scope.row.approvalStatus === 1 || scope.row.approvalStatus === "1") return "已通过";
|
|
|
|
|
- if (scope.row.approvalStatus === 2 || scope.row.approvalStatus === "2") return "已驳回";
|
|
|
|
|
- if (scope.row.approvalStatus === 0 || scope.row.approvalStatus === "0") return "待审核";
|
|
|
|
|
- return "—";
|
|
|
|
|
|
|
+ if (scope.row.approvalStatus === 1 || scope.row.approvalStatus === "1") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-pass" }, "已通过");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (scope.row.approvalStatus === 2 || scope.row.approvalStatus === "2") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-reject" }, "已驳回");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (scope.row.approvalStatus === 0 || scope.row.approvalStatus === "0") {
|
|
|
|
|
+ return h("span", { class: "personnel-cell-pending" }, "待审核");
|
|
|
|
|
+ }
|
|
|
|
|
+ return h("span", { class: "personnel-cell-dash" }, "—");
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -720,6 +777,47 @@ const formData = reactive({
|
|
|
description: ""
|
|
description: ""
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+/** 人员职位下拉:来自 storeStaffTitle/query */
|
|
|
|
|
+const staffPositionOptions = ref<{ label: string; value: string }[]>([]);
|
|
|
|
|
+
|
|
|
|
|
+const getPersonnelStoreId = (): string | number | undefined => {
|
|
|
|
|
+ return localGet("geeker-user")?.userInfo?.storeId || localGet("createdId");
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+async function loadStaffPositionOptions() {
|
|
|
|
|
+ const storeId = getPersonnelStoreId();
|
|
|
|
|
+ if (!storeId) {
|
|
|
|
|
+ staffPositionOptions.value = [];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res: any = await queryStaffTitle({ storeId });
|
|
|
|
|
+ const inner = res?.data;
|
|
|
|
|
+ const raw = Array.isArray(inner) ? inner : (inner?.records ?? inner?.list ?? []);
|
|
|
|
|
+ const arr = Array.isArray(raw) ? raw : [];
|
|
|
|
|
+ const seen = new Set<string>();
|
|
|
|
|
+ const list: { label: string; value: string }[] = [];
|
|
|
|
|
+ for (const item of arr) {
|
|
|
|
|
+ const title = String(item.titleName ?? item.name ?? item.positionName ?? "").trim();
|
|
|
|
|
+ if (!title || seen.has(title)) continue;
|
|
|
|
|
+ seen.add(title);
|
|
|
|
|
+ list.push({ label: title, value: title });
|
|
|
|
|
+ }
|
|
|
|
|
+ staffPositionOptions.value = list;
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ staffPositionOptions.value = [];
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 编辑回显:接口返回的职位若不在当前标题列表中,仍补一条可选 */
|
|
|
|
|
+function mergeLegacyPositionOption(position: string) {
|
|
|
|
|
+ const v = (position || "").trim();
|
|
|
|
|
+ if (!v) return;
|
|
|
|
|
+ if (!staffPositionOptions.value.some(o => o.value === v)) {
|
|
|
|
|
+ staffPositionOptions.value = [{ label: v, value: v }, ...staffPositionOptions.value];
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 同步组件内部文件列表到 formData(避免上传中因过滤 blob 导致列表被清空或重复)
|
|
// 同步组件内部文件列表到 formData(避免上传中因过滤 blob 导致列表被清空或重复)
|
|
|
const syncFileListFromComponent = async () => {
|
|
const syncFileListFromComponent = async () => {
|
|
|
if (!backgroundImagesUploadRef.value || !dialogVisible.value) return;
|
|
if (!backgroundImagesUploadRef.value || !dialogVisible.value) return;
|
|
@@ -923,7 +1021,7 @@ watch(
|
|
|
// 表单校验规则
|
|
// 表单校验规则
|
|
|
const rules = reactive<FormRules>({
|
|
const rules = reactive<FormRules>({
|
|
|
name: [{ required: true, message: "请输入姓名/昵称", trigger: "blur" }],
|
|
name: [{ required: true, message: "请输入姓名/昵称", trigger: "blur" }],
|
|
|
- position: [{ required: true, message: "请输入人员职位", trigger: "blur" }],
|
|
|
|
|
|
|
+ position: [{ required: true, message: "请选择人员职位", trigger: "change" }],
|
|
|
avatar: [{ required: true, message: "请上传头像", trigger: "change" }],
|
|
avatar: [{ required: true, message: "请上传头像", trigger: "change" }],
|
|
|
backgroundImages: [
|
|
backgroundImages: [
|
|
|
{
|
|
{
|
|
@@ -1177,8 +1275,13 @@ const handleTitleSubmit = async () => {
|
|
|
params.id = titleEditId.value;
|
|
params.id = titleEditId.value;
|
|
|
res = await updateTitle(params);
|
|
res = await updateTitle(params);
|
|
|
} else {
|
|
} else {
|
|
|
- // 创建标题
|
|
|
|
|
- res = await createTitle(params);
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ res = await createTitle(params, { hideBusinessErrorMessage: true });
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ ElMessage.error("此名称已存在");
|
|
|
|
|
+ titleSubmitLoading.value = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (res && (res.code === 200 || res.code === "200")) {
|
|
if (res && (res.code === 200 || res.code === "200")) {
|
|
@@ -1351,6 +1454,7 @@ const openCreateDialog = async () => {
|
|
|
editId.value = null;
|
|
editId.value = null;
|
|
|
resetForm();
|
|
resetForm();
|
|
|
uploadComponentKey.value += 1;
|
|
uploadComponentKey.value += 1;
|
|
|
|
|
+ await loadStaffPositionOptions();
|
|
|
dialogVisible.value = true;
|
|
dialogVisible.value = true;
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
// 如果检查标题时出错,记录错误但允许继续创建人员(避免阻塞用户)
|
|
// 如果检查标题时出错,记录错误但允许继续创建人员(避免阻塞用户)
|
|
@@ -1369,6 +1473,7 @@ const openCreateDialog = async () => {
|
|
|
editId.value = null;
|
|
editId.value = null;
|
|
|
resetForm();
|
|
resetForm();
|
|
|
uploadComponentKey.value += 1;
|
|
uploadComponentKey.value += 1;
|
|
|
|
|
+ await loadStaffPositionOptions();
|
|
|
dialogVisible.value = true;
|
|
dialogVisible.value = true;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
@@ -1433,6 +1538,8 @@ const editPersonnel = async (person: Personnel, index: number) => {
|
|
|
|
|
|
|
|
// 强制背景上传组件重新挂载,避免沿用上次的 _fileList 导致数量显示错误
|
|
// 强制背景上传组件重新挂载,避免沿用上次的 _fileList 导致数量显示错误
|
|
|
uploadComponentKey.value += 1;
|
|
uploadComponentKey.value += 1;
|
|
|
|
|
+ await loadStaffPositionOptions();
|
|
|
|
|
+ mergeLegacyPositionOption(formData.position);
|
|
|
// 打开对话框
|
|
// 打开对话框
|
|
|
dialogVisible.value = true;
|
|
dialogVisible.value = true;
|
|
|
} else {
|
|
} else {
|
|
@@ -2247,31 +2354,40 @@ onMounted(async () => {
|
|
|
min-height: 100%;
|
|
min-height: 100%;
|
|
|
padding: 20px;
|
|
padding: 20px;
|
|
|
background-color: white;
|
|
background-color: white;
|
|
|
- .action-section {
|
|
|
|
|
|
|
+ .personnel-table-toolbar {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
gap: 12px;
|
|
gap: 12px;
|
|
|
|
|
+ align-items: center;
|
|
|
margin-bottom: 16px;
|
|
margin-bottom: 16px;
|
|
|
|
|
+ .title-dropdown-trigger {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 列表:在线状态 / 审核状态 文字颜色 */
|
|
|
|
|
+ :deep(.personnel-cell-online-up) {
|
|
|
|
|
+ color: var(--el-color-success);
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.personnel-cell-dash) {
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.personnel-cell-pass) {
|
|
|
|
|
+ color: var(--el-color-success);
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.personnel-cell-reject) {
|
|
|
|
|
+ color: var(--el-color-danger);
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.personnel-cell-pending) {
|
|
|
|
|
+ color: var(--el-color-warning);
|
|
|
}
|
|
}
|
|
|
.table-box {
|
|
.table-box {
|
|
|
- .table-header-title {
|
|
|
|
|
|
|
+ :deep(.personnel-table-header-actions) {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- margin-bottom: 16px;
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- color: var(--el-text-color-primary);
|
|
|
|
|
- .table-title {
|
|
|
|
|
- margin-right: 8px;
|
|
|
|
|
- }
|
|
|
|
|
- .table-icon {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- color: var(--el-text-color-regular);
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: transform 0.3s;
|
|
|
|
|
- &:hover {
|
|
|
|
|
- color: var(--el-color-primary);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 12px 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* 列表为空时去掉空状态残留图形/背景,仅显示「暂无数据」文字 */
|
|
/* 列表为空时去掉空状态残留图形/背景,仅显示「暂无数据」文字 */
|
|
@@ -2346,8 +2462,16 @@ onMounted(async () => {
|
|
|
.detail-avatar {
|
|
.detail-avatar {
|
|
|
width: 100px;
|
|
width: 100px;
|
|
|
height: 100px;
|
|
height: 100px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
object-fit: cover;
|
|
object-fit: cover;
|
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
|
|
|
+ transition:
|
|
|
|
|
+ transform 0.2s,
|
|
|
|
|
+ box-shadow 0.2s;
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
|
|
|
|
|
+ transform: scale(1.05);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
.background-images {
|
|
.background-images {
|
|
|
display: grid;
|
|
display: grid;
|
|
@@ -2419,16 +2543,4 @@ onMounted(async () => {
|
|
|
display: contents;
|
|
display: contents;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-.video-preview-wrap {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- min-height: 200px;
|
|
|
|
|
- background: #000000;
|
|
|
|
|
- .video-preview-player {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- max-width: 100%;
|
|
|
|
|
- max-height: 75vh;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
</style>
|
|
</style>
|