This commit is contained in:
qsh
2024-06-14 15:55:48 +08:00
parent d22a380612
commit 4c692c48e3
18 changed files with 507 additions and 180 deletions

View File

@@ -2,45 +2,55 @@
<el-row :gutter="80">
<el-col :span="10" :offset="0">
<el-button class="mb-10px" type="primary" @click="handleInsert">新增属性</el-button>
<el-table :data="tableList">
<el-table-column prop="name" label="名称" />
<el-table-column label="启用状态">
<el-table :data="tableList" :row-class-name="setRowClass" @row-click="handleRowClick">
<el-table-column prop="label" label="名称" />
<el-table-column prop="field" label="属性编码" />
<el-table-column prop="component" label="类型" width="200px">
<template #default="{ row }">
{{ typeOptions.find((it) => it.value == row.component).label }}
</template>
</el-table-column>
<el-table-column label="启用状态" width="100">
<template #default="{ row }">
<el-switch
v-model="row.status"
:active-value="1"
:inactive-value="0"
:disabled="!row.canUpdate"
:active-value="0"
:inactive-value="1"
@change="changeStatus(row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80px">
<template #default="{ row }">
<el-button
type="primary"
text
:disabled="!row.canUpdate"
style="padding: 0"
@click="remove(row)"
<el-button type="primary" text style="padding: 0" @click="remove(row.clueParamId)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="14" :offset="0">
<el-form :model="form" ref="fieldForm" :rules="rules" label-width="80px" :inline="false">
<el-form-item label="属性名称" prop="name">
<el-input v-model="form.name" placeholder="请输入属性名称" />
<el-col :span="14" :offset="0" v-if="tableList.length || formType == 'create'">
<el-form :model="form" ref="fieldForm" :rules="rules" label-width="100px" :inline="false">
<el-form-item label="属性名称" prop="label">
<el-input v-model="form.label" placeholder="请输入属性名称" />
</el-form-item>
<el-form-item label="属性类型" prop="type">
<el-form-item prop="field">
<template #label>
<div class="flex justify-center" style="align-items: center">
<span>属性编码</span>
<Tooltip message="请输入字母或数字,必须以字母开头" />
</div>
</template>
<el-input v-model="form.field" placeholder="请输入属性编码" />
</el-form-item>
<el-form-item label="属性类型" prop="component">
<el-select
v-model="form.type"
v-model="form.component"
placeholder="请选择属性类型"
clearable
filterable
style="width: 100%"
@change="form.options = []"
>
<el-option
v-for="item in typeOptions"
@@ -51,72 +61,174 @@
</el-select>
</el-form-item>
<el-form-item
v-if="['Checkbox', 'Radio', 'Select'].includes(form.type)"
v-if="['Checkbox', 'Radio', 'Select'].includes(form.component)"
label="选项"
prop="option"
key="option"
prop="options"
key="options"
>
<div>
<el-button type="primary" @click="optionList.push([])"> 新增选项 </el-button>
<el-button type="primary" @click="handleAddOption"> 新增选项 </el-button>
<div
class="flex justify-between mt-10px"
v-for="(item, index) in optionList"
v-for="(item, index) in form.options"
:key="index"
>
<el-input v-model="item.label" placeholder="请输入选项内容" clearable />
<el-button type="primary" text @click="optionList.splice(index, 1)">删除</el-button>
<el-input
v-model="item.name"
placeholder="请输入选项内容"
clearable
style="width: 300px !important"
@blur="item.id = item.name"
/>
<el-button type="primary" text @click="form.options.splice(index, 1)">删除</el-button>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">保存</el-button>
<el-button type="primary" :disabled="formLoading" @click="onSubmit">保存</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script setup>
const tableList = ref([{ name: '单位', status: 0, canUpdate: true }])
<script setup name="FieldProduct">
import * as FieldApi from '@/api/mall/product/productField'
import { getDictOptions } from '@/utils/dict'
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const tableList = ref([])
const currentRowId = ref('')
function setRowClass({ row }) {
return row.field == currentRowId.value ? 'current-row' : ''
}
function handleRowClick(row) {
formType.value = 'update'
currentRowId.value = row.field
form.value = { ...row }
}
const form = ref({
name: undefined,
type: undefined,
option: undefined
label: undefined,
field: '',
component: undefined,
options: [],
status: 0,
isCustom: true,
isForm: true,
isSearch: true,
isTable: true
})
const typeOptions = ref([
{ label: '输入框', value: 'Input' },
{ label: '多选', value: 'Checkbox' },
{ label: '单选', value: 'Radio' },
{ label: '下拉选', value: 'Select' },
{ label: '开关', value: 'Switch' },
{ label: '日期选择', value: 'DatePicker' },
{ label: '时间选择', value: 'TimePicker' },
{ label: '富文本', value: 'Editor' },
{ label: '图片', value: 'UploadImg' },
{ label: '文件', value: 'UploadFile' }
])
const loading = ref(false)
const rules = {}
const typeOptions = ref([])
const optionList = ref([])
const rules = {
label: { required: true, message: '名称不可为空', trigger: 'blur' },
field: { required: true, message: '编码不可为空', trigger: 'blur' },
component: { required: true, message: '类型不可为空', trigger: 'change' }
}
async function getList() {
loading.value = true
try {
const data = await FieldApi.getDiyFieldList()
tableList.value = data
if (data.length) {
handleRowClick(data[0])
}
} finally {
loading.value = false
}
}
const formType = ref('')
function handleInsert() {
console.log('新增')
formType.value = 'create'
form.value = {
label: undefined,
field: '',
component: undefined,
options: [],
status: 0,
isCustom: true,
isForm: true,
isSearch: true,
isTable: true
}
}
function changeStatus(row) {
console.log(row.status)
async function remove(id) {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await FieldApi.deleteField(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch (err) {
console.log(err)
}
}
function remove(row) {
console.log(row.status)
async function changeStatus(row) {
try {
// 二次确认
await message.confirm('是否确认修改状态')
await FieldApi.updateFieldStatus(row.clueParamId, row.status)
message.success('修改成功')
// 刷新列表
await getList()
} catch {
// 取消后,进行恢复按钮
row.status = row.status == 0 ? 1 : 0
}
}
function onSubmit() {
console.log('保存')
const fieldForm = ref()
const formLoading = ref(false)
function handleAddOption() {
if (form.value.options) {
form.value.options.push({})
} else {
form.value.options = []
}
}
async function onSubmit() {
// 校验表单
if (!fieldForm.value) return
const valid = await fieldForm.value.validate()
if (!valid) return
// 提交请求
formLoading.value = true
try {
if (formType.value === 'create') {
await FieldApi.createField(form.value)
message.success(t('common.createSuccess'))
} else {
await FieldApi.updateField(form.value)
message.success(t('common.updateSuccess'))
}
// 发送操作成功的事件
getList()
} finally {
formLoading.value = false
}
}
onMounted(() => {
typeOptions.value = getDictOptions('attribute_type')
getList()
})
</script>
<style lang="scss" scoped></style>

View File

@@ -1,34 +1,50 @@
<template>
<el-form :model="form" ref="formRef" label-width="auto">
<el-form-item label="采购申请自动通过">
<el-radio-group v-model="form.autoAuditPurchase">
<el-radio :label="true"> </el-radio>
<el-radio :label="false"> </el-radio>
<el-radio-group v-model="form.purchaseAuditAutoCompleteConfig">
<el-radio label="true"> </el-radio>
<el-radio label="false"> </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="BasicSettingMall">
import * as ConfigApi from '@/api/system/set'
const message = useMessage()
const form = ref({
autoAuditPurchase: 0
purchaseAuditAutoCompleteConfig: 'true'
})
const info = ref({})
function getData() {
form.value = {
autoAuditPurchase: 1
}
ConfigApi.getConfigByConfigKey({ configKey: 'purchaseAuditAutoCompleteConfig' }).then((data) => {
info.value = data
form.value = {
purchaseAuditAutoCompleteConfig: data.configValue
}
})
}
function onSubmit() {
message.success('保存成功')
const data = {
...info,
purchaseAuditAutoCompleteConfig: form.value.purchaseAuditAutoCompleteConfig
}
ConfigApi.updateConfig(data).then(() => {
message.success('保存成功')
})
}
onMounted(() => {
getData()
})
</script>
<style lang="scss" scoped></style>

View File

@@ -33,6 +33,38 @@
</el-select>
</el-form-item>
</el-col>
<el-col
:span="8"
:offset="0"
v-for="fieldItem in diyFieldList"
:key="fieldItem.clueParamId"
>
<el-form-item :label="fieldItem.label" :prop="fieldItem.field">
<component :is="componentMap[fieldItem.component]" v-model="form[fieldItem.field]">
<template v-if="fieldItem.component == 'Select'">
<el-option
v-for="item in fieldItem.options"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</template>
<template v-else-if="fieldItem.component == 'Radio'">
<el-radio v-for="item in fieldItem.options" :key="item.id" :label="item.id">
{{ item.name }}
</el-radio>
</template>
<template v-else-if="fieldItem.component == 'Checkbox'">
<el-checkbox
v-for="item in fieldItem.options"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</template>
</component>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
@@ -51,7 +83,7 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-row :gutter="20" v-if="!formLoading">
<el-col :span="24" :offset="0">
<el-form-item label="轮播图" prop="carouselImages">
<UploadImgs v-model="form.carouselImages" height="100px" width="100px" />
@@ -143,21 +175,25 @@
</el-tabs>
<div class="mt-20px flex justify-center">
<el-button type="primary" @click="onSubmit">保存</el-button>
<el-button plain>重置</el-button>
<el-button plain @click="router.replace('/MiniMall/product')">返回列表</el-button>
</div>
<ProductAttributesAddForm ref="attributesAddFormRef" :propertyList="form.productSpecList" />
</template>
<script setup>
import { cloneDeep } from 'lodash-es'
import { getDiyFieldList } from '@/api/mall/product/productField'
import * as PropertyApi from '@/api/mall/product/property'
import * as ProductApi from '@/api/mall/product/index'
import ProductAttributesAddForm from './Comp/ProductAttributesAddForm.vue'
import * as BrandApi from '@/api/mall/product/brand'
import * as CategoryApi from '@/api/mall/product/category'
import { handleTree } from '@/utils/tree'
import { isObject } from '@/utils/is.ts'
import { componentMap } from '@/components/Form/src/componentMap'
const route = useRoute()
const router = useRouter()
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
@@ -184,7 +220,11 @@ const opts = ref({
category: []
})
const diyFieldList = ref([])
async function getOptions() {
getDiyFieldList().then((data) => {
diyFieldList.value = data
})
BrandApi.getSimpleBrandList().then((data) => {
opts.value.brand = data || []
})
@@ -329,24 +369,35 @@ const spuForm = ref()
function onSubmit() {
spuForm.value.validate(async (valid) => {
if (valid && validateSku()) {
// 深拷贝一份, 这样最终 server 端不满足,不需要影响原始数据
const deepCopyFormData = cloneDeep(unref(form.value))
deepCopyFormData.productSpecList = deepCopyFormData.skuList
if (deepCopyFormData.productCategory && deepCopyFormData.productCategory.length) {
deepCopyFormData.productCategory = deepCopyFormData.productCategory.at(-1)
}
delete deepCopyFormData.skuList
// 校验都通过后提交表单
const data = deepCopyFormData
const id = route.query.id
if (!id) {
await ProductApi.createProduct(data)
message.success(t('common.createSuccess'))
} else {
await ProductApi.updateProduct(data)
message.success(t('common.updateSuccess'))
try {
if (valid && validateSku()) {
// 深拷贝一份, 这样最终 server 端不满足,不需要影响原始数据
const deepCopyFormData = cloneDeep(unref(form.value))
deepCopyFormData.productSpecList = deepCopyFormData.skuList
if (deepCopyFormData.productCategory && deepCopyFormData.productCategory.length) {
deepCopyFormData.productCategory = deepCopyFormData.productCategory.at(-1)
}
delete deepCopyFormData.skuList
// 校验都通过后提交表单
let data = {
...deepCopyFormData,
diyParams: {}
}
for (let i = 0; i < diyFieldList.value.length; i++) {
const element = diyFieldList.value[i]
data.diyParams[element.field] = data[element.field]
}
const id = route.query.id
if (!id) {
await ProductApi.createProduct(data)
message.success(t('common.createSuccess'))
} else {
await ProductApi.updateProduct(data)
message.success(t('common.updateSuccess'))
}
}
} catch (error) {
console.log(error)
}
})
}
@@ -414,10 +465,15 @@ const getDetail = async () => {
formLoading.value = true
try {
const res = await ProductApi.getProduct(route.query.id)
const propList = getPropertyList(res.productSpecList)
let diyField = {}
if (res.diyParams) {
diyField = isObject(res.diyParams) ? res.diyParams : JSON.parse(res.diyParams)
}
const propList = getPropertyList(res?.productSpecList || [])
form.value = {
...res,
skuList: res.productSpecList,
...diyField,
skuList: res?.productSpecList || [],
productSpecList: propList
}
} finally {

View File

@@ -81,7 +81,15 @@
</el-table-column>
<el-table-column label="简介" min-width="70" prop="productIntro" />
<el-table-column :formatter="dateFormatter" label="创建时间" prop="createTime" width="180" />
<el-table-column fixed="right" label="操作" min-width="80">
<el-table-column v-for="item in diyFieldList" :key="item.clueParamId" :label="item.label">
<template #default="{ row }">
<div v-if="item.component == 'DatePicker'">
{{ formatDate(row[item.field]) }}
</div>
<div v-else>{{ row[item.field] }}</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="100">
<template #default="{ row }">
<!-- TODO详情可以后面点做哈 -->
<el-button
@@ -113,12 +121,14 @@
</template>
<script setup name="Product">
import { dateFormatter } from '@/utils/formatTime'
import { getDiyFieldList } from '@/api/mall/product/productField'
import { dateFormatter, formatDate } from '@/utils/formatTime'
import { createImageViewer } from '@/components/ImageViewer'
import * as ProductApi from '@/api/mall/product'
import * as BrandApi from '@/api/mall/product/brand'
import * as CategoryApi from '@/api/mall/product/category'
import { handleTree } from '@/utils/tree'
import { isObject } from '@/utils/is.ts'
const { currentRoute, push } = useRouter()
const message = useMessage() // 消息弹窗
@@ -162,13 +172,20 @@ async function getList() {
params.productCategory = params.productCategory.at(-1)
}
const data = await ProductApi.getProductPage(params)
tableList.value = data.list.map((prod) => ({
...prod,
properties: prod.productSpecList[0].properties.map((item) => ({
propertyId: item.propertyId,
label: item.propertyName
}))
}))
tableList.value = data.list.map((prod) => {
let diyField = {}
if (prod.diyParams) {
diyField = isObject(prod.diyParams) ? prod.diyParams : JSON.parse(prod.diyParams)
}
return {
...prod,
...diyField,
properties: prod.productSpecList[0].properties.map((item) => ({
propertyId: item.propertyId,
label: item.propertyName
}))
}
})
total.value = data.total
} finally {
loading.value = false
@@ -187,7 +204,12 @@ function handleQuery() {
getList()
}
const diyFieldList = ref([])
async function getOptions() {
getDiyFieldList().then((data) => {
diyFieldList.value = data
})
BrandApi.getSimpleBrandList().then((data) => {
opts.value.brand = data || []
})

View File

@@ -99,6 +99,8 @@ import * as WarehouseApi from '@/api/mall/warehouse'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const emit = defineEmits(['success'])
const props = defineProps({
opts: {
type: Object,

View File

@@ -6,8 +6,8 @@
<el-col :span="24" :offset="0">
<el-form-item label="审核" prop="isPass">
<el-radio-group v-model="form.isPass">
<el-radio :label="2">通过</el-radio>
<el-radio :label="3">驳回</el-radio>
<el-radio :label="true">通过</el-radio>
<el-radio :label="false">驳回</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@@ -23,13 +23,15 @@
<template #footer>
<span>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSave"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="handleSave"> </el-button>
</span>
</template>
</Dialog>
</template>
<script setup name="DialogAuditPurchase">
import { auditPurchase } from '@/api/mall/purchase'
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const form = ref({})
@@ -65,7 +67,7 @@ const open = (val, flag) => {
]
schema.value = [...schema.value, ...arr]
} else {
form.value.isPass = 2
form.value.isPass = true
form.value.auditRemark = ''
}
}
@@ -119,8 +121,19 @@ const resetSchema = () => {
]
}
function handleSave() {
console.log('保存')
const formLoading = ref(false)
const emit = defineEmits(['getList'])
async function handleSave() {
try {
formLoading.value = true
await auditPurchase(form.value)
message.success('审核完成')
dialogVisible.value = false
// 发送操作成功的事件
emit('getList')
} finally {
formLoading.value = false
}
}
</script>

View File

@@ -125,7 +125,7 @@
/>
<DialogAdd :opts="opts" ref="creatPurchase" />
<DialogAudit ref="auditPurchase" />
<DialogAudit ref="auditPurchase" @get-list="getList" />
</div>
</template>