| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- <template>
- <div>
- <el-drawer
- v-model="visible"
- title="问题编辑"
- direction="rtl"
- size="30%"
- :close-on-click-modal="false"
- @close="handleCancel"
- >
- <el-form ref="formRef" :model="formData">
- <el-form-item
- label="问题来源:"
- prop="source"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-select
- v-model="formData.source"
- placeholder="请选择问题来源"
- clearable
- @change="handleSelectChange"
- >
- <el-option
- v-for="item in sourceOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item
- label="问题类型:"
- prop="issueType"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-select v-model="formData.issueType" placeholder="请选择问题类型" clearable>
- <el-option v-for="item in options" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- <el-form-item
- label="问题描述:"
- prop="description"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-input
- v-model="formData.description"
- type="textarea"
- maxlength="100"
- autosize
- show-word-limit
- placeholder="请输入问题描述,不超过100个字"
- ></el-input>
- </el-form-item>
- <el-form-item
- class="pic-form-item"
- label="问题图片:"
- prop="pictures"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <p>(建议尺寸192*108,大小10M以下)</p>
- <el-upload
- v-model:file-list="fileList"
- :action="actionUrl"
- list-type="picture-card"
- :on-preview="handlePictureCardPreview"
- :on-remove="handleRemove"
- :on-success="handleAvatarSuccess"
- :headers="getHeaders()"
- :data="{ bizType: 'PROBLEM_REPORT' }"
- >
- <el-icon>
- <Plus />
- </el-icon>
- </el-upload>
- <el-dialog v-model="dialogVisible">
- <img w-full :src="dialogImageUrl" alt="Preview Image" />
- </el-dialog>
- </el-form-item>
- <el-form-item class="pic-form-item" label="问题视频:" prop="videos">
- <p>(仅支持上传1条视频,大小50M以内)</p>
- <el-upload
- v-if="
- formData.videos === undefined ||
- formData.videos === null ||
- (formData.videos && formData.videos.length === 0)
- "
- class="avatar-uploader"
- :action="actionUrl"
- :show-file-list="false"
- :on-success="handleUploadVideo"
- :headers="getHeaders()"
- :data="{ bizType: 'PROBLEM_REPORT' }"
- :before-upload="beforeUploadVideo"
- >
- <el-icon class="avatar-uploader-icon">
- <Plus />
- </el-icon>
- </el-upload>
- <div class="upload-success" v-else>
- <img
- src="@/assets/images/alert/video-play.png"
- @click="videoDialogVisible = true"
- style="cursor: pointer"
- />
- <el-icon class="clear-video" @click="handleDeleteVideo" :size="15" color="#fff">
- <CloseBold />
- </el-icon>
- <el-dialog v-model="videoDialogVisible">
- <video
- type="video/mp4"
- muted="true"
- preload="auto"
- :controls="true"
- autoplay
- style="height: 500px; object-fit: fill"
- >
- <source :src="formData.videos![0]" />
- </video>
- </el-dialog>
- </div>
- </el-form-item>
- <el-form-item
- label="问题地点:"
- prop="workspaceId"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-cascader
- v-model="workLocation"
- :options="locationOptions"
- :props="location"
- placeholder="请选择问题地点"
- clearable
- @change="handleCascaderChange"
- />
- </el-form-item>
- <el-form-item
- label="问题时间:"
- prop="createdAt"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-date-picker
- v-model="formData.createdAt"
- type="datetime"
- value-format="YYYY-MM-DD HH:mm:ss"
- placeholder="请选择问题时间"
- />
- </el-form-item>
- <el-form-item
- label="问题状态:"
- prop="issueState"
- :rules="{ required: true, message: '请完成必填项' }"
- >
- <el-select v-model="formData.issueState" placeholder="请选择问题状态" clearable>
- <el-option
- v-for="item in issueStateOptionsAdd"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <div class="btn-box">
- <el-button @click="handleCancel">取消</el-button>
- <el-button type="primary" @click="handleSubmit(formRef)">保存</el-button>
- </div>
- </el-form-item>
- </el-form>
- </el-drawer>
- </div>
- </template>
- <script setup lang="ts">
- import { computed, onBeforeMount, onMounted, reactive, ref } from 'vue';
- import {
- ElMessage,
- type FormInstance,
- type UploadProps,
- type UploadUserFile,
- } from 'element-plus';
- import { Plus, CloseBold } from '@element-plus/icons-vue';
- import { Source, IssueState, sourceOptions, issueStateOptionsAdd } from './constant.question';
- import { useIssueType } from '../../hooks/useIssueType';
- import { useWorkLocation } from '../../hooks/useWorkLocation';
- import { getHeaders } from '@/utils/http/axios';
- import urlJoin from 'url-join';
- import { useGlobSetting } from '@/hooks/setting';
- interface Props {
- initialData?: FormModel;
- }
- interface FormModel {
- id?: number;
- source?: number; // 来源
- issueType?: number; // 类型
- description?: string; // 描述
- pictures?: string[]; // 图片
- videos?: string[];
- workshopId?: number; // 车间id
- workshopName?: string;
- workspaceId?: number; // 工位id
- workspaceName?: string;
- createdAt?: string; // 时间
- issueState?: number; // 状态
- }
- const visible = ref(true);
- const { aiOptions, manualOptions, getAIOptions, getManualOptions } = useIssueType();
- const { locationOptions, getLocationOptions, getNameByWorkid } = useWorkLocation();
- const props = defineProps<Props>();
- const emits = defineEmits(['saveForm', 'closeForm']);
- const formRef = ref<FormInstance>();
- const formData = reactive<FormModel>({
- id: undefined,
- source: undefined,
- issueType: undefined,
- description: '',
- pictures: [],
- videos: [],
- workshopId: undefined,
- workspaceId: undefined,
- createdAt: '',
- issueState: undefined,
- });
- const location = { expandTrigger: 'hover' as const };
- const workLocation = ref<[number | undefined, number | undefined] | []>([]);
- const { urlPrefix } = useGlobSetting();
- const handleSelectChange = () => {
- formData.issueType = undefined;
- };
- const options = computed(() => {
- if (Number(formData.source) === Source.ai && aiOptions.value.length > 0) {
- return aiOptions.value;
- }
- if (Number(formData.source) === Source.manual && manualOptions.value.length > 0) {
- return manualOptions.value;
- }
- return [];
- });
- const handleCascaderChange = () => {
- if (workLocation.value != null) {
- formData.workshopId = workLocation.value[0];
- formData.workspaceId = workLocation.value[1];
- const tempString = getNameByWorkid(
- formData.workshopId,
- formData.workspaceId,
- locationOptions.value,
- );
- const strFlag = tempString?.indexOf('-');
- formData.workshopName = tempString?.slice(0, strFlag);
- formData.workspaceName = tempString?.slice(strFlag! + 1);
- } else {
- Reflect.deleteProperty(formData, 'workshopId');
- Reflect.deleteProperty(formData, 'workspaceId');
- }
- };
- const handleCopyData = () => {
- formData.id = props.initialData?.id;
- formData.source = props.initialData?.source;
- formData.issueType = props.initialData?.issueType;
- formData.description = props.initialData?.description;
- formData.pictures = props.initialData?.pictures;
- formData.videos = props.initialData?.videos;
- formData.workshopId = props.initialData?.workshopId;
- formData.workspaceId = props.initialData?.workspaceId;
- formData.createdAt = props.initialData?.createdAt;
- switch (props.initialData?.issueState) {
- case IssueState.toAuth0:
- formData.issueState = 2;
- break;
- case IssueState.toAuth1:
- formData.issueState = 2;
- break;
- case IssueState.toDeal6:
- formData.issueState = 4;
- break;
- case IssueState.hasDone7:
- formData.issueState = 8;
- break;
- default:
- formData.issueState = props.initialData?.issueState;
- break;
- }
- workLocation.value = [props.initialData?.workshopId, props.initialData?.workspaceId!];
- fileList.value = props.initialData?.pictures?.map((str) => ({ name: str, url: str })) || [];
- };
- // 取消
- const handleCancel = () => {
- emits('closeForm');
- };
- const actionUrl = computed(() => {
- return urlJoin(urlPrefix!, `/admin/minio/uploadFile`);
- });
- // 保存
- const handleSubmit = async (formEl: FormInstance | undefined) => {
- if (!formEl) return;
- await formEl.validate((valid, fields) => {
- if (valid) {
- console.log('submit!', formData);
- emits('saveForm', formData);
- } else {
- console.log('error submit!', fields);
- }
- });
- };
- const handleAvatarSuccess = (res) => {
- if (!formData.pictures) formData.pictures = [];
- formData.pictures.push(res.data.url);
- };
- const fileList = ref<UploadUserFile[]>([]);
- const dialogImageUrl = ref('');
- const dialogVisible = ref(false);
- const handleRemove: UploadProps['onRemove'] = (uploadFile) => {
- const index = formData.pictures?.indexOf(uploadFile.url || '')!;
- if (index !== -1) formData.pictures?.splice(index, 1);
- };
- const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
- dialogImageUrl.value = uploadFile.url!;
- dialogVisible.value = true;
- };
- // 视频上传
- const videoDialogVisible = ref(false);
- const handleUploadVideo = (res) => {
- if (!formData.videos) formData.videos = [];
- formData.videos.push(res.data.url);
- };
- const handleDeleteVideo = () => {
- formData.videos = [];
- };
- const beforeUploadVideo: UploadProps['beforeUpload'] = (rawFile) => {
- if (rawFile.type !== 'video/mp4') {
- ElMessage.error('上传视频仅支持mp4格式');
- return false;
- } else if (rawFile.size / 1024 / 1024 > 50) {
- ElMessage.error('上传视频大小不能超过50MB');
- return false;
- }
- return true;
- };
- onMounted(() => {
- handleCopyData();
- });
- onBeforeMount(() => {
- getAIOptions();
- getManualOptions();
- getLocationOptions();
- });
- </script>
- <style scoped lang="less">
- :deep(.el-drawer__header) {
- position: relative;
- > :first-child {
- margin-left: 32px;
- font-weight: 600;
- font-size: 16px;
- color: rgba(0, 0, 0, 0.88);
- }
- .el-drawer__close-btn {
- position: absolute;
- color: #000;
- }
- }
- .btn-box {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- margin-top: 10px;
- }
- .pic-form-item {
- :deep(.el-form-item__content) {
- display: block;
- }
- }
- p {
- font-size: 10px;
- color: #a8abb2;
- }
- :deep(.avatar-uploader .el-upload) {
- border: 1px dashed #cdd0d6;
- border-radius: 6px;
- cursor: pointer;
- position: relative;
- overflow: hidden;
- transition: var(--el-transition-duration-fast);
- background-color: #fafafa;
- }
- :deep(.avatar-uploader .el-upload:hover) {
- border-color: var(--el-color-primary);
- }
- .el-icon.avatar-uploader-icon {
- font-size: 28px;
- color: #909399;
- width: 148px;
- height: 148px;
- text-align: center;
- }
- .upload-success {
- position: relative;
- .clear-video {
- width: 25px;
- height: 25px;
- position: absolute;
- top: 0;
- left: 129px;
- cursor: pointer;
- background-color: #000;
- border-radius: 0 0 0 25px;
- opacity: 0.7;
- }
- :deep(.el-dialog) {
- width: 960px;
- height: 540px;
- padding: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: #000;
- }
- :deep(.el-dialog__header) {
- display: none;
- }
- }
- </style>
|