|
@@ -131,12 +131,15 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup name="Product" lang="ts">
|
|
<script setup name="Product" lang="ts">
|
|
|
|
|
+import { getCurrentInstance, reactive, ref, toRefs, watch, onMounted } from 'vue';
|
|
|
|
|
+import type { ComponentInternalInstance } from 'vue';
|
|
|
import { addProduct, delProduct, getProduct, listProduct, updateProduct, deletePhysicalProductImageByOsId } from '@/api/system/physical/product';
|
|
import { addProduct, delProduct, getProduct, listProduct, updateProduct, deletePhysicalProductImageByOsId } from '@/api/system/physical/product';
|
|
|
import { ProductForm, ProductQuery, ProductVO } from '@/api/system/physical/product/types';
|
|
import { ProductForm, ProductQuery, ProductVO } from '@/api/system/physical/product/types';
|
|
|
import { selectAllPhysicalTagsSelList } from '@/api/system/physical/tag';
|
|
import { selectAllPhysicalTagsSelList } from '@/api/system/physical/tag';
|
|
|
import { selectPhysicalStoreSelList } from '@/api/system/physical/store';
|
|
import { selectPhysicalStoreSelList } from '@/api/system/physical/store';
|
|
|
import { listByIds } from '@/api/system/oss';
|
|
import { listByIds } from '@/api/system/oss';
|
|
|
import { parseTime } from '@/utils/dateUtils';
|
|
import { parseTime } from '@/utils/dateUtils';
|
|
|
|
|
+
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
|
|
|
const productList = ref<ProductVO[]>([]);
|
|
const productList = ref<ProductVO[]>([]);
|
|
@@ -248,10 +251,10 @@ const handleUpdate = async (row?: ProductVO) => {
|
|
|
const _id = row?.id || ids.value[0];
|
|
const _id = row?.id || ids.value[0];
|
|
|
const res = await getProduct(_id);
|
|
const res = await getProduct(_id);
|
|
|
Object.assign(form.value, res.data);
|
|
Object.assign(form.value, res.data);
|
|
|
- // 处理商品图片 (productImagesOsId)
|
|
|
|
|
- if (res.data.productImages && Array.isArray(res.data.productImages)) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const processImages = async (images: any[]) => {
|
|
|
const imageUrls = await Promise.all(
|
|
const imageUrls = await Promise.all(
|
|
|
- res.data.productImages.map(async (image) => {
|
|
|
|
|
|
|
+ images.map(async (image) => {
|
|
|
try {
|
|
try {
|
|
|
const res = await getIds(image.osId);
|
|
const res = await getIds(image.osId);
|
|
|
const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
@@ -266,39 +269,24 @@ const handleUpdate = async (row?: ProductVO) => {
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
);
|
|
);
|
|
|
- const validImageUrls = imageUrls.filter((item) => item.url !== '');
|
|
|
|
|
- // 将有效的 URL 字符串数组赋值给 form 字段
|
|
|
|
|
- // 注意:这里应该传递 osId 字符串,让 ImageUpload 内部去解析
|
|
|
|
|
- // 修正:传递 osId 列表,而不是 URL 列表
|
|
|
|
|
- form.value.productImagesOsId = validImageUrls.map((item) => item.ossId).join(',');
|
|
|
|
|
|
|
+ return imageUrls
|
|
|
|
|
+ .filter((item) => item.url !== '')
|
|
|
|
|
+ .map((item) => item.ossId)
|
|
|
|
|
+ .join(',');
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data.productImages && Array.isArray(res.data.productImages)) {
|
|
|
|
|
+ form.value.productImagesOsId = await processImages(res.data.productImages);
|
|
|
} else {
|
|
} else {
|
|
|
form.value.productImagesOsId = [];
|
|
form.value.productImagesOsId = [];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 处理详情图片 (productDetailImgOsId),逻辑类似
|
|
|
|
|
if (res.data.productDetailImg && Array.isArray(res.data.productDetailImg)) {
|
|
if (res.data.productDetailImg && Array.isArray(res.data.productDetailImg)) {
|
|
|
- const detailImageUrls = await Promise.all(
|
|
|
|
|
- res.data.productDetailImg.map(async (image) => {
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await getIds(image.osId);
|
|
|
|
|
- const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
|
|
|
- return {
|
|
|
|
|
- url: firstItem?.url || firstItem?.picUrl,
|
|
|
|
|
- ossId: image.osId,
|
|
|
|
|
- name: image.osId
|
|
|
|
|
- };
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('获取详情图片URL失败:', error);
|
|
|
|
|
- return { url: '', ossId: '' };
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
- const validDetailImageUrls = detailImageUrls.filter((item) => item.url !== '');
|
|
|
|
|
- // 同样传递 osId 列表
|
|
|
|
|
- form.value.productDetailImgOsId = validDetailImageUrls.map((item) => item.ossId).join(',');
|
|
|
|
|
|
|
+ form.value.productDetailImgOsId = await processImages(res.data.productDetailImg);
|
|
|
} else {
|
|
} else {
|
|
|
form.value.productDetailImgOsId = [];
|
|
form.value.productDetailImgOsId = [];
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
dialog.visible = true;
|
|
dialog.visible = true;
|
|
|
dialog.title = '修改商品';
|
|
dialog.title = '修改商品';
|
|
|
};
|
|
};
|
|
@@ -307,52 +295,26 @@ const submitForm = () => {
|
|
|
productFormRef.value?.validate(async (valid: boolean) => {
|
|
productFormRef.value?.validate(async (valid: boolean) => {
|
|
|
if (valid) {
|
|
if (valid) {
|
|
|
buttonLoading.value = true;
|
|
buttonLoading.value = true;
|
|
|
- // 处理多个 osId 的情况
|
|
|
|
|
- if (form.value.productImagesOsId) {
|
|
|
|
|
- const osIds = form.value.productImagesOsId
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const processOsIds = async (osIdString: any, imageType: string) => {
|
|
|
|
|
+ if (!osIdString) return [];
|
|
|
|
|
+ const osIds = osIdString
|
|
|
.toString()
|
|
.toString()
|
|
|
.split(',')
|
|
.split(',')
|
|
|
- .map((id) => id.trim());
|
|
|
|
|
- // 创建一个数组来存储所有图片信息
|
|
|
|
|
|
|
+ .map((id: string) => id.trim());
|
|
|
const imageList = [];
|
|
const imageList = [];
|
|
|
for (const osId of osIds) {
|
|
for (const osId of osIds) {
|
|
|
const res = await getIds(osId);
|
|
const res = await getIds(osId);
|
|
|
const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
|
const picUrl = firstItem?.url || firstItem?.picUrl;
|
|
const picUrl = firstItem?.url || firstItem?.picUrl;
|
|
|
- // 将每个图片信息添加到列表中
|
|
|
|
|
- imageList.push({
|
|
|
|
|
- osId: osId,
|
|
|
|
|
- imageUrl: picUrl,
|
|
|
|
|
- imageType: 'SHOW'
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ imageList.push({ osId, imageUrl: picUrl, imageType });
|
|
|
}
|
|
}
|
|
|
- // 将图片列表赋值给表单
|
|
|
|
|
- form.value.productImages = imageList;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return imageList;
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- if (form.value.productDetailImgOsId) {
|
|
|
|
|
- const osIds = form.value.productDetailImgOsId
|
|
|
|
|
- .toString()
|
|
|
|
|
- .split(',')
|
|
|
|
|
- .map((id) => id.trim());
|
|
|
|
|
- // 创建一个数组来存储所有图片信息
|
|
|
|
|
- const imageList2 = [];
|
|
|
|
|
- for (const osId of osIds) {
|
|
|
|
|
- const res = await getIds(osId);
|
|
|
|
|
- const firstItem = Array.isArray(res) ? res[0] : res.data?.[0] || res[0];
|
|
|
|
|
- const picUrl = firstItem?.url || firstItem?.picUrl;
|
|
|
|
|
- // 将每个图片信息添加到列表中
|
|
|
|
|
- imageList2.push({
|
|
|
|
|
- osId: osId,
|
|
|
|
|
- imageUrl: picUrl,
|
|
|
|
|
- imageType: 'DETAIL'
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- // 将图片列表赋值给表单
|
|
|
|
|
- form.value.productDetailImg = imageList2;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ form.value.productImages = await processOsIds(form.value.productImagesOsId, 'SHOW');
|
|
|
|
|
+ form.value.productDetailImg = await processOsIds(form.value.productDetailImgOsId, 'DETAIL');
|
|
|
|
|
|
|
|
- // 提交数据
|
|
|
|
|
if (form.value.id) {
|
|
if (form.value.id) {
|
|
|
await updateProduct(form.value).finally(() => (buttonLoading.value = false));
|
|
await updateProduct(form.value).finally(() => (buttonLoading.value = false));
|
|
|
} else {
|
|
} else {
|
|
@@ -372,7 +334,7 @@ const getIds = async (ids: string | number) => {
|
|
|
/** 删除按钮操作 */
|
|
/** 删除按钮操作 */
|
|
|
const handleDelete = async (row?: ProductVO) => {
|
|
const handleDelete = async (row?: ProductVO) => {
|
|
|
const _ids = row?.id || ids.value;
|
|
const _ids = row?.id || ids.value;
|
|
|
- await proxy?.$modal.confirm('是否确认删除商品编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
|
|
|
|
|
|
+ await proxy?.$modal.confirm(`是否确认删除商品编号为"${_ids}"的数据项?`).finally(() => (loading.value = false));
|
|
|
await delProduct(_ids);
|
|
await delProduct(_ids);
|
|
|
proxy?.$modal.msgSuccess('删除成功');
|
|
proxy?.$modal.msgSuccess('删除成功');
|
|
|
await getList();
|
|
await getList();
|
|
@@ -389,44 +351,16 @@ const handleExport = () => {
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
const itemOptionsType = ref<{ id: number; label: string }[]>([]);
|
|
const itemOptionsType = ref<{ id: number; label: string }[]>([]);
|
|
|
-const loadItemStructuresOptions = async () => {
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await selectAllPhysicalTagsSelList();
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- // 使用 unknown 中间类型进行类型转换
|
|
|
|
|
- const data = res.data as unknown as { id: number; serviceName: string }[];
|
|
|
|
|
- const list = [];
|
|
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
|
|
- const item = data[i];
|
|
|
|
|
- list.push({
|
|
|
|
|
- id: item.id,
|
|
|
|
|
- label: item.serviceName
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- itemOptionsType.value = list;
|
|
|
|
|
- } else {
|
|
|
|
|
- alert('加载失败:' + res.msg);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('请求出错:', error);
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
const itemOptionsStore = ref<{ id: number; label: string }[]>([]);
|
|
const itemOptionsStore = ref<{ id: number; label: string }[]>([]);
|
|
|
-const loadStoreOptions = async () => {
|
|
|
|
|
|
|
+
|
|
|
|
|
+const loadOptions = async (apiFunc: () => Promise<any>, targetRef: any, labelKey: string = 'serviceName') => {
|
|
|
try {
|
|
try {
|
|
|
- const res = await selectPhysicalStoreSelList();
|
|
|
|
|
|
|
+ const res = await apiFunc();
|
|
|
if (res.code === 200) {
|
|
if (res.code === 200) {
|
|
|
- // 使用 unknown 中间类型进行类型转换
|
|
|
|
|
- const data = res.data as unknown as { id: number; serviceName: string }[];
|
|
|
|
|
- const list = [];
|
|
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
|
|
- const item = data[i];
|
|
|
|
|
- list.push({
|
|
|
|
|
- id: item.id,
|
|
|
|
|
- label: item.serviceName
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- itemOptionsStore.value = list;
|
|
|
|
|
|
|
+ targetRef.value = (res.data as unknown as any[]).map((item) => ({
|
|
|
|
|
+ id: item.id,
|
|
|
|
|
+ label: item[labelKey]
|
|
|
|
|
+ }));
|
|
|
} else {
|
|
} else {
|
|
|
alert('加载失败:' + res.msg);
|
|
alert('加载失败:' + res.msg);
|
|
|
}
|
|
}
|
|
@@ -434,24 +368,24 @@ const loadStoreOptions = async () => {
|
|
|
console.error('请求出错:', error);
|
|
console.error('请求出错:', error);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
+
|
|
|
|
|
+const loadItemStructuresOptions = () => loadOptions(selectAllPhysicalTagsSelList, itemOptionsType);
|
|
|
|
|
+const loadStoreOptions = () => loadOptions(selectPhysicalStoreSelList, itemOptionsStore);
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
getList();
|
|
getList();
|
|
|
loadItemStructuresOptions();
|
|
loadItemStructuresOptions();
|
|
|
loadStoreOptions();
|
|
loadStoreOptions();
|
|
|
});
|
|
});
|
|
|
-// 在 setup 中添加 watch
|
|
|
|
|
|
|
+
|
|
|
watch(
|
|
watch(
|
|
|
() => form.value.productImagesOsId,
|
|
() => form.value.productImagesOsId,
|
|
|
(newVal, oldVal) => {
|
|
(newVal, oldVal) => {
|
|
|
- console.log('商品图片已更新:', newVal);
|
|
|
|
|
- // 将 oldVal 和 newVal 转换为字符串数组
|
|
|
|
|
const oldIds = Array.isArray(oldVal) ? oldVal : oldVal?.split(',') || [];
|
|
const oldIds = Array.isArray(oldVal) ? oldVal : oldVal?.split(',') || [];
|
|
|
const newIds = Array.isArray(newVal) ? newVal : newVal?.split(',') || [];
|
|
const newIds = Array.isArray(newVal) ? newVal : newVal?.split(',') || [];
|
|
|
|
|
|
|
|
if (oldIds.length > newIds.length) {
|
|
if (oldIds.length > newIds.length) {
|
|
|
const removedIds = oldIds.filter((id) => !newIds.includes(id));
|
|
const removedIds = oldIds.filter((id) => !newIds.includes(id));
|
|
|
if (removedIds.length > 0) {
|
|
if (removedIds.length > 0) {
|
|
|
- console.log('商品图片被删除:', removedIds);
|
|
|
|
|
removedIds.forEach((osId) => {
|
|
removedIds.forEach((osId) => {
|
|
|
if (osId && typeof osId === 'string' && osId.trim() !== '') {
|
|
if (osId && typeof osId === 'string' && osId.trim() !== '') {
|
|
|
deletePhysicalProductImageByOsId(osId);
|
|
deletePhysicalProductImageByOsId(osId);
|
|
@@ -466,15 +400,12 @@ watch(
|
|
|
watch(
|
|
watch(
|
|
|
() => form.value.productDetailImgOsId,
|
|
() => form.value.productDetailImgOsId,
|
|
|
(newVal, oldVal) => {
|
|
(newVal, oldVal) => {
|
|
|
- console.log('详情图片已更新:', newVal);
|
|
|
|
|
- // 将 oldVal 和 newVal 转换为字符串数组
|
|
|
|
|
const oldIds = Array.isArray(oldVal) ? oldVal : oldVal?.split(',') || [];
|
|
const oldIds = Array.isArray(oldVal) ? oldVal : oldVal?.split(',') || [];
|
|
|
const newIds = Array.isArray(newVal) ? newVal : newVal?.split(',') || [];
|
|
const newIds = Array.isArray(newVal) ? newVal : newVal?.split(',') || [];
|
|
|
|
|
|
|
|
if (oldIds.length > newIds.length) {
|
|
if (oldIds.length > newIds.length) {
|
|
|
const removedIds = oldIds.filter((id) => !newIds.includes(id));
|
|
const removedIds = oldIds.filter((id) => !newIds.includes(id));
|
|
|
if (removedIds.length > 0) {
|
|
if (removedIds.length > 0) {
|
|
|
- console.log('详情图片被删除:', removedIds);
|
|
|
|
|
removedIds.forEach((osId) => {
|
|
removedIds.forEach((osId) => {
|
|
|
if (osId && typeof osId === 'string' && osId.trim() !== '') {
|
|
if (osId && typeof osId === 'string' && osId.trim() !== '') {
|
|
|
deletePhysicalProductImageByOsId(osId);
|
|
deletePhysicalProductImageByOsId(osId);
|
|
@@ -485,84 +416,6 @@ watch(
|
|
|
},
|
|
},
|
|
|
{ deep: true }
|
|
{ deep: true }
|
|
|
);
|
|
);
|
|
|
-
|
|
|
|
|
-/*const imageFileList = ref([]);
|
|
|
|
|
-const imageUrls = ref([]);
|
|
|
|
|
-/!** 处理图片上传 *!/
|
|
|
|
|
-const handleImageChange = async (file, fileList) => {
|
|
|
|
|
- imageFileList.value = fileList;
|
|
|
|
|
- // 为新上传的文件生成预览
|
|
|
|
|
- if (file.raw) {
|
|
|
|
|
- try {
|
|
|
|
|
- const rawFile = file.raw;
|
|
|
|
|
- const res = await uploadTournament(rawFile);
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- // 更新文件状态为成功并保存URL
|
|
|
|
|
- const index = imageFileList.value.findIndex((f) => f.uid === file.uid);
|
|
|
|
|
- if (index !== -1) {
|
|
|
|
|
- imageFileList.value[index] = {
|
|
|
|
|
- ...file,
|
|
|
|
|
- status: 'success',
|
|
|
|
|
- response: res.data.url,
|
|
|
|
|
- url: res.data.url
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 更新 imageUrls 数组
|
|
|
|
|
- updateImageUrls();
|
|
|
|
|
- }
|
|
|
|
|
- proxy?.$modal.msgSuccess('上传成功');
|
|
|
|
|
- } else {
|
|
|
|
|
- throw new Error(res.msg);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- // 更新文件状态为失败
|
|
|
|
|
- const index = imageFileList.value.findIndex((f) => f.uid === file.uid);
|
|
|
|
|
- if (index !== -1) {
|
|
|
|
|
- imageFileList.value[index] = {
|
|
|
|
|
- ...file,
|
|
|
|
|
- status: 'fail',
|
|
|
|
|
- error: '上传失败'
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- proxy?.$modal.msgError('上传失败,请重试');
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // 对于已有文件,直接更新 URLs
|
|
|
|
|
- updateImageUrls();
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-/!** 处理图片删除 *!/
|
|
|
|
|
-const handleImageRemove = (file, fileList) => {
|
|
|
|
|
- imageFileList.value = fileList;
|
|
|
|
|
- // 更新图片 URLs 数组
|
|
|
|
|
- updateImageUrls();
|
|
|
|
|
-
|
|
|
|
|
- // 同步到 form 数据
|
|
|
|
|
- if (form.value.productImagesOsId) {
|
|
|
|
|
- const osIds = form.value.productImagesOsId
|
|
|
|
|
- .toString()
|
|
|
|
|
- .split(',')
|
|
|
|
|
- .map((id) => id.trim());
|
|
|
|
|
- const removedId = file.response || file.url;
|
|
|
|
|
-
|
|
|
|
|
- // 过滤掉被删除的图片
|
|
|
|
|
- form.value.productImagesOsId = osIds.filter((osId) => osId !== removedId);
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-/!** 图片数量超出限制 *!/
|
|
|
|
|
-const handleImageExceed = (files, fileList) => {
|
|
|
|
|
- proxy?.$modal.msgWarning('最多只能上传5张图片');
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-/!** 更新图片 URLs 数组 *!/
|
|
|
|
|
-const updateImageUrls = () => {
|
|
|
|
|
- const urls = imageFileList.value.filter((file) => file.status === 'success' || file.url).map((file) => file.response || file.url);
|
|
|
|
|
- // 确保返回的是字符串数组
|
|
|
|
|
- imageUrls.value = urls as string[];
|
|
|
|
|
- form.value.images = urls as string[];
|
|
|
|
|
-};*/
|
|
|
|
|
</script>
|
|
</script>
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
.upload-images :deep(.el-upload-list__item) {
|
|
.upload-images :deep(.el-upload-list__item) {
|