diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 55e933ed..32848b9a 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -2,9 +2,9 @@ import { Layout } from '@/utils/routerHelper' const { t } = useI18n() /** -* redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 -* name:'router-name' 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 -* meta : { + * redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 + * name:'router-name' 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 + * meta : { hidden: true 当设置 true 的时候该路由不会再侧边栏出现 如404,login等页面(默认 false) alwaysShow: true 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式, @@ -31,7 +31,7 @@ const { t } = useI18n() canTo: true 设置为true即使hidden为true,也依然可以进行路由跳转(默认 false) } -**/ + **/ const remainingRouter: AppRouteRecordRaw[] = [ { path: '/redirect', @@ -345,6 +345,29 @@ const remainingRouter: AppRouteRecordRaw[] = [ meta: { title: '商品属性值', icon: '', activeMenu: '/product/property' } } ] + }, + { + path: '/product', + component: Layout, + name: 'ProductManagementEdit', + meta: { + hidden: true + }, + children: [ + { + path: 'productManagementAdd', + component: () => import('@/views/mall/product/management/addForm.vue'), + name: 'ProductManagementAdd', + meta: { + noCache: true, + hidden: true, + canTo: true, + icon: 'ep:edit', + title: '添加商品', + activeMenu: '/product/product-management' + } + } + ] } ] diff --git a/src/views/mall/product/management/addForm.vue b/src/views/mall/product/management/addForm.vue new file mode 100644 index 00000000..d077df5b --- /dev/null +++ b/src/views/mall/product/management/addForm.vue @@ -0,0 +1,53 @@ +<template> + <ContentWrap v-loading="formLoading"> + <el-tabs v-model="activeName"> + <el-tab-pane label="商品信息" name="basicInfo"> + <BasicInfoForm ref="basicInfoRef" /> + </el-tab-pane> + <el-tab-pane label="商品详情" name="description"> + <DescriptionForm ref="DescriptionRef" /> + </el-tab-pane> + <el-tab-pane label="其他设置" name="otherSettings"> + <OtherSettingsForm ref="otherSettingsRef" /> + </el-tab-pane> + </el-tabs> + <el-form> + <el-form-item style="float: right"> + <el-button :loading="formLoading" type="primary" @click="submitForm">保存</el-button> + <el-button @click="close">返回</el-button> + </el-form-item> + </el-form> + </ContentWrap> +</template> +<script lang="ts" name="ProductManagementForm" setup> +import { useTagsViewStore } from '@/store/modules/tagsView' +import { BasicInfoForm, DescriptionForm, OtherSettingsForm } from './components' + +// const { t } = useI18n() // 国际化 +// const message = useMessage() // 消息弹窗 +const { push, currentRoute } = useRouter() // 路由 +// const { query } = useRoute() // 查询参数 +const { delView } = useTagsViewStore() // 视图操作 + +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const activeName = ref('otherSettings') // Tag 激活的窗口 +const basicInfoRef = ref<ComponentRef<typeof BasicInfoForm>>() +const DescriptionRef = ref<ComponentRef<typeof DescriptionForm>>() + +/** 获得详情 */ +const getDetail = async () => {} + +/** 提交按钮 */ +const submitForm = async () => {} + +/** 关闭按钮 */ +const close = () => { + delView(unref(currentRoute)) + push('/product/product-management') +} + +/** 初始化 */ +onMounted(() => { + getDetail() +}) +</script> diff --git a/src/views/mall/product/management/components/BasicInfoForm.vue b/src/views/mall/product/management/components/BasicInfoForm.vue new file mode 100644 index 00000000..1b33e9eb --- /dev/null +++ b/src/views/mall/product/management/components/BasicInfoForm.vue @@ -0,0 +1,191 @@ +<template> + <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px"> + <el-row> + <el-col :span="12"> + <el-form-item label="商品名称" prop="name"> + <el-input v-model="formData.name" placeholder="请输入商品名称" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="商品分类" prop="categoryId"> + <el-tree-select + v-model="formData.categoryId" + :data="[]" + :props="defaultProps" + check-strictly + node-key="id" + placeholder="请选择商品分类" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="商品关键字" prop="keyword"> + <el-input v-model="formData.keyword" placeholder="请输入商品关键字" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="单位" prop="unit"> + <el-input v-model="formData.unit" placeholder="请输入单位" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="商品简介" prop="introduction"> + <el-input + v-model="formData.introduction" + :rows="3" + placeholder="请输入商品简介" + type="textarea" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="商品封面图" prop="picUrl"> + <div class="demo-image__preview pt-5px pb-5px pl-11x pr-11px"> + <el-image + :initial-index="0" + :preview-src-list="srcList" + :src="url" + :zoom-rate="1.2" + fit="cover" + style="width: 100%; height: 90px" + /> + </div> + </el-form-item> + </el-col> + <el-col :span="24"> + <el-form-item label="商品轮播图" prop="sliderPicUrls"> + <el-button>添加轮播图</el-button> + <el-carousel :interval="3000" height="200px" style="width: 100%" type="card"> + <el-carousel-item v-for="item in 6" :key="item"> + <h3 justify="center" text="2xl">{{ item }}</h3> + </el-carousel-item> + </el-carousel> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="运费模板" prop="deliveryTemplateId"> + <el-select v-model="formData.deliveryTemplateId" placeholder="请选择" style="width: 100%"> + <el-option v-for="item in []" :key="item.id" :label="item.name" :value="item.id" /> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-button class="ml-20px">运费模板</el-button> + </el-col> + <el-col :span="12"> + <el-form-item label="商品规格" props="specType"> + <el-radio-group v-model="formData.specType" @change="changeSpecType(formData.specType)"> + <el-radio :label="false" class="radio">单规格</el-radio> + <el-radio :label="true">多规格</el-radio> + </el-radio-group> + </el-form-item> + </el-col> + <!-- TODO 商品规格和分销类型切换待定 --> + <el-col :span="12"> + <el-form-item label="分销类型" props="subCommissionType"> + <el-radio-group + v-model="formData.subCommissionType" + @change="changeSubCommissionType(formData.subCommissionType)" + > + <el-radio :label="false">默认设置</el-radio> + <el-radio :label="true" class="radio">自行设置</el-radio> + </el-radio-group> + </el-form-item> + </el-col> + <!-- 多规格添加--> + <el-col v-if="formData.specType" :span="24"> + <el-form-item label="选择规格" prop=""> + <div class="acea-row"> + <el-select v-model="formData.selectRule"> + <el-option + v-for="item in []" + :key="item.id" + :label="item.ruleName" + :value="item.id" + /> + </el-select> + <el-button class="mr-20px" type="primary" @click="confirm">确认</el-button> + <el-button class="mr-15px" @click="addRule">添加规格</el-button> + </div> + </el-form-item> + </el-col> + </el-row> + </el-form> +</template> +<script lang="ts" name="ProductManagementBasicInfoForm" setup> +// TODO 商品封面测试数据 +import { defaultProps } from '@/utils/tree' + +const url = 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg' +const srcList = ['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'] + +const formRef = ref() +const formData = ref({ + name: '', // 商品名称 + categoryId: '', // 商品分类 + keyword: '', // 关键字 + unit: '', // 单位 + picUrl: '', // 商品封面图 + sliderPicUrls: [], // 商品轮播图 + introduction: '', // 商品简介 + deliveryTemplateId: '', // 运费模版 + selectRule: '', + specType: false, // 商品规格 + subCommissionType: false // 分销类型 +}) +const rules = reactive({ + name: [required], + categoryId: [required], + keyword: [required], + unit: [required], + picUrl: [required], + sliderPicUrls: [required], + deliveryTemplateId: [required], + specType: [required], + subCommissionType: [required] +}) +// 选择规格 +const changeSpecType = (specType) => { + console.log(specType) +} +// 分销类型 +const changeSubCommissionType = (subCommissionType) => { + console.log(subCommissionType) +} +// 选择属性确认 +const confirm = () => {} +// 添加规格 +const addRule = () => {} +</script> +<style scoped> +/*TODO 商品轮播图测试样式*/ +.el-carousel__item h3 { + color: #475669; + opacity: 0.75; + line-height: 200px; + margin: 0; + text-align: center; +} + +.el-carousel__item:nth-child(2n) { + background-color: #99a9bf; +} + +.el-carousel__item:nth-child(2n + 1) { + background-color: #d3dce6; +} + +/*TODO 商品封面测试样式*/ +.demo-image__error .image-slot { + font-size: 30px; +} + +.demo-image__error .image-slot .el-icon { + font-size: 30px; +} + +.demo-image__error .el-image { + width: 100%; + height: 200px; +} +</style> diff --git a/src/views/mall/product/management/components/DescriptionForm.vue b/src/views/mall/product/management/components/DescriptionForm.vue new file mode 100644 index 00000000..53609705 --- /dev/null +++ b/src/views/mall/product/management/components/DescriptionForm.vue @@ -0,0 +1,13 @@ +<template> + <!--富文本编辑器组件--> + <el-row> + <Editor v-model="content" :editor-config="editorConfig" /> + </el-row> +</template> +<script lang="ts" name="DescriptionForm" setup> +import { Editor } from '@/components/Editor' +import { createEditorConfig } from '@/views/mp/draft/editor-config' +// TODO 模拟参数 +const content = ref('') +const editorConfig = createEditorConfig('', 1) +</script> diff --git a/src/views/mall/product/management/components/OtherSettingsForm.vue b/src/views/mall/product/management/components/OtherSettingsForm.vue new file mode 100644 index 00000000..e8152883 --- /dev/null +++ b/src/views/mall/product/management/components/OtherSettingsForm.vue @@ -0,0 +1,94 @@ +<template> + <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px"> + <el-row> + <el-col :span="24"> + <el-col :span="8"> + <el-form-item label="商品排序"> + <el-input-number v-model="formData.sort" :min="0" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="赠送积分"> + <el-input-number v-model="formData.giveIntegral" :min="0" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="虚拟销量"> + <el-input-number + v-model="formData.virtualSalesCount" + :min="0" + placeholder="请输入虚拟销量" + /> + </el-form-item> + </el-col> + </el-col> + <el-col :span="24"> + <el-form-item label="商品推荐"> + <el-checkbox-group v-model="checkboxGroup" @change="onChangeGroup"> + <el-checkbox v-for="(item, index) in recommend" :key="index" :label="item.value"> + {{ item.name }} + </el-checkbox> + </el-checkbox-group> + </el-form-item> + </el-col> + <el-col :span="24"> + <!-- TODO tag展示暂时不考虑排序 --> + <el-form-item label="活动优先级"> + <el-tag>默认</el-tag> + <el-tag class="ml-2" type="success">秒杀</el-tag> + <el-tag class="ml-2" type="info">砍价</el-tag> + <el-tag class="ml-2" type="warning">拼团</el-tag> + </el-form-item> + </el-col> + <el-col :span="24"> + <el-form-item label="赠送优惠劵"> + <el-button>选择优惠券</el-button> + </el-form-item> + </el-col> + </el-row> + </el-form> +</template> +<script lang="ts" name="OtherSettingsForm" setup> +// 商品推荐 +const recommend = [ + { name: '是否热卖', value: 'recommendHot' }, + { name: '是否优惠', value: 'recommendBenefit' }, + { name: '是否精品', value: 'recommendBest' }, + { name: '是否新品', value: 'recommendNew' }, + { name: '是否优品', value: 'recommendGood' } +] +const checkboxGroup = ref<string[]>([]) +const onChangeGroup = () => { + checkboxGroup.value.includes('recommendHot') + ? (formData.value.recommendHot = true) + : (formData.value.recommendHot = false) + checkboxGroup.value.includes('recommendBenefit') + ? (formData.value.recommendBenefit = true) + : (formData.value.recommendBenefit = false) + checkboxGroup.value.includes('recommendBest') + ? (formData.value.recommendBest = true) + : (formData.value.recommendBest = false) + checkboxGroup.value.includes('recommendNew') + ? (formData.value.recommendNew = true) + : (formData.value.recommendNew = false) + checkboxGroup.value.includes('recommendGood') + ? (formData.value.recommendGood = true) + : (formData.value.recommendGood = false) +} +const formRef = ref() +const formData = ref({ + sort: '', + giveIntegral: 666, + virtualSalesCount: 565656, + recommendHot: false, + recommendBenefit: false, + recommendBest: false, + recommendNew: false, + recommendGood: false +}) +const rules = reactive({ + sort: [required], + giveIntegral: [required], + virtualSalesCount: [required] +}) +</script> diff --git a/src/views/mall/product/management/components/index.ts b/src/views/mall/product/management/components/index.ts new file mode 100644 index 00000000..04e6f74d --- /dev/null +++ b/src/views/mall/product/management/components/index.ts @@ -0,0 +1,5 @@ +import BasicInfoForm from './BasicInfoForm.vue' +import DescriptionForm from './DescriptionForm.vue' +import OtherSettingsForm from './OtherSettingsForm.vue' + +export { BasicInfoForm, DescriptionForm, OtherSettingsForm } diff --git a/src/views/mall/product/management/index.vue b/src/views/mall/product/management/index.vue new file mode 100644 index 00000000..4fdfed1b --- /dev/null +++ b/src/views/mall/product/management/index.vue @@ -0,0 +1,225 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + ref="queryFormRef" + :inline="true" + :model="queryParams" + class="-mb-15px" + label-width="68px" + > + <el-form-item label="品牌名称" prop="name"> + <el-input + v-model="queryParams.name" + class="!w-240px" + clearable + placeholder="请输入品牌名称" + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item label="状态" prop="status"> + <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="请选择状态"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + end-placeholder="结束日期" + start-placeholder="开始日期" + type="daterange" + value-format="YYYY-MM-DD HH:mm:ss" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon class="mr-5px" icon="ep:search" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon class="mr-5px" icon="ep:refresh" /> + 重置 + </el-button> + <el-button + v-hasPermi="['product:brand:create']" + plain + type="primary" + @click="openForm('create')" + > + <Icon class="mr-5px" icon="ep:plus" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-tabs v-model="queryParams.type" @tab-click="getList"> + <el-tab-pane + v-for="(item, index) in headerNum" + :key="index" + :label="item.name + '(' + item.count + ')'" + :name="item.type.toString()" + /> + </el-tabs> + <el-table v-loading="loading" :data="list"> + <el-table-column type="expand"> + <template #default="{ row }"> + <el-form class="demo-table-expand" inline label-position="left"> + <el-form-item label="市场价:"> + <span>{{ row.marketPrice }}</span> + </el-form-item> + <el-form-item label="成本价:"> + <span>{{ row.costPrice }}</span> + </el-form-item> + <el-form-item label="虚拟销量:"> + <span>{{ row.virtualSalesCount }}</span> + </el-form-item> + </el-form> + </template> + </el-table-column> + <el-table-column label="商品图" min-width="80"> + <template #default="{ row }"> + <div class="demo-image__preview"> + <el-image + :preview-src-list="[row.image]" + :src="row.image" + style="width: 36px; height: 36px" + /> + </div> + </template> + </el-table-column> + <el-table-column + :show-overflow-tooltip="true" + label="商品名称" + min-width="300" + prop="storeName" + /> + <el-table-column align="center" label="商品售价" min-width="90" prop="price" /> + <el-table-column align="center" label="销量" min-width="90" prop="sales" /> + <el-table-column align="center" label="库存" min-width="90" prop="stock" /> + <el-table-column align="center" label="排序" min-width="70" prop="sort" /> + <el-table-column + :formatter="dateFormatter" + align="center" + label="创建时间" + prop="createTime" + width="180" + /> + <el-table-column fixed="right" label="状态" min-width="80"> + <template #default="{ row }"> + <!--TODO 暂时用COMMON_STATUS占位一下使其不报错 --> + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" /> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" min-width="150" /> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.pageNo" + :total="total" + @pagination="getList" + /> + </ContentWrap> +</template> +<script lang="ts" name="ProductManagement" setup> +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' + +// const message = useMessage() // 消息弹窗 +// const { t } = useI18n() // 国际化 +const { push } = useRouter() // 路由跳转 +const loading = ref(false) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref<any[]>([]) // 列表的数据 +const headerNum = ref([ + { + count: 8, + name: '出售中商品', + type: 1 + }, + { + count: 0, + name: '仓库中商品', + type: 2 + }, + { + count: 0, + name: '已经售馨商品', + type: 3 + }, + { + count: 0, + name: '警戒库存', + type: 4 + }, + { + count: 0, + name: '商品回收站', + type: 5 + } +]) +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: undefined, + status: undefined, + createTime: [], + type: '1' +}) +const queryFormRef = ref() // 搜索的表单 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await ProductBrandApi.getBrandParam(queryParams) + // list.value = data.list + // total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +const openForm = () => { + push('/product/productManagementAdd') +} + +/** 删除按钮操作 */ +// const handleDelete = async (id: number) => { +// try { +// // 删除的二次确认 +// await message.delConfirm() +// // 发起删除 +// await ProductBrandApi.deleteBrand(id) +// message.success(t('common.delSuccess')) +// // 刷新列表 +// await getList() +// } catch {} +// } + +/** 初始化 **/ +onMounted(() => { + // getList() +}) +</script>