feat:商品管理
This commit is contained in:
1 parent
f716bd685f
commit
a64cda2312
9 files changed
+411
-91
No files matched your search
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<crud-layout title="" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view class="h-30rpx" />
|
||||
<tm-form @submit="onsubmit" v-model="form" :rules="rules" direction="vertical">
|
||||
<view class="card p-20rpx mb-20rpx">
|
||||
<view class="prefix_title mb-2">商品基本信息</view>
|
||||
<tm-form-item name="title" label="商品标题" direction="horizontal">
|
||||
<tm-input v-model="form.title" type="text" :showClear="true" placeholder="请输入商品标题"></tm-input>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="unit" label="计量单位" direction="horizontal">
|
||||
<tm-input v-model="form.unit" type="text" :showClear="true" placeholder="请输入计量单位"></tm-input>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="status" label="状态" direction="horizontal">
|
||||
<tm-radio-group v-model="form.status" align="flex-end">
|
||||
<tm-radio :value="index.toString()" :label="item" v-for="(item, index) in ['上架', '下架']" :key="index"></tm-radio>
|
||||
</tm-radio-group>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="saleStartTime" label="开售时间" direction="horizontal">
|
||||
<tm-picker-date v-model="form.saleStartTime" v-model:modelStr="_saleStartTimeStr">
|
||||
<tm-input
|
||||
:modelValue="_saleStartTimeStr"
|
||||
placeholder="请选择开售时间"
|
||||
style="pointer-events: none"
|
||||
disabled
|
||||
align="right"
|
||||
color="transparent"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<tm-icon name="arrow-right-s-line"></tm-icon>
|
||||
</template>
|
||||
</tm-input>
|
||||
</tm-picker-date>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="saleEndTime" label="停售时间" direction="horizontal">
|
||||
<tm-picker-date v-model="form.saleEndTime" v-model:modelStr="_saleEndTimeStr">
|
||||
<tm-input
|
||||
:modelValue="_saleEndTimeStr"
|
||||
placeholder="请选择停售时间"
|
||||
style="pointer-events: none"
|
||||
disabled
|
||||
align="right"
|
||||
color="transparent"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<tm-icon name="arrow-right-s-line"></tm-icon>
|
||||
</template>
|
||||
</tm-input>
|
||||
</tm-picker-date>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="coverImage" label="商品图">
|
||||
<tm-upload-photo
|
||||
v-model="form.coverImage"
|
||||
:maxFileSize="1024 * 1024 * 5"
|
||||
:url="'/api/admin/sys-file/upload'"
|
||||
:header="hooks.useDefaultHeader()"
|
||||
:column="2"
|
||||
img-height="300"
|
||||
:max-count="1"
|
||||
/>
|
||||
</tm-form-item>
|
||||
<view class="sub-text-20 c-red! mb-2">注:图片大小不超过5M</view>
|
||||
<tm-form-item name="description" label="详情描述">
|
||||
<tm-input v-model="form.description" type="textarea" :showClear="false" placeholder="请输入详情描述"></tm-input>
|
||||
</tm-form-item>
|
||||
</view>
|
||||
</tm-form>
|
||||
|
||||
<view class="card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<tm-picker
|
||||
rang-key="title"
|
||||
rang-text="title"
|
||||
v-model="applyForm.reason"
|
||||
v-model:model-str="applyForm.reasonStr"
|
||||
:list="state.selectList"
|
||||
>
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-28">申请原因</view>
|
||||
<view class="flex-row items-center second-text-24">
|
||||
<text>{{ applyForm.reasonStr || "请选择申请原因" }} </text>
|
||||
<text class="m-l-10rpx color-#b1b1b1 iconfont icon-xiangxiajiantouxiao" />
|
||||
</view>
|
||||
</view>
|
||||
</tm-picker>
|
||||
</view>
|
||||
|
||||
<view class="h-30rpx" />
|
||||
|
||||
<template #main-bottom>
|
||||
<view class="bg-#0094ff py-20rpx text-center rounded-40rpx m-30rpx sub-text-30 color-white!" @tap="doSubmit"> 保存 </view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue"
|
||||
import { hooks } from "@@/index"
|
||||
|
||||
const form = reactive<any>({})
|
||||
const _saleStartTimeStr = ref("")
|
||||
const _saleEndTimeStr = ref("")
|
||||
|
||||
// 保存
|
||||
const doSubmit = async () => {}
|
||||
</script>
|
||||
@@ -1,30 +1,206 @@
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<template #top> </template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="100%"
|
||||
:fixed="false"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<template #top>
|
||||
<view class="w-full mt-2 flex items-center gap-2">
|
||||
<tm-button size="m" @click="addGoods">新 增</tm-button>
|
||||
<tm-button size="m">分 类</tm-button>
|
||||
<tm-input
|
||||
class="flex-1"
|
||||
v-model="state.params.keyword"
|
||||
type="text"
|
||||
height="72"
|
||||
minHeight="72"
|
||||
fontSize="28"
|
||||
:showClear="true"
|
||||
:focus="false"
|
||||
placeholder="请输入商品名称"
|
||||
style="border: 4rpx solid #0779fd; border-radius: 14rpx"
|
||||
:focus-highlight="false"
|
||||
color="#ECF4F9"
|
||||
@clear="inputClear"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<tm-button class="mr-1 px-3 py-26rpx text-30rpx!" size="xs" @click="search">搜 索</tm-button>
|
||||
</template>
|
||||
</tm-input>
|
||||
</view>
|
||||
<scroll-view scroll-x>
|
||||
<view class="w-full flex my-2">
|
||||
<view
|
||||
class="w-300rpx mr-2 sub-text-28 py-1 px-2 rounded-1 bg-#fff border border-solid border-transparent whitespace-nowrap"
|
||||
:class="{ 'bg-#0779FD22! c-#0779FD! border-#0779FD33!': state.params.categoryId === v.id }"
|
||||
v-for="(v, i) in state.category"
|
||||
:key="i"
|
||||
@tap="doClassify(v.id)"
|
||||
>
|
||||
{{ v.name }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<view v-for="v in pageHook.list" :key="v.id" class="card mx-20rpx mb-2 px-4 py-2">
|
||||
<view class="flex">
|
||||
<image
|
||||
:src="filePath(v.coverImage)"
|
||||
class="size-180rpx rounded-12rpx bg-#eeeeee"
|
||||
mode="aspectFill"
|
||||
@click.stop="hooks.usePreviewImage(filePath(v.coverImage))"
|
||||
/>
|
||||
<view class="flex-1 ml-2 overflow-hidden">
|
||||
<view class="truncate sub-text-34">{{ v.title }}</view>
|
||||
<view class="sub-text-26 mt-4rpx">
|
||||
<text class="c-#0094ff! px-2 bg-#0094ff22 rounded-2 mr-2">
|
||||
{{ state.category.find((item) => item.id == v.categoryId)?.name || "未知分类" }}
|
||||
</text>
|
||||
<text class="c-#0094ff! px-2 bg-#0094ff22 rounded-2">{{ v.status == "0" ? "在售" : "未售" }}</text>
|
||||
</view>
|
||||
<view class="mt-4rpx">
|
||||
<text class="second-text-28 mr-2">单位 {{ v.unit }}</text>
|
||||
<text class="second-text-28">库存 {{ v.totalStock }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text class="second-text-32 line-through mr-1">
|
||||
<text class="text-30rpx">¥</text>
|
||||
<text class="font-bold">{{ v.originalPrice.toFixed(2) }}</text>
|
||||
</text>
|
||||
<text class="color-red">
|
||||
<text class="text-30rpx">¥</text>
|
||||
<text class="text-46rpx font-bold">{{ v.spuPrice.toFixed(2).split(".")[0] }}.</text>
|
||||
<text class="text-38rpx font-bold">{{ v.spuPrice.toFixed(2).split(".")[1] }}</text>
|
||||
</text>
|
||||
<text class="view-clip px-1 text-20rpx c-white bg-red ml-1 rounded-r-1 rounded-lt-1">到手价</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="my-2 h-1rpx bg-#A0A0A044"></view>
|
||||
<view class="flex gap-2 justify-end">
|
||||
<tm-button class="px-2" size="s" :linear="['to right', '#FFC328', '#E2000099']" @click.stop="deleteGoods(v.id)">
|
||||
删除商品
|
||||
</tm-button>
|
||||
<tm-button class="px-2" size="s" :linear="['to right', '#62abff', '#0779FD99']" @click.stop="editGoods(v.id)">
|
||||
编辑商品
|
||||
</tm-button>
|
||||
<tm-button class="px-2" size="s" :linear="['to right', '#00B960', '#00552C99']" @click.stop="doGoodsDetail(v.id)">
|
||||
查看详情
|
||||
</tm-button>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue"
|
||||
import { reactive, ref } from "vue"
|
||||
import { prosperityShopApi } from "@/sheep/api"
|
||||
import { hooks } from "@/sheep"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
|
||||
const state = reactive({
|
||||
goodsList: [],
|
||||
const state = reactive<any>({
|
||||
params: {
|
||||
keyword: "",
|
||||
categoryId: "",
|
||||
},
|
||||
category: [],
|
||||
curCategoryIndex: 0,
|
||||
})
|
||||
|
||||
const pageRef = ref<any>(null)
|
||||
const pageHook = hooks.usePage(pageRef, prosperityShopApi.getGoodsList, null, "data.records")
|
||||
|
||||
const query = (page: number, pagesize: number) => {
|
||||
pageHook.startPage(page, pagesize, false, state.params)
|
||||
}
|
||||
|
||||
onLoad(async () => {
|
||||
await getGoodsList()
|
||||
await getGoodsCategory()
|
||||
})
|
||||
|
||||
const getGoodsList = async () => {
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 99999,
|
||||
// categoryId: state.category[state.curCategoryIndex].id,
|
||||
}
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsList(params)
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品列表获取失败", icon: "none" })
|
||||
state.goodsList = data?.records ?? []
|
||||
const getGoodsCategory = async () => {
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsCategory()
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品分类获取失败", icon: "none" })
|
||||
state.category = data ?? []
|
||||
state.category.unshift({ id: "", name: "全部分类" })
|
||||
}
|
||||
|
||||
// 切换分类
|
||||
const doClassify = async (categoryId: string) => {
|
||||
if (state.params.categoryId == categoryId) return
|
||||
state.params.categoryId = categoryId
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 点击搜索
|
||||
const search = () => {
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const inputClear = () => {
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const doGoodsDetail = (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
uni.navigateTo({
|
||||
url: `/pages/prosperity-shop/goods-detail?id=${id}`,
|
||||
})
|
||||
}
|
||||
|
||||
// 新增商品
|
||||
const addGoods = () => {
|
||||
uni.navigateTo({ url: `/pages/prosperity-shop/goods-form` })
|
||||
}
|
||||
|
||||
// 编辑商品
|
||||
const editGoods = (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
uni.navigateTo({ url: `/pages/prosperity-shop/goods-form?id=${id}` })
|
||||
}
|
||||
|
||||
// 删除商品
|
||||
const deleteGoods = (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
uni.showModal({
|
||||
title: "确定删除商品吗?",
|
||||
content: "",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
const { code } = await prosperityShopApi.deleteGoods(id)
|
||||
if (code != 0) return uni.showToast({ title: "删除失败", icon: "error" })
|
||||
uni.showToast({ title: "删除成功", icon: "none" })
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.view-clip {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -18rpx;
|
||||
bottom: 0rpx;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: radial-gradient(circle at 0 0, transparent 80%, red 0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -94,7 +94,7 @@ onLoad((options: any) => {
|
||||
|
||||
// 点击搜索
|
||||
const search = () => {
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const doGoodsDetail = (id: string) => {
|
||||
|
||||
@@ -108,7 +108,7 @@ onLoad(async (option: any) => {
|
||||
uni.showLoading({ title: "加载中..." })
|
||||
state.id = option.id
|
||||
await getShopDetail(option.id)
|
||||
await getGoodsCategory(option.id)
|
||||
await getGoodsCategoryTree(option.id)
|
||||
await getGoodsList()
|
||||
uni.hideLoading()
|
||||
})
|
||||
@@ -119,8 +119,8 @@ const getShopDetail = async (id: string) => {
|
||||
state.detail = data
|
||||
}
|
||||
|
||||
const getGoodsCategory = async (id: string) => {
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsCategory({ merchantId: id })
|
||||
const getGoodsCategoryTree = async (id: string) => {
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsCategoryTree({ merchantId: id })
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品分类获取失败", icon: "none" })
|
||||
state.category = treeToList(data) ?? []
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ const getClassify = async () => {
|
||||
state.classifyList.unshift({ id: "", name: "全部分类" })
|
||||
if (!isEmpty(state.classifyList)) {
|
||||
state.params.categoryId = state.classifyList[0].id
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,20 +234,20 @@ const confirmRadioMerchant = async () => {
|
||||
state.params.merchantId = state.curMerchant.id
|
||||
cartStore.saveShopMerchantId(state.curMerchant.id)
|
||||
await cartStore.getShopCart()
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 点击搜索
|
||||
const searchProduct = () => {
|
||||
state.params.categoryId = ""
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 切换分类
|
||||
const doClassify = async (categoryId: string) => {
|
||||
if (state.params.categoryId == categoryId) return
|
||||
state.params.categoryId = categoryId
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const pageHook = hooks.usePage(pageRef, onlineShopApi.getSpuList, null, "data.records")
|
||||
|
||||
@@ -136,13 +136,13 @@ onLoad(async () => {
|
||||
// const doClassify = async (categoryId: string) => {
|
||||
// if (state.params.categoryId == categoryId) return
|
||||
// state.params.categoryId = categoryId
|
||||
// pageRef.value && pageRef.value.reload(true)
|
||||
// pageRef.value && pageRef.value.reload(false)
|
||||
// }
|
||||
|
||||
// 点击搜索
|
||||
const search = () => {
|
||||
// state.params.categoryId = ""
|
||||
pageRef.value && pageRef.value.reload(true)
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 联系商家
|
||||
|
||||
Reference in new issue
Block a user