feat: 商品详情编辑

This commit is contained in:
zc 2025-11-05 11:29:11 +08:00
parent 8fc07dd9cd
commit 7099bea338
6 changed files with 136 additions and 13 deletions

View File

@ -19,9 +19,10 @@ const useUserStore = defineStore('user', {
this.$reset()
},
// 登录
onLogin(data: { tokenValue: string; tokenName: string }) {
onLogin(data: { tokenValue: string; tokenName: string; userNickName: string }) {
this.tokenValue = data.tokenValue
this.tokenName = data.tokenName
this.userNickName = data.userNickName
},
// 获取用户信息(昵称、头像、角色集合、权限集合)
getUserRoleInfo() {

View File

@ -5,6 +5,8 @@ interface PreviewItem {
type: 'image' | 'video'
}
export const curPropertyTypeImage = ref(null)
// 选择资源库图片
export const useImportFile = (fileList: Ref<PreviewItem[]>) => {
const showFileExplorer = ref(false)
@ -18,10 +20,15 @@ export const useImportFile = (fileList: Ref<PreviewItem[]>) => {
// 处理文件选择
const handleChooseResourceFileCallback = (files: PreviewItem[] = []) => {
handleChooseFiles(curFileType.value, files, fileList.value)
if (curPropertyTypeImage.value) {
curPropertyTypeImage.value.imageUrl = files[0].resourceUrl
} else {
handleChooseFiles(curFileType.value, files, fileList.value)
}
}
const onClickChooseResourceBtn = (type: 'mainImageUrl' | 'videoUrl' | 'subImageUrl') => {
curPropertyTypeImage.value = null
curFileType.value = type
showFileExplorer.value = true
}

View File

@ -21,7 +21,11 @@ export const handleGetDialogData = (
result.adminCategoryId = defaultCheckedNodes.value.admin.slice(-1)[0]
defaultCheckedNodes.value.app = [data.appCategoryId1, data.appCategoryId2]
result.isTest = data.isTest
result.isNew = data.isNew
result.isFlash = data.isFlash
result.title = data.title
result.frontPage = data.frontPage
result.status = data.status
result.feature1 = data.feature1
result.feature2 = data.feature2
result.htmlContent = data.vvProductDetailList.find((item: any) => item.type === 2)?.detail || ''
@ -86,7 +90,7 @@ export const handleGetNewAdminCategoryData = (data: any) => {
// 编辑的时候对sku进行重组
export const handleGetNewSkuList = (data: any) => {
return data.map((item: any) => {
const arr = data.map((item: any) => {
let categoryPropertyNames = ''
let name = ''
item.vvSkuPropertyValueList.forEach((child: any, index: number) => {
@ -101,4 +105,45 @@ export const handleGetNewSkuList = (data: any) => {
categoryPropertyNames
}
})
return sortByPrefix(arr)
}
/**
* name
* @param arr
* @returns
*/
export const sortByPrefix = <T extends { name?: string }>(arr: T[]): T[] => {
if (!Array.isArray(arr) || arr.length === 0) {
return arr
}
// 计算前缀:如果 name 包含 "-",取最后一个 "-" 之前的部分作为前缀
const getPrefix = (name: string): string => {
if (!name) return ''
// 找到最后一个 "-" 的位置,取之前的部分作为前缀
const lastDashIndex = name.lastIndexOf('-')
if (lastDashIndex > 0) {
return name.substring(0, lastDashIndex + 1) // 包含 "-" 分隔符
}
// 如果没有 "-",返回整个字符串
return name
}
// 创建副本并排序
return [...arr].sort((a, b) => {
const prefixA = getPrefix(a.name || '')
const prefixB = getPrefix(b.name || '')
// 先按前缀排序
const prefixCompare = prefixA.localeCompare(prefixB, 'zh-CN')
if (prefixCompare !== 0) {
return prefixCompare
}
// 如果前缀相同,再按完整的 name 排序
return (a.name || '').localeCompare(b.name || '', 'zh-CN')
})
}

View File

@ -77,9 +77,6 @@
>
</el-tree-select>
</el-form-item>
<el-form-item label="测试商品">
<el-switch v-model="$dialog.data.isTest" active-value="1" inactive-value="0" />
</el-form-item>
<el-form-item label="特色">
<div class="flex">
<el-input
@ -94,6 +91,22 @@
></el-input>
</div>
</el-form-item>
<br />
<el-form-item label="测试商品">
<el-switch v-model="$dialog.data.isTest" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="新品">
<el-switch v-model="$dialog.data.isNew" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="限时秒杀">
<el-switch v-model="$dialog.data.isFlash" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="上线">
<el-switch v-model="$dialog.data.status" active-value="online" inactive-value="down" />
</el-form-item>
<el-form-item label="加入首页">
<el-switch v-model="$dialog.data.frontPage" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item>
<el-popover
:visible="visiblePropertyLine"
@ -146,10 +159,47 @@
closable
effect="plain"
:type="colors[index % 4]"
class="mr-1"
class="mr-1 property-type-tag"
size="large"
@click="onClickPropertyValue(item, child)"
@close="onDeletePropertyValue(index, child.id)"
>{{ child.categoryPropertyValue }}</el-tag
>
<el-popover title="" placement="top-start" :width="280">
<template #reference>
<el-icon
color="#999"
class="mr-1"
v-if="!child.imageUrl"
@click.stop="onChangePropertyTypeImage(child)"
><Picture
/></el-icon>
<img
v-else
:src="child.imageUrl"
alt=""
class="w-6 h-6 mr-1"
@click.stop="onChangePropertyTypeImage(child)"
/>
</template>
<div>
<file-upload-btn
class="inline-block"
size="small"
accept="image/*"
@change="(val) => (child.imageUrl = val[0].resourceUrl)"
/>
<el-button
type="success"
size="small"
class="ml-2"
@click="(showFileExplorer = true) && (curPropertyTypeImage = child)"
>资源库导入</el-button
>
<el-button type="danger" size="small" class="ml-2" @click="child.imageUrl = ''"
>清空</el-button
>
</div> </el-popover
><span>{{ child.categoryPropertyValue }}</span></el-tag
>
</div>
<el-input
@ -233,7 +283,8 @@ import {
defaultAdminCategoryTreeProps,
defaultCheckedNodes,
fileList,
TSkuList
TSkuList,
onChangePropertyTypeImage
} from './use-method'
import {
handleGetDialogData,
@ -258,10 +309,11 @@ import categoryConfig from './category-config.vue'
import wanEditor from './editor.vue'
import fileUploadBtn from '@/components/FileUploadBtn/index.vue'
import resourceReview from '@/components/ResourceReview/index.vue'
import { useImportFile, handleChooseFiles } from './choose-file-method'
import { curPropertyTypeImage, useImportFile, handleChooseFiles } from './choose-file-method'
import FileExplorerDialog from '@/components/FileExplorerDialog/index.vue'
import { Atrans$DialogRes } from '@/utils/page/config'
import { ElMessage } from 'element-plus'
import { Picture } from '@element-plus/icons-vue'
const route = useRoute()
const $dialog = ref<Atrans$DialogRes>({} as Atrans$DialogRes)
@ -275,7 +327,11 @@ const init = async () => {
appCategoryId: '',
adminCategoryId: '',
isTest: 0,
title: ''
isNew: 0,
isFlash: 0,
title: '',
frontPage: 0,
status: 'down'
}
adminCategoryData.value = []
skuList.value = []
@ -378,5 +434,11 @@ init()
}
color: #666;
}
.property-type-tag {
:deep(.el-tag__content) {
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -319,7 +319,7 @@ export const generateSkuList = (categories: CategoryDataMock): TSkuList[] => {
return combos.map((combo) => {
const serialNo = combo.map((opt) => opt.id.toString()).join('-')
const name = combo.map((opt) => String(opt.categoryPropertyValue)).join('-')
const categoryPropertyNames = combo.map((opt) => String(opt.categoryPropertyValue)).join('-')
const categoryPropertyNames = combo.map((opt) => String(opt.categoryPropertyName)).join('-')
const originArray = combo
return {
serialNo,
@ -352,3 +352,7 @@ const generateAddSkuList = (
})
return generateSkuList(filterCategoryData)
}
export const onChangePropertyTypeImage = (child: any) => {
console.log(1111, child)
}

View File

@ -21,7 +21,11 @@ const handleLogin = () => {
if (valid) {
api.login.login.post(loginData).then((res) => {
router.push({ path: '/home' })
user.onLogin({ tokenValue: res.data.token, tokenName: 'mmToken' })
user.onLogin({
tokenValue: res.data.token,
tokenName: 'mmToken',
userNickName: res.data.username
})
})
} else {
return false