Merge remote-tracking branch 'origin/master'

This commit is contained in:
zjf committed 2025-02-10 12:47:01 +08:00
commit f424b960ca
9 files changed
+150 -189

No files matched your search

-30
View File
@@ -1,30 +0,0 @@
You are an expert in TypeScript, Vite, Vue3, Vue Router, Pinia, VueUse ,Daisy UI, Element Plus, and Tailwind, with a deep understanding of best practices and performance optimization techniques in these technologies.
Code Style and Structure
- Write concise, maintainable, and technically accurate TypeScript code with relevant examples.
- Use functional and declarative programming patterns; avoid classes.
- Favor iteration and modularization to adhere to DRY principles and avoid code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Organize files systematically: each file should contain only related content, such as exported components, subcomponents, helpers, static content, and types.
Naming Conventions
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
- Favor named exports for functions.
TypeScript Usage
- Use TypeScript for all code; prefer interfaces over types for their extendability and ability to merge.
- Avoid enums; use maps instead for better type safety and flexibility.
- Use functional components with TypeScript interfaces.
Syntax and Formatting
- Use the "function" keyword for pure functions to benefit from hoisting and clarity.
- Always use the Vue Composition API script setup style.
- The order is template , typescript , Sass
UI and Styling
- Use Element Plus,Daisyui, and Tailwind for components and styling.
- Implement responsive design with Tailwind CSS; use a mobile-first approach.
- Styles need to support both light and dark modes
Performance Optimization
- Leverage VueUse functions where applicable to enhance reactivity and performance.
+3 -3
View File
@@ -8,9 +8,9 @@ VITE_OPEN = true
ENV = 'development'
# ADMIN 服务地址
#VITE_ADMIN_PROXY_PATH = http://123.156.230.15:8089/api/ # 线上
VITE_ADMIN_PROXY_PATH = http://123.156.230.15:8089/api/ # 线上
# VITE_ADMIN_PROXY_PATH = http://pjcloud.center.takin.cc/
VITE_ADMIN_PROXY_PATH = http://localhost:9999/
# VITE_ADMIN_PROXY_PATH = http://localhost:9999/
# VITE_ADMIN_PROXY_PATH = http://192.168.101.29:9999/ # 邓-本地
# VITE_ADMIN_PROXY_PATH = http://192.168.101.37:9999/ # 邓-本地
# VITE_ADMIN_PROXY_PATH = http://59.202.170.152:81/api # 正式环境
@@ -18,7 +18,7 @@ VITE_ADMIN_PROXY_PATH = http://localhost:9999/
# 图片访问基础地址
VITE_IMAGE_BASE_PATH = http://123.156.230.15:8089/api # 线上
# VITE_IMAGE_BASE_PATH = http://pjcloud.center.takin.cc
VITE_IMAGE_BASE_PATH = http://localhost:9999
# VITE_IMAGE_BASE_PATH = http://localhost:9999
# VITE_IMAGE_BASE_PATH = http://192.168.101.29:9999 # 邓-本地
# VITE_IMAGE_BASE_PATH = http://192.168.101.37:9999 # 邓-本地
# VITE_IMAGE_BASE_PATH = http://59.202.170.152:81/api/ # 正式环境
BIN
View File
Binary file not shown.
+11 -8
View File
@@ -70,20 +70,17 @@
draggable
@close=""
>
<!-- <el-row>
<el-form :model="foodQueryForm" ref="queryRef" :inline="true" @keyup.enter="getDataListAndSelect">
<el-row>
<el-form :inline="true" @keyup.enter="getDataList">
<el-form-item label="商品名称" prop="name">
<el-input placeholder="请输入商品名称" v-model="foodQueryForm.name" />
</el-form-item>
<el-form-item label="商品分类" prop="categoryId">
<select-ctcg v-model="foodQueryForm.categoryId" style="width: 200px" />
<el-input placeholder="请输入商品名称" v-model="state.queryForm.productName" />
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="getDataListAndSelect">查询</el-button>
<el-button icon="search" type="primary" @click="getDataList">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row> -->
</el-row>
<el-table
v-loading="state.loading"
@@ -234,9 +231,15 @@ const state: BasicTableProps = reactive<BasicTableProps>({
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } =
useTable(state)
const resetQuery = () => {
state.queryForm.productName = ""
getDataList()
}
// 点击选择库存商品
const handleClickSelectSpu = () => {
loading.value = true
resetQuery()
spuSelectDialogVisible.value = true
try {
getDataList()
@@ -37,7 +37,6 @@ const form = reactive<any>({
// 定义校验规则
const dataRules = ref({
barCode: [{ required: true, message: "条码不能为空", trigger: "blur" }],
spuId: [{ required: true, message: "spuID不能为空", trigger: "blur" }],
})
// 打开弹窗
@@ -47,6 +46,7 @@ const openDialog = (rowData: any = null) => {
// 重置表单数据
dataFormRef.value?.resetFields()
form.barCode = ""
if (rowData) {
Object.assign(form, rowData)
@@ -31,10 +31,12 @@
<el-col :span="14" class="mb20">
<el-form-item label="内装" prop="packageNum">
<el-alert type="warning" show-icon :closable="false">
<p>注:内装数据必须为该商品的最小售卖的基本单位,否则无法完成库存数量转换,影响erp库存自动扣减操作。
例如:一瓶矿泉水内装填'1',为售卖的最小基础单位,如果想按箱卖,在继续添加包装单位为箱,内装为24</p>
</el-alert>
<el-alert type="warning" show-icon :closable="false">
<p>
注:内装数据必须为该商品的最小售卖的基本单位,否则无法完成库存数量转换,影响erp库存自动扣减操作。
例如:一瓶矿泉水内装填'1',为售卖的最小基础单位,如果想按箱卖,在继续添加包装单位为箱,内装为24
</p>
</el-alert>
<el-input-number v-model="form.packageNum" :min="0" :precision="0" />
</el-form-item>
</el-col>
@@ -37,8 +37,9 @@
class="ml10"
v-auth="'supermarket_supermarketUnit_add'"
@click="formDialogRef.openDialog()"
>新 增</el-button
>
新 增
</el-button>
<!-- <el-button
plain
:disabled="multiple"
+113 -122
View File
@@ -68,52 +68,54 @@
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="单位" prop="unit">
<!-- <el-alert type="warning" show-icon>-->
<!-- <p>最小售卖的基本单位</p>-->
<!-- </el-alert>-->
<el-input placeholder="请输入单位" v-model.trim="form.unit" />
</el-form-item>
</el-col>
<el-col :span="14" class="mb20">
<el-form-item label="内装数" prop="packageNum">
<!-- <el-alert type="warning" show-icon >-->
<!-- <p>注:内装数据必须为该商品的基本单位的内装数,否则无法完成库存数量转换。-->
<!-- 例如:零售一瓶矿泉水内装数为1,按一箱售卖矿泉水内装填'24'</p>-->
<!-- </el-alert>-->
<el-input-number v-model="form.packageNum" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="零售价" prop="retailPrice">
<el-input-number v-model="form.retailPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="促销价" prop="promotionPrice">
<el-input-number v-model="form.promotionPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="进价" prop="purchasePrice">
<el-input-number v-model="form.purchasePrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="单位" prop="unit">
<!-- <el-alert type="warning" show-icon>-->
<!-- <p>最小售卖的基本单位</p>-->
<!-- </el-alert>-->
<el-input placeholder="请输入单位" v-model.trim="form.unit" />
</el-form-item>
</el-col>
<el-col :span="14" class="mb20">
<el-form-item label="内装数" prop="packageNum">
<!-- <el-alert type="warning" show-icon >-->
<!-- <p>注:内装数据必须为该商品的基本单位的内装数,否则无法完成库存数量转换。-->
<!-- 例如:零售一瓶矿泉水内装数为1,按一箱售卖矿泉水内装填'24'</p>-->
<!-- </el-alert>-->
<el-input-number v-model="form.packageNum" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="零售价" prop="retailPrice">
<el-input-number v-model="form.retailPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="促销价" prop="promotionPrice">
<el-input-number v-model="form.promotionPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="进价" prop="purchasePrice">
<el-input-number v-model="form.purchasePrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="成本价" prop="costPrice">
<el-input-number v-model="form.costPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="14" class="mb20">
<el-form-item label="总库存" prop="stock">
<el-alert type="warning" show-icon >
<p>注:最小售卖单位的总库存,否则无法换算完成库存扣减,每卖出一个包装形式的商品,都会进行总库存-内装数,实现多种包装形式售卖</p>
</el-alert>
<el-input-number v-model="form.stock" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="成本价" prop="costPrice">
<el-input-number v-model="form.costPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="14" class="mb20">
<el-form-item label="总库存" prop="stock">
<el-alert type="warning" show-icon>
<p>
注:最小售卖单位的总库存,否则无法换算完成库存扣减,每卖出一个包装形式的商品,都会进行总库存-内装数,实现多种包装形式售卖
</p>
</el-alert>
<el-input-number v-model="form.stock" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="商品状态" prop="status">
<el-radio-group v-model="form.status">
@@ -123,21 +125,21 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="规格" prop="spec">
<el-input placeholder="请输入规格" v-model.trim="form.specification" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="规格" prop="spec">
<el-input placeholder="请输入规格" v-model.trim="form.specification" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="产地" prop="origin">
<el-input v-model.trim="form.origin" placeholder="请输入产地" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序字段" prop="sort">
<el-input-number :min="0" :max="1000" :precision="0" v-model="form.sort" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序字段" prop="sort">
<el-input-number :min="0" :max="1000" :precision="0" v-model="form.sort" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="库存上限" prop="inventoryUpperLimit">
<el-input-number v-model="form.inventoryUpperLimit" :min="0" :precision="0" />
@@ -159,9 +161,7 @@
<supermarketUnit v-model:supermarketUnitEntityList="form.smErpUnitEntityList" />
</el-tab-pane>
<el-tab-pane label="辅助条码" name="辅助条码" style="overflow-y: auto; height: 60vh">
<supermarketAuxiliaryCode
v-model:supermarketAuxiliaryCodeEntityList="form.smErpAuxiliaryCodeEntityList"
/>
<supermarketAuxiliaryCode v-model:supermarketAuxiliaryCodeEntityList="form.smErpAuxiliaryCodeEntityList" />
</el-tab-pane>
</el-tabs>
</el-form>
@@ -171,24 +171,30 @@
<el-button @click="visible = false">取消</el-button>
<el-button v-if="currentTabPaneIndex != 0" type="primary" @click="currentTabPaneIndex--">上一步</el-button>
<el-button v-if="currentTabPaneIndex != 2" type="primary" @click="currentTabPaneIndex++">下一步</el-button>
<el-button v-if="currentTabPaneIndex == 2" type="primary" @click="onSubmit" :disabled="loading"
>确 认</el-button
>
<el-button v-if="currentTabPaneIndex == 2" type="primary" @click="onSubmit" :disabled="loading">
确 认
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { useDict } from "/src/hooks/dict"
import { useMessage } from "/src/hooks/message"
import { getObj, addObj, putObj, getSupermarketCategory, getSupermarketBrand } from "/src/api/supermarketerp/supermarketSpu"
import { getSupplierTypeOptions } from "/src/api/supermarketerp/smErpSupplier"
import { rule } from "/src/utils/validate"
import { useDict } from "/@/hooks/dict"
import { useMessage } from "/@/hooks/message"
import {
getObj,
addObj,
putObj,
getSupermarketCategory,
getSupermarketBrand,
} from "/@/api/supermarketerp/supermarketSpu"
import { getSupplierTypeOptions } from "/@/api/supermarketerp/smErpSupplier"
import { rule } from "/@/utils/validate"
import supermarketAuxiliaryCode from "./components/supermarketAuxiliaryCode/index.vue"
import supermarketUnit from "./components/supermarketUnit/index.vue"
import { TabPaneName } from "element-plus"
import { displayPrice, storePrice } from "/src/utils/formatMoney"
import { displayPrice, storePrice } from "/@/utils/formatMoney"
const emit = defineEmits(["refresh"])
@@ -198,7 +204,6 @@ const visible = ref(false)
const loading = ref(false)
const currentTabPaneIndex = ref(0)
const tabPaneActiveName = computed(() => tabPaneEnum[currentTabPaneIndex.value])
// 提交表单数据
const form = reactive({
id: "",
@@ -218,7 +223,7 @@ const form = reactive({
giveIntegral: 0,
specification: "",
origin: "",
packageNum: 0,
packageNum: 0,
retailPrice: 0,
purchasePrice: 0,
supplierId: "",
@@ -235,8 +240,8 @@ const form = reactive({
inventoryUpperLimit: 0,
inventoryLowerLimit: 0,
grossMargin: 0,
smErpUnitEntityList: [],
smErpAuxiliaryCodeEntityList: [],
smErpUnitEntityList: [],
smErpAuxiliaryCodeEntityList: [],
})
// 定义校验规则
const dataRules = {
@@ -245,40 +250,24 @@ const dataRules = {
productCode: [{ required: true, message: "货号不能为空", trigger: "blur" }],
barcode: [{ required: true, message: "自编码/条码不能为空", trigger: "blur" }],
productName: [{ required: true, message: "商品名称不能为空", trigger: "blur" }],
stock: [{ required: true, message: "单位不能为空", trigger: "blur" }],
unit: [{ required: true, message: "单位不能为空", trigger: "blur" }],
stock: [{ required: true, message: "总库存不能为空", trigger: "blur" }],
categoryId: [{ required: true, message: "商品分类不能为空", trigger: "blur" }],
brandId: [{ required: true, message: "品牌不能为空", trigger: "blur" }],
picUrl: [{ required: true, message: "商品封面图不能为空", trigger: "blur" }],
status: [{ required: true, message: "请选择商品状态", trigger: "blur" }],
supplierId: [{ required: true, message: "请选择货商", trigger: "blur" }],
smErpUnitEntityList: [{ required: true, message: "请添加包装单位", trigger: "change" }],
smErpAuxiliaryCodeEntityList: [{ required: true, message: "请添加辅助条码", trigger: "change" }],
// costPrice: [{ required: true, message: "成本价不能为空", trigger: "blur" }],
retailPrice: [{ required: true, message: "零售价不能为空", trigger: "blur" }],
unit: [{ required: true, message: "单位不能为空", trigger: "blur" }],
packageNum: [{ required: true, message: "内装数不能为空", trigger: "blur" }],
smErpUnitEntityList: [{ required: true, message: "请添加包装单位", trigger: "change" }],
smErpAuxiliaryCodeEntityList: [{ required: true, message: "请添加辅助条码", trigger: "change" }],
// costPrice: [{ required: true, message: "成本价不能为空", trigger: "blur" }],
retailPrice: [{ required: true, message: "零售价不能为空", trigger: "blur" }],
packageNum: [{ required: true, message: "内装数不能为空", trigger: "blur" }],
}
const { supermarket_nature, status } = useDict("supermarket_nature", "status")
const categoryOptions = ref<any>([]) // 商品分类的下拉选项
const brandOptions = ref<any>([]) // 超市品牌的下拉选项
const supplierOptions = ref<any>([]) // 货商的下拉选项
// 初始化表单数据
const getsupermarketSpuData = async (id: string) => {
// 获取数据
loading.value = true
const res = await getObj(id).finally(() => (loading.value = false))
res.data.smErpUnitEntityList.map((item: any) => {
item.costPrice = displayPrice(item.costPrice, "")
item.promotionPrice = displayPrice(item.promotionPrice, "")
item.purchasePrice = displayPrice(item.purchasePrice, "")
item.retailPrice = displayPrice(item.retailPrice, "")
})
Object.assign(form, res.data)
console.log(res.data)
}
// 打开弹窗
const openDialog = async (id: string) => {
visible.value = true
@@ -287,6 +276,8 @@ const openDialog = async (id: string) => {
// 重置表单数据
dataFormRef.value?.resetFields()
form.smErpUnitEntityList = []
form.smErpAuxiliaryCodeEntityList = []
// 获取supermarketSpu信息
if (id) {
@@ -294,34 +285,35 @@ const openDialog = async (id: string) => {
getsupermarketSpuData(id)
}
// 获取分类下拉选项
if (categoryOptions.value.length <= 0) {
try {
const res = await getSupermarketCategory()
categoryOptions.value = res.data
} catch (error) {
categoryOptions.value = []
}
}
// 获取分类下拉选项 & 获取品牌下拉选项 & 获取货商下拉选项
const [categoryDict, brandDict, supplierDict] = await Promise.allSettled([
getSupermarketCategory(),
getSupermarketBrand(),
getSupplierTypeOptions(),
]).then((results) => results.map((result) => (result.status === "fulfilled" ? result.value : null)))
// 获取品牌下拉选项
if (brandOptions.value.length <= 0) {
try {
const res = await getSupermarketBrand()
brandOptions.value = res.data
} catch (error) {
brandOptions.value = []
}
}
console.log(categoryDict, brandDict, supplierDict)
// 获取货商下拉选项
if (supplierOptions.value.length <= 0) {
try {
const res = await getSupplierTypeOptions()
supplierOptions.value = res.data
} catch (error) {
supplierOptions.value = []
}
categoryOptions && categoryDict.code === 0 && (categoryOptions.value = categoryDict.data)
brandOptions && brandDict.code === 0 && (brandOptions.value = brandDict.data)
supplierOptions && supplierDict.code === 0 && (supplierOptions.value = supplierDict.data)
}
// 初始化表单数据
const getsupermarketSpuData = async (id: string) => {
// 获取数据
loading.value = true
const res = await getObj(id).finally(() => (loading.value = false))
if (res.code === 0) {
res.data.smErpUnitEntityList.map((item: any) => {
// 格式化数据
item.retailPrice = displayPrice(item.retailPrice, "")
item.promotionPrice = displayPrice(item.promotionPrice, "")
item.purchasePrice = displayPrice(item.purchasePrice, "")
item.costPrice = displayPrice(item.costPrice, "")
})
Object.assign(form, res.data)
console.log(res.data)
}
}
@@ -336,8 +328,7 @@ const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {})
if (!valid) useMessage().warning("基础信息必填项未填写完整")
if (!form.smErpUnitEntityList || form.smErpUnitEntityList.length <= 0)
useMessage().warning("请添加包装单位")
if (!form.smErpUnitEntityList || form.smErpUnitEntityList.length <= 0) useMessage().warning("请添加包装单位")
if (!form.smErpAuxiliaryCodeEntityList || form.smErpAuxiliaryCodeEntityList.length <= 0)
useMessage().warning("请添加辅助条码")
if (!valid) return false
@@ -46,7 +46,7 @@
class="ml10 mr20"
style="float: right"
@queryTable="getDataList"
></right-toolbar>
/>
</div>
</el-row>
<el-table
@@ -76,7 +76,7 @@
</el-table-column>
<el-table-column prop="picUrl" label="封面图" width="100">
<template #default="scope">
<preview-image style="width: 50px; height: 50px" :src="imageBaseUrl + scope.row.picUrl" />
<preview-image :src="scope.row.picUrl" />
</template>
</el-table-column>
<el-table-column prop="status" label="商品状态" width="100">
@@ -134,28 +134,22 @@
</template>
<script setup lang="ts" name="systemSupermarketSpu">
import { BasicTableProps, useTable } from "/src/hooks/table"
import { fetchList, delObjs, getSupermarketCategory, getSupermarketBrand } from "/src/api/supermarketerp/supermarketSpu"
import { useMessage, useMessageBox } from "/src/hooks/message"
import { useDict } from "/src/hooks/dict"
const imageBaseUrl = import.meta.env.VITE_IMAGE_BASE_PATH
import { BasicTableProps, useTable } from "/@/hooks/table"
import { fetchList, delObjs, getSupermarketCategory, getSupermarketBrand } from "/@/api/supermarketerp/supermarketSpu"
import { useMessage, useMessageBox } from "/@/hooks/message"
import { useDict } from "/@/hooks/dict"
// 引入组件
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
const { supermarket_nature, status } = useDict("supermarket_nature", "status")
// 定义变量内容
const formDialogRef = ref()
// 搜索变量
const queryRef = ref()
const formDialogRef = ref() // 对话框ref引用
const queryRef = ref() // 搜索表单ref引用
const showSearch = ref(true)
// 多选变量
const selectObjs = ref([]) as any
const multiple = ref(true)
// 商品分类
const supermarketCategory = ref<any>([])
// 商品品牌
const supermarketBrand = ref<any>([])
const selectObjs = ref([]) as any // 表格行选中的数据
const multiple = ref(true) // 是否已经多选
const supermarketCategory = ref<any>([]) // 商品分类
const supermarketBrand = ref<any>([]) // 商品品牌
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
@@ -208,14 +202,14 @@ const handleDelete = async (ids: string[]) => {
}
onMounted(async () => {
// 商品分类
// 获取商品分类
try {
const res = await getSupermarketCategory()
supermarketCategory.value = res.data
} catch (error) {
supermarketCategory.value = []
}
// 商品品牌
// 获取商品品牌
try {
const res = await getSupermarketBrand()
supermarketBrand.value = res.data