上传
This commit is contained in:
@@ -7,7 +7,7 @@ VITE_DEV=true
|
||||
VITE_BASE_URL='http://118.31.23.45:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=/dev-api
|
||||
|
||||
2
.env.dev
2
.env.dev
@@ -7,7 +7,7 @@ VITE_DEV=false
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=/dev-api
|
||||
|
||||
@@ -7,7 +7,7 @@ VITE_DEV=true
|
||||
VITE_BASE_URL='http://118.31.23.45:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://api-dashboard.yudao.iocoder.cn/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=/dev-api
|
||||
|
||||
2
.env.pro
2
.env.pro
@@ -7,7 +7,7 @@ VITE_DEV=false
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=
|
||||
|
||||
@@ -7,7 +7,7 @@ VITE_DEV=false
|
||||
VITE_BASE_URL='http://api-dashboard.yudao.iocoder.cn'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://api-dashboard.yudao.iocoder.cn/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=
|
||||
|
||||
@@ -7,7 +7,7 @@ VITE_DEV=false
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=
|
||||
|
||||
@@ -7,7 +7,7 @@ VITE_DEV=false
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
|
||||
# 上传路径
|
||||
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
|
||||
VITE_UPLOAD_URL='http://118.31.23.45:48080/admin-api/system/file/upload'
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASEPATH=
|
||||
|
||||
45
src/api/infra/file/index.ts
Normal file
45
src/api/infra/file/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export interface FilePageReqVO extends PageParam {
|
||||
path?: string
|
||||
type?: string
|
||||
createTime?: Date[]
|
||||
}
|
||||
|
||||
// 文件预签名地址 Response VO
|
||||
export interface FilePresignedUrlRespVO {
|
||||
// 文件配置编号
|
||||
configId: number
|
||||
// 文件上传 URL
|
||||
uploadUrl: string
|
||||
// 文件 URL
|
||||
url: string
|
||||
}
|
||||
|
||||
// 查询文件列表
|
||||
export const getFilePage = (params: FilePageReqVO) => {
|
||||
return request.get({ url: '/infra/file/page', params })
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
export const deleteFile = (id: number) => {
|
||||
return request.delete({ url: '/infra/file/delete?id=' + id })
|
||||
}
|
||||
|
||||
// 获取文件预签名地址
|
||||
export const getFilePresignedUrl = (path: string) => {
|
||||
return request.get<FilePresignedUrlRespVO>({
|
||||
url: '/infra/file/presigned-url',
|
||||
params: { path }
|
||||
})
|
||||
}
|
||||
|
||||
// 创建文件
|
||||
export const createFile = (data: any) => {
|
||||
return request.post({ url: '/infra/file/create', data })
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
export const updateFile = (data: any) => {
|
||||
return request.upload({ url: '/admin-api/system/file/upload', data })
|
||||
}
|
||||
@@ -32,27 +32,27 @@ export interface BrandVO {
|
||||
|
||||
// 创建商品品牌
|
||||
export const createBrand = (data: BrandVO) => {
|
||||
return request.post({ url: '/product/brand/create', data })
|
||||
return request.post({ url: '/admin-api/crm/erp-product-brand/create', data })
|
||||
}
|
||||
|
||||
// 更新商品品牌
|
||||
export const updateBrand = (data: BrandVO) => {
|
||||
return request.put({ url: '/product/brand/update', data })
|
||||
return request.put({ url: '/admin-api/crm/erp-product-brand/update', data })
|
||||
}
|
||||
|
||||
// 删除商品品牌
|
||||
export const deleteBrand = (id: number) => {
|
||||
return request.delete({ url: `/product/brand/delete?id=${id}` })
|
||||
return request.delete({ url: `/admin-api/crm/erp-product-brand/delete?id=${id}` })
|
||||
}
|
||||
|
||||
// 获得商品品牌
|
||||
export const getBrand = (id: number) => {
|
||||
return request.get({ url: `/product/brand/get?id=${id}` })
|
||||
return request.get({ url: `/admin-api/crm/erp-product-brand/get?id=${id}` })
|
||||
}
|
||||
|
||||
// 获得商品品牌列表
|
||||
export const getBrandParam = (params: PageParam) => {
|
||||
return request.get({ url: '/product/brand/page', params })
|
||||
return request.get({ url: '/admin-api/crm/erp-product-brand/page', params })
|
||||
}
|
||||
|
||||
// 获得商品品牌精简信息列表
|
||||
|
||||
@@ -36,25 +36,25 @@ export interface CategoryVO {
|
||||
|
||||
// 创建商品分类
|
||||
export const createCategory = (data: CategoryVO) => {
|
||||
return request.post({ url: '/product/category/create', data })
|
||||
return request.post({ url: '/admin-api/crm/erp-product-category/create', data })
|
||||
}
|
||||
|
||||
// 更新商品分类
|
||||
export const updateCategory = (data: CategoryVO) => {
|
||||
return request.put({ url: '/product/category/update', data })
|
||||
return request.put({ url: '/admin-api/crm/erp-product-category/update', data })
|
||||
}
|
||||
|
||||
// 删除商品分类
|
||||
export const deleteCategory = (id: number) => {
|
||||
return request.delete({ url: `/product/category/delete?id=${id}` })
|
||||
return request.delete({ url: `/admin-api/crm/erp-product-category/delete?id=${id}` })
|
||||
}
|
||||
|
||||
// 获得商品分类
|
||||
export const getCategory = (id: number) => {
|
||||
return request.get({ url: `/product/category/get?id=${id}` })
|
||||
return request.get({ url: `/admin-api/crm/erp-product-category/get?id=${id}` })
|
||||
}
|
||||
|
||||
// 获得商品分类列表
|
||||
export const getCategoryList = (params: any) => {
|
||||
return request.get({ url: '/product/category/list', params })
|
||||
return request.get({ url: '/admin-api/crm/erp-product-category/page', params })
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import request from '@/config/axios'
|
||||
// 查询列表
|
||||
export const getProductPage = async (params) => {
|
||||
return await request.get({ url: '/admin-api/crm/erp-product//page', params })
|
||||
return await request.get({ url: '/admin-api/crm/erp-product/page', params })
|
||||
}
|
||||
|
||||
// 查询详情
|
||||
export const getProduct = async (id) => {
|
||||
return await request.get({ url: '/admin-api/crm/erp-product//get?id=' + id })
|
||||
return await request.get({ url: '/admin-api/crm/erp-product/get?id=' + id })
|
||||
}
|
||||
|
||||
// 新增
|
||||
export const createProduct = async (data) => {
|
||||
return await request.post({ url: '/admin-api/crm/erp-product//create', data: data })
|
||||
return await request.post({ url: '/admin-api/crm/erp-product/create', data: data })
|
||||
}
|
||||
|
||||
// 修改
|
||||
export const updateProduct = async (params) => {
|
||||
return await request.put({ url: '/admin-api/crm/erp-product//update', data: params })
|
||||
return await request.put({ url: '/admin-api/crm/erp-product/update', data: params })
|
||||
}
|
||||
|
||||
// 删除
|
||||
export const deleteProduct = async (id) => {
|
||||
return await request.delete({ url: '/admin-api/crm/erp-product//delete?id=' + id })
|
||||
return await request.delete({ url: '/admin-api/crm/erp-product/delete?id=' + id })
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { propTypes } from '@/utils/propTypes'
|
||||
import { isNumber } from '@/utils/is'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useLocaleStore } from '@/store/modules/locale'
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth'
|
||||
import { getAccessToken, getTenantId, getAppId } from '@/utils/auth'
|
||||
|
||||
type InsertFnType = (url: string, alt: string, href: string) => void
|
||||
|
||||
@@ -103,7 +103,8 @@ const editorConfig = computed((): IEditorConfig => {
|
||||
headers: {
|
||||
Accept: '*',
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId()
|
||||
'tenant-id': getTenantId(),
|
||||
'instance-id': getAppId()
|
||||
},
|
||||
|
||||
// 跨域是否传递 cookie ,默认为 false
|
||||
@@ -140,6 +141,63 @@ const editorConfig = computed((): IEditorConfig => {
|
||||
customInsert(res: any, insertFn: InsertFnType) {
|
||||
insertFn(res.data, 'image', res.data)
|
||||
}
|
||||
},
|
||||
['uploadVideo']: {
|
||||
server: import.meta.env.VITE_UPLOAD_URL,
|
||||
// 单个文件的最大体积限制,默认为 2M
|
||||
maxFileSize: 100 * 1024 * 1024,
|
||||
// 最多可上传几个文件,默认为 100
|
||||
maxNumberOfFiles: 10,
|
||||
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
|
||||
allowedFileTypes: ['video/*'],
|
||||
|
||||
// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
|
||||
meta: { updateSupport: 0 },
|
||||
// 将 meta 拼接到 url 参数中,默认 false
|
||||
metaWithUrl: true,
|
||||
|
||||
// 自定义增加 http header
|
||||
headers: {
|
||||
Accept: '*',
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId(),
|
||||
'instance-id': getAppId()
|
||||
},
|
||||
|
||||
// 跨域是否传递 cookie ,默认为 false
|
||||
withCredentials: true,
|
||||
|
||||
// 超时时间,默认为 10 秒
|
||||
timeout: 10 * 1000, // 5 秒
|
||||
|
||||
// form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
|
||||
fieldName: 'file',
|
||||
|
||||
// 上传之前触发
|
||||
onBeforeUpload(file: File) {
|
||||
console.log(file)
|
||||
return file
|
||||
},
|
||||
// 上传进度的回调函数
|
||||
onProgress(progress: number) {
|
||||
// progress 是 0-100 的数字
|
||||
console.log('progress', progress)
|
||||
},
|
||||
onSuccess(file: File, res: any) {
|
||||
console.log('onSuccess', file, res)
|
||||
},
|
||||
onFailed(file: File, res: any) {
|
||||
alert(res.message)
|
||||
console.log('onFailed', file, res)
|
||||
},
|
||||
onError(file: File, err: any, res: any) {
|
||||
alert(err.message)
|
||||
console.error('onError', file, err, res)
|
||||
},
|
||||
// 自定义插入图片
|
||||
customInsert(res: any, insertFn: InsertFnType) {
|
||||
insertFn(res.data, 'video', res.data)
|
||||
}
|
||||
}
|
||||
},
|
||||
uploadImgShowBase64: true
|
||||
|
||||
@@ -33,8 +33,8 @@ const props = defineProps({
|
||||
.validate((v: string) => ['left', 'center', 'right'].includes(v))
|
||||
.def('center'),
|
||||
showLabel: propTypes.bool.def(false),
|
||||
showSearch: propTypes.bool.def(true),
|
||||
showReset: propTypes.bool.def(true),
|
||||
showSearch: propTypes.bool.def(false),
|
||||
showReset: propTypes.bool.def(false),
|
||||
// 是否显示伸缩
|
||||
expand: propTypes.bool.def(false),
|
||||
// 伸缩的界限字段
|
||||
@@ -199,10 +199,10 @@ initSearch()
|
||||
</ElButton>
|
||||
<!-- add by 芋艿:补充在搜索后的按钮 -->
|
||||
<slot name="actionMore"></slot>
|
||||
<ElButton v-if="expand" text @click="setVisible">
|
||||
<!-- <ElButton v-if="expand" text @click="setVisible">
|
||||
{{ t(visible ? 'common.shrink' : 'common.expand') }}
|
||||
<!-- <Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" /> -->
|
||||
</ElButton>
|
||||
<Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" />
|
||||
</ElButton> -->
|
||||
</div>
|
||||
</template>
|
||||
<template v-for="name in Object.keys($slots)" :key="name" #[name]>
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
<el-upload
|
||||
v-model:file-list="fileList"
|
||||
:accept="fileType.join(',')"
|
||||
:action="updateUrl"
|
||||
:action="uploadUrl"
|
||||
:before-upload="beforeUpload"
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled="disabled"
|
||||
:drag="drag"
|
||||
:headers="uploadHeaders"
|
||||
:http-request="httpRequest"
|
||||
:limit="limit"
|
||||
:multiple="true"
|
||||
:on-error="uploadError"
|
||||
@@ -28,7 +29,7 @@
|
||||
<Icon icon="ep:zoom-in" />
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="handle-icon" @click="handleRemove(file)">
|
||||
<div v-if="!disabled" class="handle-icon" @click="handleRemove(file)">
|
||||
<Icon icon="ep:delete" />
|
||||
<span>删除</span>
|
||||
</div>
|
||||
@@ -45,13 +46,14 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="UploadImgs" setup>
|
||||
import { PropType } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
|
||||
import { ElNotification } from 'element-plus'
|
||||
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth'
|
||||
import { useUpload } from './useUpload'
|
||||
|
||||
defineOptions({ name: 'UploadImgs' })
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
@@ -68,11 +70,7 @@ type FileTypes =
|
||||
| 'image/x-icon'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Array as PropType<UploadUserFile[]>,
|
||||
required: true
|
||||
},
|
||||
updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
|
||||
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
|
||||
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
||||
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false)
|
||||
limit: propTypes.number.def(5), // 最大图片上传数 ==> 非必传(默认为 5张)
|
||||
@@ -80,27 +78,14 @@ const props = defineProps({
|
||||
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
|
||||
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
|
||||
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
|
||||
borderRadius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
|
||||
borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
|
||||
})
|
||||
|
||||
const uploadHeaders = ref({
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId()
|
||||
})
|
||||
const { uploadUrl, httpRequest } = useUpload()
|
||||
|
||||
const fileList = ref<UploadUserFile[]>()
|
||||
// fix: 改为动态监听赋值解决图片回显问题
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(data) => {
|
||||
if (!data) return
|
||||
fileList.value = data
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
const fileList = ref<UploadUserFile[]>([])
|
||||
const uploadNumber = ref<number>(0)
|
||||
const uploadList = ref<UploadUserFile[]>([])
|
||||
/**
|
||||
* @description 文件上传之前判断
|
||||
* @param rawFile 上传的文件
|
||||
@@ -120,29 +105,60 @@ const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
message: `上传图片大小不能超过 ${props.fileSize}M!`,
|
||||
type: 'warning'
|
||||
})
|
||||
uploadNumber.value++
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
}
|
||||
|
||||
// 图片上传成功
|
||||
interface UploadEmits {
|
||||
(e: 'update:modelValue', value: UploadUserFile[]): void
|
||||
(e: 'update:modelValue', value: string[]): void
|
||||
}
|
||||
|
||||
const emit = defineEmits<UploadEmits>()
|
||||
const uploadSuccess = (response, uploadFile: UploadFile) => {
|
||||
if (!response) return
|
||||
// TODO 多图上传组件成功后只是把保存成功后的url替换掉组件选图时的文件路径,所以返回的fileList包含的是一个包含文件信息的对象列表
|
||||
uploadFile.url = response.data
|
||||
emit('update:modelValue', fileList.value)
|
||||
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
// 删除自身
|
||||
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
|
||||
fileList.value.splice(index, 1)
|
||||
uploadList.value.push({ name: res.data, url: res.data })
|
||||
if (uploadList.value.length == uploadNumber.value) {
|
||||
fileList.value.push(...uploadList.value)
|
||||
uploadList.value = []
|
||||
uploadNumber.value = 0
|
||||
emitUpdateModelValue()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听模型绑定值变动
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string | string[]) => {
|
||||
if (!val) {
|
||||
fileList.value = [] // fix:处理掉缓存,表单重置后上传组件的内容并没有重置
|
||||
return
|
||||
}
|
||||
|
||||
fileList.value = [] // 保障数据为空
|
||||
fileList.value.push(
|
||||
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
||||
)
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
// 发送图片链接列表更新
|
||||
const emitUpdateModelValue = () => {
|
||||
let result: string[] = fileList.value.map((file) => file.url!)
|
||||
emit('update:modelValue', result)
|
||||
}
|
||||
// 删除图片
|
||||
const handleRemove = (uploadFile: UploadFile) => {
|
||||
fileList.value = fileList.value.filter(
|
||||
(item) => item.url !== uploadFile.url || item.name !== uploadFile.name
|
||||
)
|
||||
emit('update:modelValue', fileList.value)
|
||||
emit(
|
||||
'update:modelValue',
|
||||
fileList.value.map((file) => file.url!)
|
||||
)
|
||||
}
|
||||
|
||||
// 图片上传错误提示
|
||||
@@ -216,7 +232,7 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderRadius);
|
||||
border-radius: v-bind(borderradius);
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-color-primary);
|
||||
@@ -233,7 +249,7 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
background-color: transparent;
|
||||
border-radius: v-bind(borderRadius);
|
||||
border-radius: v-bind(borderradius);
|
||||
}
|
||||
|
||||
.upload-image {
|
||||
@@ -246,16 +262,16 @@ const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background: rgb(0 0 0 / 60%);
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.handle-icon {
|
||||
display: flex;
|
||||
|
||||
93
src/components/UploadFile/src/useUpload.ts
Normal file
93
src/components/UploadFile/src/useUpload.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import * as FileApi from '@/api/infra/file'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
|
||||
import axios from 'axios'
|
||||
|
||||
export const useUpload = () => {
|
||||
// 后端上传地址
|
||||
const uploadUrl = import.meta.env.VITE_UPLOAD_URL
|
||||
// 是否使用前端直连上传
|
||||
const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
|
||||
// 重写ElUpload上传方法
|
||||
const httpRequest = async (options: UploadRequestOptions) => {
|
||||
// 模式一:前端上传
|
||||
if (isClientUpload) {
|
||||
// 1.1 生成文件名称
|
||||
const fileName = await generateFileName(options.file)
|
||||
// 1.2 获取文件预签名地址
|
||||
const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
|
||||
// 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
|
||||
return axios.put(presignedInfo.uploadUrl, options.file).then(() => {
|
||||
// 1.4. 记录文件信息到后端(异步)
|
||||
createFile(presignedInfo, fileName, options.file)
|
||||
// 通知成功,数据格式保持与后端上传的返回结果一致
|
||||
return { data: presignedInfo.url }
|
||||
})
|
||||
} else {
|
||||
// 模式二:后端上传
|
||||
// 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
|
||||
return new Promise((resolve, reject) => {
|
||||
FileApi.updateFile({ file: options.file })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(res)
|
||||
}
|
||||
})
|
||||
.catch((res) => {
|
||||
reject(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
uploadUrl,
|
||||
httpRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件信息
|
||||
* @param vo 文件预签名信息
|
||||
* @param name 文件名称
|
||||
* @param file 文件
|
||||
*/
|
||||
function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
|
||||
const fileVo = {
|
||||
configId: vo.configId,
|
||||
url: vo.url,
|
||||
path: name,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
size: file.size
|
||||
}
|
||||
FileApi.createFile(fileVo)
|
||||
return fileVo
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件名称(使用算法SHA256)
|
||||
* @param file 要上传的文件
|
||||
*/
|
||||
async function generateFileName(file: UploadRawFile) {
|
||||
// 读取文件内容
|
||||
const data = await file.arrayBuffer()
|
||||
const wordArray = CryptoJS.lib.WordArray.create(data)
|
||||
// 计算SHA256
|
||||
const sha256 = CryptoJS.SHA256(wordArray).toString()
|
||||
// 拼接后缀
|
||||
const ext = file.name.substring(file.name.lastIndexOf('.'))
|
||||
return `${sha256}${ext}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传类型
|
||||
*/
|
||||
enum UPLOAD_TYPE {
|
||||
// 客户端直接上传(只支持S3服务)
|
||||
CLIENT = 'client',
|
||||
// 客户端发送到后端上传
|
||||
SERVER = 'server'
|
||||
}
|
||||
@@ -58,7 +58,7 @@
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" :offset="0">
|
||||
<el-form-item label="状态" prop="remark">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<Editor v-model:modelValue="formData.remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 搜索工作栏 -->
|
||||
<Search
|
||||
:schema="allSchemas.searchSchema"
|
||||
labelWidth="0"
|
||||
@search="setSearchParams"
|
||||
@reset="setSearchParams"
|
||||
/>
|
||||
<Search :schema="allSchemas.searchSchema" labelWidth="0">
|
||||
<template #actionMore>
|
||||
<el-button @click="getTableList" v-hasPermi="['clue:order:search']"> 搜索 </el-button>
|
||||
<el-button @click="resetQuery" v-hasPermi="['clue:order:reset']"> 重置 </el-button>
|
||||
</template>
|
||||
</Search>
|
||||
<!-- 列表 -->
|
||||
<SSTable
|
||||
class="mt-20px"
|
||||
@@ -21,30 +21,55 @@
|
||||
:label="item.label"
|
||||
min-width="120px"
|
||||
/>
|
||||
<el-table-column label="操作" width="140px" fixed="right">
|
||||
<el-table-column label="操作" width="200px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="mr-10px"
|
||||
link
|
||||
style="padding: 0; margin-left: 0"
|
||||
v-hasPermi="['clue:order:after-sale']"
|
||||
@click="sellAfter(scope.row)"
|
||||
>售后</el-button
|
||||
>
|
||||
<el-button type="primary" class="mr-10px" link style="padding: 0; margin-left: 0"
|
||||
>售后审核</el-button
|
||||
>
|
||||
售后
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
class="mr-10px"
|
||||
link
|
||||
style="padding: 0; margin-left: 0"
|
||||
v-hasPermi="['clue:order:after-sale-audit']"
|
||||
>
|
||||
售后审核
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
class="mr-10px"
|
||||
link
|
||||
style="padding: 0; margin-left: 0"
|
||||
v-hasPermi="['clue:order:send']"
|
||||
>
|
||||
发货(进销存)
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
class="mr-10px"
|
||||
link
|
||||
style="padding: 0; margin-left: 0"
|
||||
v-hasPermi="['clue:order:return']"
|
||||
@click="feeBack(scope.row)"
|
||||
>回款</el-button
|
||||
>
|
||||
<el-button type="primary" class="mr-10px" link style="padding: 0; margin-left: 0"
|
||||
>回款确认</el-button
|
||||
回款
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
class="mr-10px"
|
||||
link
|
||||
style="padding: 0; margin-left: 0"
|
||||
v-hasPermi="['clue:order:return-audit']"
|
||||
>
|
||||
回款确认
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</SSTable>
|
||||
@@ -62,7 +87,7 @@ const tableObject = ref({
|
||||
currentPage: 1
|
||||
})
|
||||
|
||||
function setSearchParams() {
|
||||
function resetQuery() {
|
||||
// 方法体
|
||||
}
|
||||
// 查询
|
||||
|
||||
@@ -30,17 +30,19 @@
|
||||
<el-tab-pane label="公海" name="4" />
|
||||
</el-tabs>
|
||||
<div class="absolute" style="right: 10px; top: 0">
|
||||
<el-button plain>导入</el-button>
|
||||
<el-button type="primary" @click="handleInsert">新增线索</el-button>
|
||||
<el-button plain v-hasPermi="['clue:pool:import']">导入</el-button>
|
||||
<el-button type="primary" @click="handleInsert" v-hasPermi="['clue:pool:add']">
|
||||
新增线索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 搜索工作栏 -->
|
||||
<Search
|
||||
:schema="allSchemas.searchSchema"
|
||||
labelWidth="0"
|
||||
@search="setSearchParams"
|
||||
@reset="setSearchParams"
|
||||
/>
|
||||
<Search :schema="allSchemas.searchSchema" labelWidth="0">
|
||||
<template #actionMore>
|
||||
<el-button @click="getTableList" v-hasPermi="['clue:pool:search']"> 搜索 </el-button>
|
||||
<el-button @click="resetQuery" v-hasPermi="['clue:pool:reset']"> 重置 </el-button>
|
||||
</template>
|
||||
</Search>
|
||||
<!-- 列表 -->
|
||||
<SSTable
|
||||
class="mt-20px"
|
||||
@@ -58,9 +60,15 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="item.field == 'followRecord'">
|
||||
<el-button type="primary" text style="padding: 0" @click="handleFollow(row)"
|
||||
>快速新增</el-button
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
style="padding: 0"
|
||||
@click="handleFollow(row)"
|
||||
v-hasPermi="['clue:pool:update']"
|
||||
>
|
||||
快速新增
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-else-if="item.field == 'contact'">
|
||||
<span>{{ row[item.field] }}</span>
|
||||
@@ -71,10 +79,31 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="handleDetail(scope.row)">详情</el-button>
|
||||
<el-button type="primary" link @click="handleEdit(scope.row)">修改</el-button>
|
||||
<el-button type="primary" link @click="handleSuccess(scope.row)">登记</el-button>
|
||||
<el-button type="primary" link>释放</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="handleDetail(scope.row)"
|
||||
v-hasPermi="['clue:pool:detail']"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="handleEdit(scope.row)"
|
||||
v-hasPermi="['clue:pool:update']"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="handleSuccess(scope.row)"
|
||||
v-hasPermi="['clue:pool:enroll']"
|
||||
>
|
||||
登记
|
||||
</el-button>
|
||||
<el-button type="primary" link v-hasPermi="['clue:pool:release']"> 释放 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</SSTable>
|
||||
@@ -121,8 +150,12 @@ function getCheckedColumns(list) {
|
||||
showColumns.value = list
|
||||
}
|
||||
|
||||
const setSearchParams = function () {
|
||||
// 方法体
|
||||
function resetQuery() {
|
||||
searchForm.value = {
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
getTableList()
|
||||
}
|
||||
|
||||
function getTableList() {
|
||||
|
||||
50
src/views/Clue/Set/Comp/GeneralSet.vue
Normal file
50
src/views/Clue/Set/Comp/GeneralSet.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<el-form :model="form" ref="formRef" label-width="auto">
|
||||
<el-form-item label="售后申请自动通过">
|
||||
<el-radio-group v-model="form.autoAudiAfterSale">
|
||||
<el-radio :label="0"> 是 </el-radio>
|
||||
<el-radio :label="1"> 否 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="发货自动发起采购">
|
||||
<el-radio-group v-model="form.autoSend">
|
||||
<el-radio :label="0"> 是 </el-radio>
|
||||
<el-radio :label="1"> 否 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="回款申请自动通过">
|
||||
<el-radio-group v-model="form.autoAuditReturn">
|
||||
<el-radio :label="0"> 是 </el-radio>
|
||||
<el-radio :label="1"> 否 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="getData">刷新</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup name="GeneralClue">
|
||||
const message = useMessage()
|
||||
|
||||
const form = ref({
|
||||
autoAudiAfterSale: 0,
|
||||
autoSend: 0,
|
||||
autoAuditReturn: 0
|
||||
})
|
||||
|
||||
function getData() {
|
||||
form.value = {
|
||||
autoAudiAfterSale: 0,
|
||||
autoSend: 0,
|
||||
autoAuditReturn: 0
|
||||
}
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
message.success('保存成功')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -16,7 +16,10 @@
|
||||
<el-tab-pane label="线索分配规则" :name="30">
|
||||
<ClueSend />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="消息通知" :name="40">
|
||||
<el-tab-pane label="常规设置" :name="40">
|
||||
<GeneralSet />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="消息通知" :name="50">
|
||||
<MsgSend />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -30,6 +33,7 @@ import ClueSource from './Comp/ClueSource.vue'
|
||||
import ClueGet from './Comp/ClueGet.vue'
|
||||
import ClueSend from './Comp/ClueSend.vue'
|
||||
import MsgSend from './Comp/MsgSend.vue'
|
||||
import GeneralSet from './Comp/GeneralSet.vue'
|
||||
|
||||
const tabIndex = ref(0)
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<el-tabs v-model="curTab" type="card" tab-position="top">
|
||||
<el-tab-pane label="库存" name="1">
|
||||
<el-tab-pane label="库存" name="1" v-if="checkPermi(['mall:inventory:index'])">
|
||||
<InventoryDetail v-if="curTab == 1" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="库存变动记录" name="2">
|
||||
<el-tab-pane label="库存变动记录" name="2" v-if="checkPermi(['mall:inventory:record'])">
|
||||
<InventoryRecord v-if="curTab == 2" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="仓库" name="3">
|
||||
<el-tab-pane label="仓库" name="3" v-if="checkPermi(['mall:inventory:depot'])">
|
||||
<Warehouse v-if="curTab == 3" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -16,6 +16,7 @@
|
||||
import InventoryDetail from './Comp/InventoryDetail.vue'
|
||||
import Warehouse from './Comp/Warehouse.vue'
|
||||
import InventoryRecord from './Comp/InventoryRecord.vue'
|
||||
import { checkPermi } from '@/utils/permission'
|
||||
|
||||
const curTab = ref('1')
|
||||
</script>
|
||||
|
||||
@@ -15,22 +15,31 @@
|
||||
<el-button type="primary" @click="openForm('create', null)">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="loading" :data="tableList">
|
||||
<el-table-column prop="brandName" label="品牌名称" />
|
||||
<el-table-column prop="orderNum" label="排序" width="100px" />
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
<el-table-column label="创建时间" prop="createTime" width="180px" />
|
||||
<el-table-column label="创建人" prop="createUser" width="150px" />
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column prop="name" label="品牌名称" />
|
||||
<el-table-column prop="sort" label="排序" width="100px" />
|
||||
<el-table-column prop="description" label="备注" />
|
||||
<el-table-column label="开启状态" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
prop="createTime"
|
||||
width="180px"
|
||||
:formatter="dateFormatter"
|
||||
/>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" text @click="openForm('update', scope.row)">修改</el-button>
|
||||
<el-button type="danger" text @click="handleDelete(scope.row)">删除</el-button>
|
||||
<el-button type="primary" text @click="openForm('update', scope.row.id)">修改</el-button>
|
||||
<el-button type="danger" text @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<Pagination
|
||||
v-model:limit="searchForm.pageSize"
|
||||
v-model:page="searchForm.pageNum"
|
||||
v-model:page="searchForm.pageNo"
|
||||
:total="total"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
@@ -40,51 +49,56 @@
|
||||
</template>
|
||||
|
||||
<script setup name="BrandSet">
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import * as ProductBrandApi from '@/api/mall/product/brand'
|
||||
import DialogBrand from './DialogBrand.vue'
|
||||
|
||||
const searchForm = ref({
|
||||
pageNum: 1,
|
||||
name: undefined,
|
||||
pageNo: 1,
|
||||
pageSize: 20
|
||||
})
|
||||
|
||||
const total = ref(0)
|
||||
const brandDialog = ref()
|
||||
const tableList = ref([])
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
function handleQuery() {
|
||||
searchForm.value.pageNum = 1
|
||||
searchForm.value.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
function resetQuery() {
|
||||
searchForm.value = {
|
||||
name: '',
|
||||
pageSize: 20,
|
||||
pageNum: 1
|
||||
pageNo: 1
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
function getList() {
|
||||
tableList.value = [
|
||||
{
|
||||
brandId: 1,
|
||||
brandName: '测试'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function openForm(type, info) {
|
||||
brandDialog.value.open(type, info)
|
||||
}
|
||||
|
||||
async function handleDelete(row) {
|
||||
async function getList() {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await ProductBrandApi.getBrandParam(searchForm.value)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openForm(type, id) {
|
||||
brandDialog.value.open(type, id)
|
||||
}
|
||||
|
||||
async function handleDelete(id) {
|
||||
try {
|
||||
console.log(row)
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
// await UserApi.deleteUser(row.id)
|
||||
await ProductBrandApi.deleteBrand(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
|
||||
@@ -15,24 +15,28 @@
|
||||
<el-button type="primary" @click="openForm('create', null)">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableList"
|
||||
row-key="categoryId"
|
||||
:tree-props="{ children: 'children' }"
|
||||
>
|
||||
<el-table v-loading="loading" :data="list" row-key="id" :tree-props="{ children: 'children' }">
|
||||
<el-table-column prop="categoryName" label="分类名称" />
|
||||
<el-table-column prop="orderNum" label="排序" width="100px" />
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
<el-table-column label="创建时间" prop="createTime" width="180px" />
|
||||
<el-table-column label="创建人" prop="createUser" width="150px" />
|
||||
<el-table-column label="状态" align="center" min-width="150" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
prop="createTime"
|
||||
width="180px"
|
||||
:formatter="dateFormatter"
|
||||
/>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" text @click="openForm('update', scope.row)">修改</el-button>
|
||||
<el-button type="primary" text @click="openForm('createChildren', scope.row)"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button type="danger" text @click="handleDelete(scope.row)">删除</el-button>
|
||||
<el-button type="danger" text @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -48,58 +52,61 @@
|
||||
</template>
|
||||
|
||||
<script setup name="CategorySet">
|
||||
import * as ProductCategoryApi from '@/api/mall/product/category'
|
||||
import { handleTree } from '@/utils/tree'
|
||||
import DialogCategory from './DialogCategory.vue'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
|
||||
const searchForm = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 20
|
||||
name: undefined
|
||||
})
|
||||
|
||||
const total = ref(0)
|
||||
const categoryDialog = ref()
|
||||
const tableList = ref([])
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
function handleQuery() {
|
||||
searchForm.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
function resetQuery() {
|
||||
searchForm.value = {
|
||||
name: '',
|
||||
pageSize: 20,
|
||||
pageNum: 1
|
||||
name: undefined
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
function getList() {
|
||||
tableList.value = [
|
||||
{
|
||||
categoryId: 1,
|
||||
categoryName: '测试',
|
||||
level: 1,
|
||||
children: [{ categoryId: 1001, categoryName: '二级分类', level: 2, parentCategory: '测试' }]
|
||||
}
|
||||
]
|
||||
async function getList() {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await ProductCategoryApi.getCategoryList(searchForm.value)
|
||||
list.value = handleTree(data, 'id', 'parentId')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openForm(type, info) {
|
||||
categoryDialog.value.open(type, info)
|
||||
}
|
||||
|
||||
async function handleDelete(row) {
|
||||
async function handleDelete(id) {
|
||||
try {
|
||||
console.log(row)
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
// await UserApi.deleteUser(row.id)
|
||||
await ProductCategoryApi.deleteCategory(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
handleQuery()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="500px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
v-loading="formLoading"
|
||||
@@ -7,11 +7,17 @@
|
||||
:rules="formRules"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="品牌名称" prop="brandName">
|
||||
<el-input v-model="formData.brandName" placeholder="请输入品牌名称" />
|
||||
<el-form-item label="品牌名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入品牌名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="orderNum">
|
||||
<el-input v-model="formData.orderNum" placeholder="请输入排序" type="number" :min="0" />
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort" placeholder="请输入排序" type="number" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="0"> 启用 </el-radio>
|
||||
<el-radio :label="1"> 禁用 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
@@ -29,6 +35,8 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script name="DialogBrand" setup>
|
||||
import * as ProductBrandApi from '@/api/mall/product/brand'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
@@ -37,27 +45,27 @@ const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
brandName: '',
|
||||
orderNum: 1,
|
||||
name: '',
|
||||
sort: 1,
|
||||
status: 0,
|
||||
remark: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
brandName: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type, info) => {
|
||||
const open = async (type, id) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = type == 'update' ? '修改品牌' : '新增品牌'
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (info.brandId) {
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = { ...info }
|
||||
// formData.value = await UserApi.getUser(id)
|
||||
formData.value = await ProductBrandApi.getBrand(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
@@ -75,12 +83,11 @@ const submitForm = async () => {
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
// const data = formData.value as unknown as UserApi.UserVO
|
||||
if (formType.value === 'create') {
|
||||
// await UserApi.createUser(data)
|
||||
await ProductBrandApi.createBrand(formData.value)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
// await UserApi.updateUser(data)
|
||||
await ProductBrandApi.updateBrand(formData.value)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
@@ -94,8 +101,9 @@ const submitForm = async () => {
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
brandName: '',
|
||||
orderNum: 1,
|
||||
name: '',
|
||||
sort: 1,
|
||||
status: 0,
|
||||
remark: ''
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="500px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
v-loading="formLoading"
|
||||
@@ -10,11 +10,17 @@
|
||||
<el-form-item v-if="formData.level > 1" label="上级分类">
|
||||
<el-input v-model="formData.parentCategory" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称" prop="categoryName">
|
||||
<el-input v-model="formData.categoryName" placeholder="请输入分类名称" />
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入分类名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="orderNum">
|
||||
<el-input v-model="formData.orderNum" placeholder="请输入排序" type="number" :min="0" />
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort" placeholder="请输入排序" type="number" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="0"> 启用 </el-radio>
|
||||
<el-radio :label="1"> 禁用 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
@@ -32,6 +38,8 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script name="DialogCategory" setup>
|
||||
import * as ProductCategoryApi from '@/api/mall/product/category'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
@@ -40,12 +48,13 @@ const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
categoryName: '',
|
||||
orderNum: 1,
|
||||
name: '',
|
||||
sort: 1,
|
||||
status: 0,
|
||||
remark: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
categoryName: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
@@ -56,16 +65,15 @@ const open = async (type, info) => {
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (info.categoryId) {
|
||||
if (info?.id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
if (type == 'update') {
|
||||
formData.value = { ...info }
|
||||
formData.value = await ProductCategoryApi.getCategory(info.id)
|
||||
} else {
|
||||
formData.value.level = info.level + 1
|
||||
formData.value.parentCategory = info.categoryName
|
||||
formData.value.parentCategory = info.name
|
||||
}
|
||||
// formData.value = await UserApi.getUser(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
@@ -83,12 +91,11 @@ const submitForm = async () => {
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
// const data = formData.value as unknown as UserApi.UserVO
|
||||
if (formType.value === 'create') {
|
||||
// await UserApi.createUser(data)
|
||||
await ProductCategoryApi.createCategory(formData.value)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
// await UserApi.updateUser(data)
|
||||
await ProductCategoryApi.updateCategory(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
@@ -102,8 +109,9 @@ const submitForm = async () => {
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
categoryName: '',
|
||||
orderNum: 1,
|
||||
name: '',
|
||||
sort: 1,
|
||||
status: 0,
|
||||
remark: ''
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<el-tabs v-model="tabIndex" type="border-card">
|
||||
<el-tab-pane label="产品属性" :name="0">
|
||||
<FieldProduct />
|
||||
<el-tab-pane label="产品属性" :name="0" v-if="checkPermi(['mall:setting:prod'])">
|
||||
<FieldProduct v-if="tabIndex == 0" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="分类设置" :name="1">
|
||||
<CategorySet />
|
||||
<el-tab-pane label="分类设置" :name="1" v-if="checkPermi(['mall:setting:category'])">
|
||||
<CategorySet v-if="tabIndex == 1" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="品牌设置" :name="2">
|
||||
<BrandSet />
|
||||
<el-tab-pane label="品牌设置" :name="2" v-if="checkPermi(['mall:setting:brand'])">
|
||||
<BrandSet v-if="tabIndex == 2" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="供应商设置" :name="3">
|
||||
<SupplierSet />
|
||||
<el-tab-pane label="供应商设置" :name="3" v-if="checkPermi(['mall:setting:supplier'])">
|
||||
<SupplierSet v-if="tabIndex == 3" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="常规设置" :name="4">
|
||||
<GeneralSet />
|
||||
<el-tab-pane label="常规设置" :name="4" v-if="checkPermi(['mall:setting:general'])">
|
||||
<GeneralSet v-if="tabIndex == 4" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="消息通知" :name="9">
|
||||
<MsgSend />
|
||||
<el-tab-pane label="消息通知" :name="9" v-if="checkPermi(['mall:setting:msg'])">
|
||||
<MsgSend v-if="tabIndex == 9" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
@@ -28,6 +28,7 @@ import MsgSend from './Comp/MsgSend.vue'
|
||||
import CategorySet from './Comp/CategorySet.vue'
|
||||
import BrandSet from './Comp/BrandSet.vue'
|
||||
import SupplierSet from './Comp/SupplierSet.vue'
|
||||
import { checkPermi } from '@/utils/permission'
|
||||
|
||||
const tabIndex = ref(0)
|
||||
</script>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
placeholder="请选择分类"
|
||||
filterable
|
||||
show-all-levels
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -44,15 +45,15 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="主图" prop="picUrl">
|
||||
<UploadImg v-model="form.picUrl" height="100px" width="100px" />
|
||||
<el-form-item label="主图" prop="mainImage">
|
||||
<UploadImg v-model="form.mainImage" height="100px" width="100px" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" :offset="0">
|
||||
<el-form-item label="轮播图" prop="sliderPicUrls">
|
||||
<UploadImgs v-model:modelValue="form.sliderPicUrls" height="100px" width="100px" />
|
||||
<el-form-item label="轮播图" prop="carouselImages">
|
||||
<UploadImgs v-model="form.carouselImages" height="100px" width="100px" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -60,7 +61,7 @@
|
||||
<el-col :span="24" :offset="0">
|
||||
<el-form-item label="商品规格">
|
||||
<el-button @click="handleAddSpec">添加规格</el-button>
|
||||
<el-col v-for="(item, index) in form.specsList" :key="index">
|
||||
<el-col v-for="(item, index) in form.productSpecList" :key="index">
|
||||
<div>
|
||||
<el-text class="mx-1">属性名:</el-text>
|
||||
<el-tag class="mx-1" closable type="success" @close="handleCloseProperty(index)"
|
||||
@@ -109,7 +110,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="col in form.specsList"
|
||||
v-for="col in form.productSpecList"
|
||||
:prop="col.id"
|
||||
:key="col.id"
|
||||
:label="col.name"
|
||||
@@ -135,10 +136,10 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="详细信息" name="detail">
|
||||
<Editor v-model:modelValue="form.description" />
|
||||
<Editor v-model:modelValue="form.detailInfo" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<ProductAttributesAddForm ref="attributesAddFormRef" :propertyList="form.specsList" />
|
||||
<ProductAttributesAddForm ref="attributesAddFormRef" :propertyList="form.productSpecList" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -148,27 +149,33 @@ const message = useMessage() // 消息弹窗
|
||||
|
||||
const tabName = ref('basic')
|
||||
const form = ref({
|
||||
name: '',
|
||||
category: '',
|
||||
brand: '',
|
||||
intro: '',
|
||||
picUrl: '',
|
||||
sliderPicUrls: [],
|
||||
specsList: [],
|
||||
productName: undefined,
|
||||
productCategory: undefined,
|
||||
productBrand: undefined,
|
||||
productIntro: undefined,
|
||||
mainImage: '',
|
||||
carouselImages: [],
|
||||
productSpecList: [],
|
||||
skuList: [],
|
||||
description: null
|
||||
detailInfo: null
|
||||
})
|
||||
const rules = ref({})
|
||||
const attributesAddFormRef = ref() // 添加商品属性表单
|
||||
|
||||
const opts = {
|
||||
brand: [],
|
||||
productCategory: []
|
||||
brand: [{ value: 1, label: '品牌1' }],
|
||||
productCategory: [
|
||||
{
|
||||
id: 1,
|
||||
label: '分类1',
|
||||
children: [{ id: 2, label: '子分类1' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
/** 删除属性*/
|
||||
function handleCloseProperty(index) {
|
||||
form.value.specsList?.splice(index, 1)
|
||||
form.value.productSpecList?.splice(index, 1)
|
||||
}
|
||||
|
||||
const attributeIndex = ref(null)
|
||||
@@ -186,7 +193,7 @@ async function handleInputConfirm(index, propertyId) {
|
||||
try {
|
||||
// const id = await PropertyApi.createPropertyValue({ propertyId, name: inputValue.value })
|
||||
const id = propertyId || parseInt(Math.random() * 1000000)
|
||||
form.value.specsList[index].values.push({ id, name: inputValue.value })
|
||||
form.value.productSpecList[index].values.push({ id, name: inputValue.value })
|
||||
message.success('添加成功')
|
||||
} catch {
|
||||
message.error('添加失败,请重试')
|
||||
@@ -199,7 +206,7 @@ async function handleInputConfirm(index, propertyId) {
|
||||
|
||||
function getTableList() {
|
||||
let list = []
|
||||
form.value.specsList.map((item) => {
|
||||
form.value.productSpecList.map((item) => {
|
||||
if (!list.length) {
|
||||
item.values.map((it) => {
|
||||
const obj = {}
|
||||
@@ -238,8 +245,7 @@ const setInputRef = (el) => {
|
||||
}
|
||||
|
||||
function handleAddSpec() {
|
||||
const id = parseInt(Math.random() * 1000)
|
||||
form.value.specsList.push({ name: `测试规格${id}`, id, values: [] })
|
||||
attributesAddFormRef.value.open()
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
@@ -249,19 +255,19 @@ function onSubmit() {
|
||||
onMounted(() => {
|
||||
if (route.query?.id) {
|
||||
form.value = {
|
||||
name: '商品名称哦~'
|
||||
productName: '商品名称哦~'
|
||||
}
|
||||
} else {
|
||||
form.value = {
|
||||
name: '',
|
||||
category: '',
|
||||
brand: '',
|
||||
intro: '',
|
||||
picUrl: '',
|
||||
sliderPicUrls: [],
|
||||
specsList: [],
|
||||
productName: undefined,
|
||||
productCategory: undefined,
|
||||
productBrand: undefined,
|
||||
productIntro: undefined,
|
||||
mainImage: 'https://ss-cloud.ahduima.com/1001/1796426117251600384.png',
|
||||
carouselImages: ['https://ss-cloud.ahduima.com/1001/1796426117251600384.png'],
|
||||
productSpecList: [],
|
||||
skuList: [],
|
||||
description: null
|
||||
detailInfo: null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"> 搜索 </el-button>
|
||||
<el-button @click="resetQuery"> 重置 </el-button>
|
||||
<el-button plain type="primary" @click="openForm"> 新增 </el-button>
|
||||
<el-button @click="handleQuery" v-hasPermi="['mall:prod:search']"> 搜索 </el-button>
|
||||
<el-button @click="resetQuery" v-hasPermi="['mall:prod:reset']"> 重置 </el-button>
|
||||
<el-button plain type="primary" @click="openForm" v-hasPermi="['mall:prod:add']">
|
||||
新增
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@@ -71,8 +73,22 @@
|
||||
<el-table-column fixed="right" label="操作" min-width="80">
|
||||
<template #default="{ row }">
|
||||
<!-- TODO:【详情】,可以后面点做哈 -->
|
||||
<el-button link type="primary" @click="openForm(row.productId)"> 修改 </el-button>
|
||||
<el-button link type="danger" @click="handleDelete(row.productId)"> 删除 </el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm(row.productId)"
|
||||
v-hasPermi="['mall:prod:update']"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(row.productId)"
|
||||
v-hasPermi="['mall:prod:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 搜索工作栏 -->
|
||||
<Search
|
||||
:schema="allSchemas.searchSchema"
|
||||
labelWidth="0"
|
||||
expand
|
||||
expand-field="supplier"
|
||||
@search="setSearchParams"
|
||||
@reset="setSearchParams"
|
||||
>
|
||||
<Search :schema="allSchemas.searchSchema" labelWidth="0">
|
||||
<template #actionMore>
|
||||
<el-button type="primary" @click="handleAdd">发起采购</el-button>
|
||||
<el-button @click="getList" v-hasPermi="['mall:purchase:search']"> 搜索 </el-button>
|
||||
<el-button @click="resetQuery" v-hasPermi="['mall:purchase:reset']"> 重置 </el-button>
|
||||
<el-button type="primary" @click="handleAdd" v-hasPermi="['mall:purchase:add']">
|
||||
发起采购
|
||||
</el-button>
|
||||
</template>
|
||||
</Search>
|
||||
<!-- 列表 -->
|
||||
@@ -31,11 +28,32 @@
|
||||
/>
|
||||
<el-table-column label="操作" width="150px" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" v-if="row.status == 1" link @click="handleAudit(row)"
|
||||
>采购审核</el-button
|
||||
<el-button
|
||||
type="primary"
|
||||
v-if="row.status == 1"
|
||||
link
|
||||
@click="handleAudit(row)"
|
||||
v-hasPermi="['mall:purchase:audit']"
|
||||
>
|
||||
<el-button v-else type="primary" link @click="purchaseAgain(row)">再次采购</el-button>
|
||||
<el-button type="primary" link @click="handleDetail(row)">详情</el-button>
|
||||
采购审核
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
type="primary"
|
||||
link
|
||||
@click="purchaseAgain(row)"
|
||||
v-hasPermi="['mall:purchase:readd']"
|
||||
>
|
||||
再次采购
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="handleDetail(row)"
|
||||
v-hasPermi="['mall:purchase:detail']"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</SSTable>
|
||||
@@ -59,7 +77,19 @@ const tableObject = ref({
|
||||
pageSize: 20,
|
||||
currentPage: 1
|
||||
})
|
||||
const setSearchParams = function () {
|
||||
|
||||
function resetQuery() {
|
||||
queryParams.value = {
|
||||
productName: undefined,
|
||||
productBrand: undefined,
|
||||
productCategory: undefined,
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = function () {
|
||||
tableObject.value.tableList = [
|
||||
{ name: '测试', status: 1, statusName: '审核中', supplier: '林氏木业', purchaseCount: 10 },
|
||||
{ name: '测试2', status: 2, statusName: '已通过', supplier: '张氏木业', purchaseCount: 1 },
|
||||
|
||||
Reference in New Issue
Block a user