鱼种类修改,导入修改,新增修改
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
10c3c33ad0
commit
7e383e35fe
@ -6,4 +6,7 @@ NODE_ENV='development'
|
||||
VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
## 开发环境API地址
|
||||
VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
|
||||
## 开发环境预览 图片视频地址
|
||||
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'
|
||||
|
||||
@ -4,4 +4,7 @@ NODE_ENV='production'
|
||||
VITE_APP_TITLE = 'qgc-buji-web'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
## 生产环境API地址
|
||||
VITE_APP_BASE_URL = 'http://localhost:8093'
|
||||
## 生产环境预览 图片视频地址
|
||||
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'
|
||||
|
||||
BIN
frontend/dist.rar
Normal file
BIN
frontend/dist.rar
Normal file
Binary file not shown.
@ -81,7 +81,7 @@ export function checkImportStatus() {
|
||||
});
|
||||
}
|
||||
|
||||
// 查询用户导入导入结果
|
||||
// 查询用户导入结果
|
||||
export function getLastImportResult() {
|
||||
return request({
|
||||
url: '/data/fishDraft/getLastImportResult',
|
||||
|
||||
@ -9,11 +9,11 @@ export function getBaseDropdown(data:any) {
|
||||
});
|
||||
}
|
||||
//电站下拉列表
|
||||
export function getEngInfoDropdown(params:any) {
|
||||
export function getEngInfoDropdown(data:any) {
|
||||
return request({
|
||||
url: '/env/engInfo/dropdown',
|
||||
method: 'get',
|
||||
params
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//过鱼设施下拉列表
|
||||
@ -31,3 +31,12 @@ export function getFishDictoryDropdown() {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
// 上传文件
|
||||
export function uploadFile(data:any) {
|
||||
return request({
|
||||
url: import.meta.env.VITE_APP_PREVIEW_URL + '/upload',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,13 +7,12 @@
|
||||
:loading="loading"
|
||||
@change="handleChange"
|
||||
@search="handleSearch"
|
||||
placeholder="请选择鱼种类"
|
||||
placeholder="鱼种类支持俗名查询"
|
||||
:mode="multiple ? 'multiple' : undefined"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
class="custom-fish-select"
|
||||
:dropdownMatchSelectWidth="false"
|
||||
:getPopupContainer="(triggerNode: HTMLElement) => triggerNode.parentNode"
|
||||
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||
:max-tag-count="multiple ? 1 : undefined"
|
||||
:open="open"
|
||||
@ -29,6 +28,23 @@
|
||||
|
||||
<template #dropdownRender>
|
||||
<div class="custom-dropdown-container">
|
||||
<div class="w-[340px] h-[30px] flex items-center pl-[10px]" @click.stop @mousedown.prevent>
|
||||
<div>查询方式:</div>
|
||||
<div
|
||||
class="text-[12px] font-bold mr-2 cursor-pointer"
|
||||
:class="{ 'text-[#005293]': !isIntelligentQuery }"
|
||||
@click="IntelligentQueryCLick(false)"
|
||||
>
|
||||
相似度
|
||||
</div>
|
||||
<div
|
||||
class="text-[12px] font-bold cursor-pointer"
|
||||
:class="{ 'text-[#005293]': isIntelligentQuery }"
|
||||
@click="IntelligentQueryCLick(true)"
|
||||
>
|
||||
智能查询
|
||||
</div>
|
||||
</div>
|
||||
<!-- 左侧:可滚动的选项列表 -->
|
||||
<div class="dropdown-left-list">
|
||||
<div
|
||||
@ -42,7 +58,7 @@
|
||||
@click.stop="handleSelectOption(opt)"
|
||||
@mouseenter="hoveredId = opt.id"
|
||||
>
|
||||
<span class="item-name">{{ opt.name }}</span>
|
||||
<span class="item-name" v-html="highlightText(opt.name)"></span>
|
||||
<!-- 选中对勾 -->
|
||||
<span v-if="isSelected(opt.id)" class="check-icon">✓</span>
|
||||
</div>
|
||||
@ -53,11 +69,14 @@
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<!-- 右侧:固定显示的别名/详情 -->
|
||||
<div class="dropdown-right-detail">
|
||||
<div class="dropdown-right-detail" @click.stop @mousedown.prevent>
|
||||
<div v-if="currentDetailData" class="detail-content">
|
||||
<div class="detail-title">{{ currentDetailData.name }}</div>
|
||||
<div
|
||||
class="detail-title"
|
||||
v-html="highlightText(currentDetailData.name)"
|
||||
></div>
|
||||
<div class="detail-alias" :title="currentDetailData.alias">
|
||||
{{ currentDetailData.alias || "暂无别名" }}
|
||||
<div v-html="highlightText(currentDetailData.alias)"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="detail-placeholder">请选择或悬停查看</div>
|
||||
@ -71,6 +90,7 @@
|
||||
import { ref, onMounted, computed, watch } from "vue";
|
||||
import { getFishDictoryDropdown } from "@/api/select";
|
||||
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
|
||||
import { message } from "ant-design-vue";
|
||||
const shuJuTianBaoStore = useShuJuTianBaoStore();
|
||||
|
||||
// --- Props & Emits ---
|
||||
@ -94,6 +114,7 @@ const options = ref<any[]>([]);
|
||||
const searchKeyword = ref<string>("");
|
||||
const hoveredId = ref<string | null>(null);
|
||||
const open = ref(false); // 控制下拉框显隐
|
||||
const isIntelligentQuery = ref(true); // 控制是否为智能查询
|
||||
|
||||
// --- Computed ---
|
||||
const filteredOptions = computed(() => {
|
||||
@ -128,6 +149,7 @@ const isSelected = (id: string) => {
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
searchKeyword.value = value;
|
||||
hoveredId.value = null;
|
||||
};
|
||||
|
||||
const handleDropdownVisibleChange = (val: boolean) => {
|
||||
@ -139,6 +161,8 @@ const handleDropdownVisibleChange = (val: boolean) => {
|
||||
};
|
||||
|
||||
const handleSelectOption = (opt: any) => {
|
||||
console.log(props.modelValue)
|
||||
console.log(props.modelValue)
|
||||
if (props.multiple) {
|
||||
// --- 多选逻辑 ---
|
||||
let newValues: string[] = Array.isArray(props.modelValue)
|
||||
@ -165,11 +189,19 @@ const handleSelectOption = (opt: any) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
const IntelligentQueryCLick = (val: boolean) => {
|
||||
isIntelligentQuery.value = val;
|
||||
if (val) {
|
||||
message.success("智能查询已开启");
|
||||
} else {
|
||||
message.success("智能查询已关闭");
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (val: any) => {
|
||||
// 当 a-select 内部触发 change 时(例如删除 Tag)
|
||||
// 在单选模式下,如果用户通过键盘或删除操作改变了值,这里也会捕获
|
||||
emit("update:modelValue", val, '');
|
||||
emit("update:modelValue", val, "");
|
||||
};
|
||||
|
||||
const getFishNameById = (id: string) => {
|
||||
@ -195,21 +227,29 @@ watch(
|
||||
const init = () => {
|
||||
let data = shuJuTianBaoStore.getFishOption();
|
||||
if (data.length === 0) {
|
||||
loading.value = true;
|
||||
getFishDictoryDropdown()
|
||||
.then((res) => {
|
||||
options.value = res.data || [];
|
||||
loading.value = false;
|
||||
shuJuTianBaoStore.setFishOption(options.value);
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
loading.value = true;
|
||||
getFishDictoryDropdown()
|
||||
.then((res) => {
|
||||
options.value = res.data || [];
|
||||
loading.value = false;
|
||||
shuJuTianBaoStore.setFishOption(options.value);
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
options.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
// 根据名字高亮显示匹配项
|
||||
const highlightText = (text) => {
|
||||
if (text == null) {
|
||||
return "暂无别名";
|
||||
}
|
||||
const reg = new RegExp(searchKeyword.value, "g");
|
||||
return text.replace(reg, `<span style="color: red;">${searchKeyword.value}</span>`);
|
||||
};
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
@ -226,7 +266,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.custom-dropdown-container {
|
||||
width: 401px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
@ -323,6 +365,9 @@ onMounted(() => {
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
span {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-placeholder {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed } from "vue";
|
||||
import { useTagsViewStore } from "@/store/modules/tagsView";
|
||||
import { useRoute } from "vue-router";
|
||||
import GisView from "@/components/gis/GisView.vue";
|
||||
// import GisView from "@/components/gis/GisView.vue";
|
||||
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
|
||||
@ -12,7 +12,7 @@ const routeKey = computed(() => router.path + Math.random());
|
||||
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<GisView />
|
||||
<!-- <GisView /> -->
|
||||
<div class="gi-panels">
|
||||
<router-view v-slot="{ Component, route }" :key="routeKey">
|
||||
<transition name="router-fade" mode="out-in">
|
||||
|
||||
@ -11,11 +11,9 @@ import Sidebar from "./Sidebar/index.vue";
|
||||
|
||||
import { useTagsViewStore } from "@/store/modules/tagsView";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import Cookies from "js-cookie";
|
||||
import {getPath,removePath } from '@/utils/auth';
|
||||
|
||||
// const url = import.meta.env.VITE_APP_BASE_API;
|
||||
const username = Cookies.get("username");
|
||||
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
const userStore = useUserStore();
|
||||
@ -67,7 +65,7 @@ onBeforeUnmount(() => {
|
||||
<span class="icon">
|
||||
<UserOutlined />
|
||||
</span>
|
||||
<span class="text">{{ username }}</span>
|
||||
<span class="text">{{ userStore.username }}</span>
|
||||
</div>
|
||||
</a-space>
|
||||
<template #overlay>
|
||||
|
||||
@ -12,6 +12,7 @@ import { UserInfo } from '@/api/user/types';
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// state
|
||||
const Token = ref<string>(getToken() || '');
|
||||
const username = ref<string>('');
|
||||
const nickname = ref<string>('');
|
||||
const avatar = ref<string>('');
|
||||
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
||||
@ -47,6 +48,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
if (!data.roles || data.roles.length <= 0) {
|
||||
reject('getUserInfo: roles must be a non-null array!');
|
||||
}
|
||||
username.value = data.userInfo.username;
|
||||
nickname.value = data.userInfo.nickname;
|
||||
avatar.value = data.userInfo.avatar;
|
||||
roles.value = data.roles;
|
||||
@ -85,6 +87,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
}
|
||||
return {
|
||||
Token,
|
||||
username,
|
||||
nickname,
|
||||
avatar,
|
||||
roles,
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
v-model:value="formData.rstcd"
|
||||
:loading="engLoading"
|
||||
placeholder="请选择电站名称"
|
||||
:disabled="isView"
|
||||
:disabled="isView || !formData.baseId"
|
||||
show-search
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
@ -72,7 +72,7 @@
|
||||
v-model:value="formData.stcd"
|
||||
:loading="fpssLoading"
|
||||
placeholder="请选择过鱼设施"
|
||||
:disabled="isView"
|
||||
:disabled="isView || !formData.rstcd"
|
||||
show-search
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
@ -218,16 +218,47 @@
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-col :span="12" class="imgupload" :class="{'imgupload_hidden': isView}">
|
||||
<a-form-item label="图片" name="picpth">
|
||||
<!-- <a-input v-model:value="formData.picpth" placeholder="图片路径" /> -->
|
||||
<a-upload
|
||||
v-model:file-list="imageFileList"
|
||||
list-type="picture-card"
|
||||
:multiple="true"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
:before-upload="beforeImageUpload"
|
||||
@preview="handleImagePreview"
|
||||
:disabled="isView"
|
||||
:maxCount="5"
|
||||
@remove="handleImageRemove"
|
||||
>
|
||||
<div v-if="!isView && imageFileList.length < 5">
|
||||
<plus-outlined />
|
||||
<div style="margin-top: 8px">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="视频" name="vdpth">
|
||||
<!-- <a-input v-model:value="formData.vdpth" placeholder="视频路径" /> -->
|
||||
<a-upload
|
||||
v-if="!isView"
|
||||
v-model:file-list="videoFileList"
|
||||
list-type="text"
|
||||
:multiple="false"
|
||||
accept=".mp4"
|
||||
:before-upload="beforeVideoUpload"
|
||||
:disabled="isView"
|
||||
:maxCount="5"
|
||||
@remove="handleVideoRemove"
|
||||
>
|
||||
<a-button :disabled="isView && videoFileList.length < 5">
|
||||
<upload-outlined />
|
||||
上传视频 (MP4)
|
||||
</a-button>
|
||||
</a-upload>
|
||||
<a-button v-else @click="handleVideoPreview"> 点击预览视频 </a-button>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@ -238,10 +269,17 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch, computed } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { message } from "ant-design-vue";
|
||||
import { Upload, message } from "ant-design-vue";
|
||||
import { UploadOutlined, PlusOutlined } from "@ant-design/icons-vue";
|
||||
import type { Rule } from "ant-design-vue/es/form";
|
||||
import type { UploadProps } from "ant-design-vue";
|
||||
import fishSearch from "@/components/fishSearch/index.vue";
|
||||
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from "@/api/select";
|
||||
import {
|
||||
getBaseDropdown,
|
||||
getEngInfoDropdown,
|
||||
getFpssDropdown,
|
||||
uploadFile,
|
||||
} from "@/api/select";
|
||||
|
||||
// 定义 Props
|
||||
interface Props {
|
||||
@ -257,6 +295,8 @@ const fpssLoading = ref(false);
|
||||
const baseOption = ref<any[]>([]);
|
||||
const engOption = ref<any[]>([]);
|
||||
const fpssOption = ref<any[]>([]);
|
||||
const imageFileList = ref<any[]>([]);
|
||||
const videoFileList = ref<any[]>([]);
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
@ -315,6 +355,7 @@ const emit = defineEmits<{
|
||||
(e: "update:visible", value: boolean): void;
|
||||
(e: "cancel"): void;
|
||||
(e: "ok", values: any): void;
|
||||
(e: "preview-click", record: any, type: string, index: number): void;
|
||||
}>();
|
||||
|
||||
// 表单引用
|
||||
@ -420,7 +461,55 @@ const validateWeight = () => {
|
||||
|
||||
return true;
|
||||
};
|
||||
// 图片上传前校验
|
||||
const beforeImageUpload: UploadProps["beforeUpload"] = (file) => {
|
||||
const isJpgOrPng =
|
||||
file.type === "image/jpeg" ||
|
||||
file.type === "image/png" ||
|
||||
file.name.toLowerCase().endsWith(".jpg") ||
|
||||
file.name.toLowerCase().endsWith(".jpeg") ||
|
||||
file.name.toLowerCase().endsWith(".png");
|
||||
if (!isJpgOrPng) {
|
||||
message.error("只能上传 JPG/PNG/JPEG 格式的图片!");
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
const isLt2M = file.size / 1024 / 1024 < 5; // 限制5M,可根据需求调整
|
||||
if (!isLt2M) {
|
||||
message.error("图片大小不能超过 5MB!");
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
// 返回 false 阻止自动上传,我们手动处理
|
||||
return false;
|
||||
};
|
||||
|
||||
// 视频上传前校验
|
||||
const beforeVideoUpload: UploadProps["beforeUpload"] = (file) => {
|
||||
const isMp4 = file.type === "video/mp4" || file.name.toLowerCase().endsWith(".mp4");
|
||||
if (!isMp4) {
|
||||
message.error("只能上传 MP4 格式的视频!");
|
||||
return false;
|
||||
}
|
||||
const isLt50M = file.size / 1024 / 1024 < 10; // 限制50M,可根据需求调整
|
||||
if (!isLt50M) {
|
||||
message.error("视频大小不能超过 10MB!");
|
||||
return false;
|
||||
}
|
||||
// 返回 false 阻止自动上传
|
||||
return false;
|
||||
};
|
||||
|
||||
// 移除图片
|
||||
const handleImageRemove = (file: any) => {
|
||||
const index = imageFileList.value.indexOf(file);
|
||||
const newFileList = imageFileList.value.slice();
|
||||
newFileList.splice(index, 1);
|
||||
imageFileList.value = newFileList;
|
||||
};
|
||||
|
||||
// 移除视频
|
||||
const handleVideoRemove = (file: any) => {
|
||||
videoFileList.value = [];
|
||||
};
|
||||
// 1. 定义一个初始化表单的函数
|
||||
const initForm = () => {
|
||||
if (props.initialValues) {
|
||||
@ -453,7 +542,30 @@ const initForm = () => {
|
||||
formData.bodyLengthMin = undefined;
|
||||
formData.bodyLengthMax = undefined;
|
||||
}
|
||||
if (values.picpth) {
|
||||
const paths = Array.isArray(values.picpth)
|
||||
? values.picpth
|
||||
: values.picpth.split(",");
|
||||
imageFileList.value = paths.map((path: string, index: number) => ({
|
||||
uid: `-${index}`,
|
||||
name: path.split("/").pop() || `image-${index}`,
|
||||
status: "done",
|
||||
path: path,
|
||||
url: import.meta.env.VITE_APP_PREVIEW_URL + "/?" + path, // 这里需要是完整的可访问URL
|
||||
}));
|
||||
}
|
||||
|
||||
// 处理视频回显
|
||||
if (values.vdpth) {
|
||||
const paths = Array.isArray(values.vdpth) ? values.vdpth : values.vdpth.split(",");
|
||||
videoFileList.value = paths.map((path: string, index: number) => ({
|
||||
uid: `-${index}`,
|
||||
name: path.split("/").pop() || `image-${index}`,
|
||||
status: "done",
|
||||
path: path,
|
||||
url: import.meta.env.VITE_APP_PREVIEW_URL + "/?" + path, // 这里需要是完整的可访问URL
|
||||
}));
|
||||
}
|
||||
// 回填其他普通字段
|
||||
Object.keys(formData).forEach((key) => {
|
||||
// 跳过已经特殊处理的字段
|
||||
@ -498,6 +610,9 @@ const resetForm = () => {
|
||||
// 清空手动验证的错误信息
|
||||
bodyLengthError.value = "";
|
||||
weightError.value = "";
|
||||
// 清空文件列表
|
||||
imageFileList.value = [];
|
||||
videoFileList.value = [];
|
||||
};
|
||||
|
||||
// 取消操作
|
||||
@ -506,7 +621,21 @@ const handleCancel = () => {
|
||||
emit("cancel");
|
||||
resetForm();
|
||||
};
|
||||
const handleVideoPreview = () => {
|
||||
emit("preview-click", { vdpthList: videoFileList.value }, "formVideo", 0);
|
||||
};
|
||||
// ... 其他导入 ...
|
||||
|
||||
// 新增:自定义图片预览处理
|
||||
const handleImagePreview = async (file: any) => {
|
||||
if (!props.isView) {
|
||||
return "";
|
||||
}
|
||||
emit("preview-click", { picpthList: imageFileList.value }, "formImage", 0);
|
||||
return "";
|
||||
};
|
||||
|
||||
// ... 其他现有代码 ...
|
||||
// 确认操作
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
@ -520,6 +649,70 @@ const handleOk = async () => {
|
||||
}
|
||||
// 验证表单
|
||||
await formRef.value.validate();
|
||||
// 1. 处理图片上传
|
||||
let uploadedPicPaths: any[] = [];
|
||||
// 过滤出新生成的文件(没有 url 属性的通常是新选择的文件)
|
||||
const newImageFiles = imageFileList.value.filter(
|
||||
(file) => !file.url && file.originFileObj
|
||||
);
|
||||
|
||||
if (newImageFiles.length > 0) {
|
||||
// 这里需要循环上传,或者使用 Promise.all 并行上传
|
||||
// 伪代码:假设 uploadFile 返回 { data: { url: '...' } }
|
||||
const uploadPromises = newImageFiles.map((file) => {
|
||||
const formDataUpload = new FormData();
|
||||
formDataUpload.append("file", file.originFileObj);
|
||||
return uploadFile(formDataUpload); // 替换为真实的上传接口调用
|
||||
});
|
||||
|
||||
const results = await Promise.all(uploadPromises);
|
||||
uploadedPicPaths = results.map((item: any, index: number) => ({
|
||||
path: item.message,
|
||||
uid: `-${index}`,
|
||||
name: item.fileMD5,
|
||||
status: "done",
|
||||
url: item.fullFilePath, // 这里需要是完整的可访问URL
|
||||
}));
|
||||
}
|
||||
|
||||
// 合并已存在的图片路径(编辑模式下回显的)和新上传的
|
||||
const existingPics = imageFileList.value
|
||||
.filter((file) => file.path)
|
||||
.map((file) => file.path);
|
||||
const uploadedPicPaths1 = uploadedPicPaths
|
||||
.filter((file) => file.path)
|
||||
.map((file) => file.path);
|
||||
const finalPicPaths = [...existingPics, ...uploadedPicPaths1];
|
||||
|
||||
// 2. 处理视频上传
|
||||
let uploadedVideoPath = [];
|
||||
const newVideoFiles = videoFileList.value.filter(
|
||||
(file) => !file.url && file.originFileObj
|
||||
);
|
||||
|
||||
if (newVideoFiles.length > 0) {
|
||||
const uploadPromises = newVideoFiles.map((file) => {
|
||||
const formDataUpload = new FormData();
|
||||
formDataUpload.append("file", file.originFileObj);
|
||||
return uploadFile(formDataUpload); // 替换为真实的上传接口调用
|
||||
});
|
||||
const results = await Promise.all(uploadPromises);
|
||||
uploadedVideoPath = results.map((item: any, index: number) => ({
|
||||
path: item.message,
|
||||
uid: `-${index}`,
|
||||
name: item.fileMD5,
|
||||
status: "done",
|
||||
url: item.fullFilePath, // 这里需要是完整的可访问URL
|
||||
}));
|
||||
}
|
||||
const existingVideos = videoFileList.value
|
||||
.filter((file) => file.path)
|
||||
.map((file) => file.path);
|
||||
const uploadedVideoPaths1 = uploadedVideoPath
|
||||
.filter((file) => file.path)
|
||||
.map((file) => file.path);
|
||||
const finalVideoPaths = [...existingVideos, ...uploadedVideoPaths1];
|
||||
|
||||
let fwet = "";
|
||||
if (
|
||||
formData.weightMin == formData.weightMax &&
|
||||
@ -528,7 +721,7 @@ const handleOk = async () => {
|
||||
) {
|
||||
fwet = formData.weightMin;
|
||||
} else if (formData.weightMin == undefined && formData.weightMax == undefined) {
|
||||
fwet = "-";
|
||||
fwet = "";
|
||||
} else {
|
||||
fwet = formData.weightMin + "~" + formData.weightMax;
|
||||
}
|
||||
@ -543,7 +736,7 @@ const handleOk = async () => {
|
||||
formData.bodyLengthMin == undefined &&
|
||||
formData.bodyLengthMax == undefined
|
||||
) {
|
||||
fsz = "-";
|
||||
fsz = "";
|
||||
} else {
|
||||
fsz = formData.bodyLengthMin + "~" + formData.bodyLengthMax;
|
||||
}
|
||||
@ -552,9 +745,12 @@ const handleOk = async () => {
|
||||
...formData,
|
||||
fwet: fwet,
|
||||
fsz: fsz,
|
||||
picpth: finalPicPaths.join(","), // 根据后端要求,可能是数组或逗号分隔字符串
|
||||
vdpth: finalVideoPaths.join(","),
|
||||
};
|
||||
if (!formData.id) submitValues.tm = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
console.log(submitValues);
|
||||
// return;
|
||||
emit("ok", submitValues);
|
||||
} catch (error) {
|
||||
console.error("Validate Failed:", error);
|
||||
@ -563,5 +759,52 @@ const handleOk = async () => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.imgupload {
|
||||
/* 1. 控制上传触发按钮(那个加号框)的大小 */
|
||||
:deep(.ant-upload-select-picture-card) {
|
||||
width: 78px !important;
|
||||
height: 78px !important;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 2. 控制已上传列表项容器的大小 */
|
||||
:deep(.ant-upload-list-item-container) {
|
||||
width: 78px !important;
|
||||
height: 78px !important;
|
||||
float: left; /* 确保浮动排列,避免换行问题 */
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 3. 控制列表项内部的具体内容(图片/缩略图) */
|
||||
:deep(.ant-upload-list-item) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
|
||||
/* 删除预览按钮 */
|
||||
.ant-upload-list-item-actions {
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.imgupload_hidden{
|
||||
:deep(.ant-upload-list-item) {
|
||||
/* 删除预览按钮 */
|
||||
.ant-upload-list-item-actions {
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -78,7 +78,6 @@ import {
|
||||
import dayjs from "dayjs";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue"; // 确保路径正确
|
||||
import { DateSetting } from "@/utils/enumeration";
|
||||
import { checkPerm } from "@/directive/permission";
|
||||
import fishSearch from "@/components/fishSearch/index.vue";
|
||||
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
:columns="modalColumns"
|
||||
:scroll="{ y: 500, x: '100%' }"
|
||||
:pagination="false"
|
||||
:row-key="(record, index) => index"
|
||||
:row-key="(_record, index) => index"
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<!-- 1. 操作列 -->
|
||||
@ -29,28 +29,33 @@
|
||||
<template
|
||||
v-else-if="
|
||||
!isEditing(index) &&
|
||||
column.dataIndexKey &&
|
||||
record._warnings &&
|
||||
record._warnings.includes(column.dataIndexKey)
|
||||
"
|
||||
>
|
||||
<div style="color: red; display: flex; align-items: center">
|
||||
<span>{{ record[column.dataIndex] }}</span>
|
||||
<span v-if="record[column.dataIndex]">{{ record[column.dataIndex] }}</span>
|
||||
<span v-else> 请添加{{ column.title }}</span>
|
||||
<exclamation-circle-outlined style="margin-left: 4px" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 3. 编辑状态下的单元格 (绑定到 editingData) -->
|
||||
<template v-else-if="isEditing(index) && column.dataIndex != 'picpth' && column.dataIndex != 'vdpth'">
|
||||
<template
|
||||
v-else-if="
|
||||
isEditing(index) && column.dataIndex != 'picpth' && column.dataIndex != 'vdpth'
|
||||
"
|
||||
>
|
||||
<template v-if="column.dataIndex === 'baseName'">
|
||||
<a-select
|
||||
v-model:value="editingData.baseId"
|
||||
placeholder="请选择"
|
||||
show-search
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
:loading="rowStates[index]?.baseLoading"
|
||||
style="width: 100%"
|
||||
@change="(val) => handleBaseChange(val, index)"
|
||||
@change="(val) => handleBaseChange(val, index, 'input')"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="opt in baseOptions"
|
||||
@ -69,11 +74,12 @@
|
||||
v-model:value="editingData.rstcd"
|
||||
placeholder="请选择"
|
||||
show-search
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
:loading="rowStates[index]?.engLoading"
|
||||
style="width: 100%"
|
||||
:disabled="!editingData.baseId"
|
||||
@change="(val) => handleEngChange(val, index)"
|
||||
@change="(val) => handleEngChange(val, index, 'input')"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="opt in rowStates[index]?.engOptions || []"
|
||||
@ -92,6 +98,7 @@
|
||||
v-model:value="editingData.stcd"
|
||||
placeholder="请选择"
|
||||
show-search
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
:loading="rowStates[index]?.fpssLoading"
|
||||
style="width: 100%"
|
||||
@ -117,6 +124,7 @@
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="(val) => delWarning(val,'strdt')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -135,6 +143,7 @@
|
||||
v-model:value="editingData.direction"
|
||||
placeholder="请选择"
|
||||
style="width: 100%"
|
||||
@change="(val) => delWarning(val,'direction')"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in direction"
|
||||
@ -147,7 +156,15 @@
|
||||
</template>
|
||||
|
||||
<!-- 数字输入框 -->
|
||||
<template v-else-if="['fcnt', 'wt'].includes(column.dataIndex)">
|
||||
<template v-else-if="['fcnt'].includes(column.dataIndex)">
|
||||
<a-input-number
|
||||
v-model:value="editingData[column.dataIndex]"
|
||||
style="width: 100%"
|
||||
@change="(val) => delWarning(val, column.dataIndex)"
|
||||
:min="0"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="['wt'].includes(column.dataIndex)">
|
||||
<a-input-number
|
||||
v-model:value="editingData[column.dataIndex]"
|
||||
style="width: 100%"
|
||||
@ -157,7 +174,8 @@
|
||||
|
||||
<!-- 是否鱼苗 -->
|
||||
<template v-else-if="column.dataIndex === 'isfs'">
|
||||
<a-radio-group v-model:value="editingData.isfs">
|
||||
<a-radio-group v-model:value="editingData.isfs"
|
||||
@change="(val) => delWarning(val,'isfs')">
|
||||
<a-radio :value="1">是</a-radio>
|
||||
<a-radio :value="0">否</a-radio>
|
||||
</a-radio-group>
|
||||
@ -198,25 +216,29 @@
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-else-if="column.dataIndex === 'picpth'"
|
||||
>
|
||||
<template v-else-if="column.dataIndex === 'picpth'">
|
||||
<div class="preview" v-for="(item, index) in record.picpthList">
|
||||
<div class="text" :class="{'text_warning': record.picpthsWarnings.includes(item.name)}" @click="emit('preview-click', record, 'image' ,index)">
|
||||
<div
|
||||
class="text"
|
||||
:class="{ text_warning: record.picpthsWarnings.includes(item.name) }"
|
||||
@click="emit('preview-click', record, 'image', index)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="record.picpthList.length==0">暂无图片</div>
|
||||
<div v-if="record.picpthList.length == 0">暂无图片</div>
|
||||
</template>
|
||||
<template
|
||||
v-else-if="column.dataIndex === 'vdpth'"
|
||||
>
|
||||
<div class="preview" v-for="(item, index) in record.vdpthList">
|
||||
<div class="text" :class="{'text_warning': record.vdpthsWarnings.includes(item.name)}" @click="emit('preview-click', record, 'vdpth' ,index)">
|
||||
<template v-else-if="column.dataIndex === 'vdpth'">
|
||||
<div class="preview" v-for="(item, index) in record.vdpthList">
|
||||
<div
|
||||
class="text"
|
||||
:class="{ text_warning: record.vdpthsWarnings.includes(item.name) }"
|
||||
@click="emit('preview-click', record, 'video', index)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="record.vdpthList.length==0">暂无视频</div>
|
||||
<div v-if="record.vdpthList.length == 0">暂无视频</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -228,8 +250,6 @@ import { message, Tag } from "ant-design-vue";
|
||||
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
||||
import fishSearch from "@/components/fishSearch/index.vue";
|
||||
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from "@/api/select";
|
||||
import { CloseCircleOutlined } from "@ant-design/icons-vue";
|
||||
import { es } from "element-plus/es/locale/index.mjs";
|
||||
|
||||
const props: any = defineProps({
|
||||
fileTableData: { type: Array, default: () => [] },
|
||||
@ -269,12 +289,25 @@ const modalColumns = ref([
|
||||
title: "过鱼设施名称",
|
||||
width: 150,
|
||||
},
|
||||
{ dataIndex: "strdt", key: "strdt", title: "过鱼时间", width: 190 },
|
||||
{ dataIndex: "ftpName", key: "ftpName", title: "鱼种类", width: 120 },
|
||||
{
|
||||
dataIndex: "strdt",
|
||||
key: "strdt",
|
||||
dataIndexKey: "strdt",
|
||||
title: "过鱼时间",
|
||||
width: 190,
|
||||
},
|
||||
{
|
||||
dataIndex: "ftpName",
|
||||
key: "ftpName",
|
||||
dataIndexKey: "ftp",
|
||||
title: "鱼种类",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: "isfs",
|
||||
key: "isfs",
|
||||
title: "是否鱼苗",
|
||||
dataIndexKey: "isfs",
|
||||
width: 130,
|
||||
customRender: ({ text }: any) => {
|
||||
const isYes = text === 1 || text === "1";
|
||||
@ -285,13 +318,20 @@ const modalColumns = ref([
|
||||
},
|
||||
{
|
||||
dataIndex: "direction",
|
||||
dataIndexKey: "direction",
|
||||
key: "direction",
|
||||
title: "游向",
|
||||
width: 120,
|
||||
customRender: ({ text }: any) => props.direction.find((item: any) => item.itemCode === text)?.dictName || "-"
|
||||
,
|
||||
customRender: ({ text }: any) =>
|
||||
props.direction.find((item: any) => item.itemCode === text)?.dictName || "-",
|
||||
},
|
||||
{
|
||||
dataIndex: "fcnt",
|
||||
key: "fcnt",
|
||||
dataIndexKey: "fcnt",
|
||||
title: "过鱼数量(尾)",
|
||||
width: 120,
|
||||
},
|
||||
{ dataIndex: "fcnt", key: "fcnt", title: "过鱼数量(尾)", width: 120 },
|
||||
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 160 },
|
||||
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 160 },
|
||||
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
||||
@ -335,25 +375,23 @@ const ensureRowState = (index: number) => {
|
||||
};
|
||||
|
||||
// --- 级联逻辑 (操作 editingData) ---
|
||||
|
||||
const handleBaseChange = async (baseId: string, index: number) => {
|
||||
console.log(baseId);
|
||||
const handleBaseChange = async (
|
||||
baseId: string,
|
||||
index: number,
|
||||
type: string = "start"
|
||||
) => {
|
||||
const state = ensureRowState(index);
|
||||
editingData.value.baseName = baseOptions.value.find(
|
||||
(item: any) => item.baseid == baseId
|
||||
)?.basename;
|
||||
if (baseId && editingData.value._warnings) {
|
||||
editingData.value._warnings = editingData.value._warnings.filter(
|
||||
(w: string) => w !== "baseName"
|
||||
);
|
||||
}
|
||||
const state = ensureRowState(index);
|
||||
delWarning(baseId, "baseId");
|
||||
// 清空后续字段
|
||||
editingData.value.rstcd = undefined;
|
||||
editingData.value.stcd = undefined;
|
||||
state.engOptions = [];
|
||||
state.fpssOptions = [];
|
||||
|
||||
if (!baseId) return;
|
||||
if (type != "start") {
|
||||
editingData.value.rstcd = undefined;
|
||||
editingData.value.stcd = undefined;
|
||||
state.engOptions = [];
|
||||
state.fpssOptions = [];
|
||||
}
|
||||
state.engLoading = true;
|
||||
try {
|
||||
const res = await getEngInfoDropdown({ baseId });
|
||||
@ -365,20 +403,16 @@ const handleBaseChange = async (baseId: string, index: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleEngChange = async (rstcd: string, index: number) => {
|
||||
const handleEngChange = async (rstcd: string, index: number, type: string = "start") => {
|
||||
const state = ensureRowState(index);
|
||||
if (rstcd && editingData.value._warnings) {
|
||||
editingData.value._warnings = editingData.value._warnings.filter(
|
||||
(w: string) => w !== "ennm"
|
||||
);
|
||||
editingData.value.ennm = state.engOptions.find(
|
||||
(item: any) => item.stcd === rstcd
|
||||
)?.ennm;
|
||||
delWarning(rstcd, "rstcd");
|
||||
if (type != "start") {
|
||||
editingData.value.stcd = undefined;
|
||||
state.fpssOptions = [];
|
||||
}
|
||||
editingData.value.ennm = state.engOptions.find(
|
||||
(item: any) => item.stcd === rstcd
|
||||
)?.ennm;
|
||||
editingData.value.stcd = undefined;
|
||||
state.fpssOptions = [];
|
||||
|
||||
if (!rstcd || !editingData.value.baseId) return;
|
||||
state.fpssLoading = true;
|
||||
try {
|
||||
const res = await getFpssDropdown({ rstcd, baseId: editingData.value.baseId });
|
||||
@ -391,18 +425,35 @@ const handleEngChange = async (rstcd: string, index: number) => {
|
||||
};
|
||||
const handleFpssChange = (stcd: string, index: number) => {
|
||||
const state = ensureRowState(index);
|
||||
if (stcd && editingData.value._warnings) {
|
||||
editingData.value._warnings = editingData.value._warnings.filter(
|
||||
(w: string) => w !== "stnm"
|
||||
);
|
||||
}
|
||||
delWarning(stcd, "stcd");
|
||||
editingData.value.stnm = state.fpssOptions.find(
|
||||
(item: any) => item.stcd === stcd
|
||||
)?.stnm;
|
||||
};
|
||||
|
||||
// --- 编辑控制 ---
|
||||
// 消除警告 / 添加警告
|
||||
const delWarning = (val: any, key: string) => {
|
||||
// 确保 _warnings 数组存在
|
||||
if (!editingData.value._warnings) {
|
||||
editingData.value._warnings = [];
|
||||
}
|
||||
|
||||
const warnings = editingData.value._warnings;
|
||||
const hasWarning = warnings.includes(key);
|
||||
|
||||
if (val !== null && val !== undefined && val !== '') {
|
||||
// 1. 如果有值,且存在警告,则移除警告
|
||||
if (hasWarning) {
|
||||
editingData.value._warnings = warnings.filter((w: string) => w !== key);
|
||||
}
|
||||
} else {
|
||||
// 2. 如果值为空 (null/undefined/''),且不存在警告,则添加警告
|
||||
if (!hasWarning) {
|
||||
editingData.value._warnings.push(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
// --- 编辑控制 ---
|
||||
const isEditing = (index: number) => editingRowIndex.value === index;
|
||||
const startEdit = (index: number) => {
|
||||
const originalRecord = props.fileTableData[index];
|
||||
@ -416,11 +467,20 @@ const startEdit = (index: number) => {
|
||||
editingRowIndex.value = index;
|
||||
|
||||
// 3. 预加载下拉选项 (基于 editingData 的值)
|
||||
if (editingData.value.baseId && !editingData.value.rstcd) {
|
||||
handleBaseChange(editingData.value.baseId, index);
|
||||
} else if (editingData.value.baseId && editingData.value.rstcd) {
|
||||
handleBaseChange(editingData.value.baseId, index).then(() => {
|
||||
handleEngChange(editingData.value.rstcd, index);
|
||||
console.log(editingData.value.baseId);
|
||||
if (editingData.value.baseId == "" || editingData.value.baseId == undefined) {
|
||||
console.log(editingData.value.rstcd);
|
||||
if (editingData.value.rstcd) {
|
||||
handleBaseChange("", index, "start").then(() => {
|
||||
handleEngChange(editingData.value.rstcd, index, "start");
|
||||
});
|
||||
} else {
|
||||
handleEngChange("", index, "start");
|
||||
}
|
||||
} else if (editingData.value.baseId != "" && editingData.value.baseId != undefined) {
|
||||
console.log(2);
|
||||
handleBaseChange(editingData.value.baseId, index, "start").then(() => {
|
||||
handleEngChange(editingData.value.rstcd, index, "start");
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -515,9 +575,9 @@ const handlePreviewDelete = (index: number) => {
|
||||
// 鱼种类编辑 修改名称
|
||||
const handleFtpChange = (val: any, opt: any) => {
|
||||
editingData.value.ftpName = opt.name;
|
||||
delWarning(val, "ftp");
|
||||
};
|
||||
|
||||
|
||||
// --- 辅助函数 ---
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
|
||||
@ -128,6 +128,7 @@
|
||||
:loading="submitLoading"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
@preview-click="handlePreviewClick"
|
||||
/>
|
||||
|
||||
<!-- 媒体预览 Modal -->
|
||||
@ -137,6 +138,7 @@
|
||||
:footer="null"
|
||||
width="900px"
|
||||
@cancel="closeMediaPreview"
|
||||
z-index="2000"
|
||||
>
|
||||
<div class="flex h-[60vh] gap-4">
|
||||
<!-- 左侧:混合列表 (图片+视频) -->
|
||||
@ -149,9 +151,12 @@
|
||||
@click="currentMediaIndex = index"
|
||||
>
|
||||
<span class="file-name">{{ item.name }}</span>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<div class="list-item-delete" @click.stop="handleDeleteMedia(item, index)">
|
||||
<div
|
||||
class="list-item-delete"
|
||||
v-if="item.type != 'formVideo' && item.type != 'formImage'"
|
||||
@click.stop="handleDeleteMedia(item, index)"
|
||||
>
|
||||
<CloseCircleOutlined />
|
||||
</div>
|
||||
</div>
|
||||
@ -166,17 +171,16 @@
|
||||
v-if="
|
||||
currentMediaItem &&
|
||||
currentMediaItem.url != '' &&
|
||||
currentMediaItem.type === 'image'
|
||||
(currentMediaItem.type === 'image' || currentMediaItem.type === 'formImage')
|
||||
"
|
||||
:src="currentMediaItem.url"
|
||||
class="max-w-full max-h-full object-contain"
|
||||
:preview="{ visible: false }"
|
||||
/>
|
||||
<div
|
||||
v-else-if="
|
||||
currentMediaItem &&
|
||||
currentMediaItem.url == '' &&
|
||||
currentMediaItem.type === 'image'
|
||||
(currentMediaItem.type === 'image' || currentMediaItem.type === 'formImage')
|
||||
"
|
||||
class="text-gray-400"
|
||||
>
|
||||
@ -188,7 +192,7 @@
|
||||
v-else-if="
|
||||
currentMediaItem &&
|
||||
currentMediaItem.url != '' &&
|
||||
currentMediaItem.type === 'video'
|
||||
(currentMediaItem.type === 'video' || currentMediaItem.type === 'formVideo')
|
||||
"
|
||||
:src="currentMediaItem.url"
|
||||
controls
|
||||
@ -201,7 +205,7 @@
|
||||
v-else-if="
|
||||
currentMediaItem &&
|
||||
currentMediaItem.url == '' &&
|
||||
currentMediaItem.type === 'video'
|
||||
(currentMediaItem.type === 'video' || currentMediaItem.type === 'formVideo')
|
||||
"
|
||||
class="text-gray-400"
|
||||
>
|
||||
@ -240,6 +244,7 @@ import BasicTable from "@/components/BasicTable/index.vue";
|
||||
import GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
|
||||
import GuoYuSheShiShuJuTianBaoTable from "./guoYuSheShiShuJuTianBaoTable.vue";
|
||||
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
|
||||
import { checkPerm } from "@/directive/permission";
|
||||
|
||||
import {
|
||||
getFishDraftPage,
|
||||
@ -261,7 +266,7 @@ import { getDictItemsByCode } from "@/api/dict";
|
||||
import dayjs from "dayjs";
|
||||
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
|
||||
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
|
||||
// --- 类型定义 ---
|
||||
interface FormData {
|
||||
[key: string]: any;
|
||||
@ -353,7 +358,7 @@ const submitLoading = ref(false);
|
||||
const mediaPreviewVisible = ref(false);
|
||||
const videoPreviewTitle = ref("视频预览");
|
||||
interface MediaItem {
|
||||
type: "image" | "video";
|
||||
type: "image" | "video" | "formVideo" | "formImage";
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
@ -412,6 +417,7 @@ const columns = computed(() => {
|
||||
// --- 业务逻辑方法 ---
|
||||
|
||||
const handleAdd = () => {
|
||||
isView.value = false;
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
@ -552,13 +558,14 @@ const handleReject = (id: any) => {
|
||||
};
|
||||
// 多选禁用
|
||||
const getCheckboxProps = (record: any) => {
|
||||
console.log(checkPerm(["sjtb:edit-review"]));
|
||||
return {
|
||||
disabled: ['SUBMITTED', 'APPROVED'].includes(record.status),
|
||||
disabled: ["SUBMITTED", "APPROVED"].includes(record.status),
|
||||
};
|
||||
};
|
||||
const handleDataLoaded = (params: any, data: any) => {
|
||||
console.log(params, data);
|
||||
return
|
||||
return;
|
||||
};
|
||||
// 多选
|
||||
const handleSelectionChange = (keys: any) => {
|
||||
@ -652,10 +659,40 @@ const handleModalOk = () => {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < fileTableData.value.length; i++) {
|
||||
// if (fileTableData.value[i]._warnings?.length > 0) {
|
||||
// message.warning("请检查数据,标红部分数据有误!");
|
||||
// return;
|
||||
// }
|
||||
if (fileTableData.value[i]._warnings?.length > 0) {
|
||||
if (fileTableData.value[i]._warnings.includes("baseId")) {
|
||||
message.warning("请检查流域,流域填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("rstcd")) {
|
||||
message.warning("请检查电站,电站填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("stcd")) {
|
||||
message.warning("请检查过鱼设施,过鱼设施填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("strdt")) {
|
||||
message.warning("请检查过鱼时间,过鱼时间填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("ftp")) {
|
||||
message.warning("请检查鱼种类,鱼种类填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("direction")) {
|
||||
message.warning("请检查游向,游向填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("isfs")) {
|
||||
message.warning("请检查是否鱼苗,是否鱼苗填写有误!");
|
||||
return;
|
||||
}
|
||||
if (fileTableData.value[i]._warnings.includes("fcnt")) {
|
||||
message.warning("请检查过鱼数量,过鱼数量填写有误!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fileTableData.value[i].picpthsWarnings?.length > 0) {
|
||||
message.warning("请检查图片,图片路径有误!");
|
||||
return;
|
||||
@ -800,10 +837,16 @@ const fileTableaAnalysis = (res: any, type: string) => {
|
||||
let data = [];
|
||||
let list = [];
|
||||
if (type == "file") {
|
||||
list = res.data.failedRows;
|
||||
list = res.data.failedRows.concat(res.data.successRows);
|
||||
} else {
|
||||
list = res.data.result.failedRowDetails;
|
||||
list = res.data.result.failedRowDetails.concat(res.data.result.successRowDetails);
|
||||
}
|
||||
list.sort((a: any, b: any) => {
|
||||
const keyA = a.rowIndex !== undefined && a.rowIndex !== null ? Number(a.rowIndex) : -1;
|
||||
const keyB = b.rowIndex !== undefined && b.rowIndex !== null ? Number(b.rowIndex) : -1;
|
||||
return keyA - keyB;
|
||||
});
|
||||
|
||||
list.forEach((item) => {
|
||||
data.push({
|
||||
...item.data,
|
||||
@ -827,7 +870,9 @@ const customTransform = (res: any) => {
|
||||
const modifiedRecords = rawRecords.map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
picpthList: item.picpth ? item.picpth.split(",").map((item: string) => baseUrl + "/?" + item) || [] : [],
|
||||
picpthList: item.picpth
|
||||
? item.picpth.split(",").map((item: string) => baseUrl + "/?" + item) || []
|
||||
: [],
|
||||
};
|
||||
});
|
||||
return {
|
||||
@ -896,9 +941,10 @@ const handleSearchFinish = (values: any) => {
|
||||
};
|
||||
// 处理预览点击 (由子组件触发)
|
||||
const handlePreviewClick = (record: any, type: string, index: number) => {
|
||||
console.log(record, type);
|
||||
const mixedList: MediaItem[] = [];
|
||||
tablePreviewRecord.value = record;
|
||||
if (type === "image") {
|
||||
tablePreviewRecord.value = record;
|
||||
videoPreviewTitle.value = "图片预览";
|
||||
const nameList = record.picpthList;
|
||||
nameList.forEach((item: any) => {
|
||||
@ -908,7 +954,8 @@ const handlePreviewClick = (record: any, type: string, index: number) => {
|
||||
url: item.value ? `${baseUrl}/?${item.value}` : "",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
} else if (type === "video") {
|
||||
tablePreviewRecord.value = record;
|
||||
videoPreviewTitle.value = "视频预览";
|
||||
const nameList = record.vdpthList;
|
||||
nameList.forEach((item: any) => {
|
||||
@ -918,10 +965,31 @@ const handlePreviewClick = (record: any, type: string, index: number) => {
|
||||
url: item.value ? `${baseUrl}/?${item.value}` : "",
|
||||
});
|
||||
});
|
||||
} else if (type === "formImage") {
|
||||
videoPreviewTitle.value = "图片预览";
|
||||
const nameList = JSON.parse(JSON.stringify(record)).picpthList;
|
||||
nameList.forEach((item: any) => {
|
||||
mixedList.push({
|
||||
type: "formImage",
|
||||
name: item.name, // 视频通常没有单独的名称字段,可根据需要调整
|
||||
url: item.url,
|
||||
});
|
||||
});
|
||||
} else if (type === "formVideo") {
|
||||
videoPreviewTitle.value = "视频预览";
|
||||
const nameList = JSON.parse(JSON.stringify(record)).vdpthList;
|
||||
nameList.forEach((item: any) => {
|
||||
mixedList.push({
|
||||
type: "formVideo",
|
||||
name: item.name, // 视频通常没有单独的名称字段,可根据需要调整
|
||||
url: item.url,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
mediaPreviewVisible.value = true;
|
||||
currentMediaIndex.value = index;
|
||||
console.log(mixedList);
|
||||
nextTick(() => {
|
||||
previewList.value = mixedList;
|
||||
});
|
||||
@ -945,6 +1013,7 @@ const handleDeleteMedia = (item: any, index: number) => {
|
||||
Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "确定要从预览列表中移除该项吗?",
|
||||
zIndex: 2002,
|
||||
onOk: () => {
|
||||
previewList.value.splice(index, 1);
|
||||
console.log(previewList.value);
|
||||
|
||||
@ -25,9 +25,9 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
||||
proxy: {
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
// 线上API地址
|
||||
// target: 'http://localhost:8093/',
|
||||
target: env.VITE_APP_BASE_URL,
|
||||
// 本地API地址
|
||||
target: 'http://10.84.121.21:8093',
|
||||
// target: 'http://10.84.121.21:8093',
|
||||
changeOrigin: true,
|
||||
rewrite: path =>
|
||||
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user