修改bug

This commit is contained in:
郑彪辉
2025-04-23 23:51:02 +08:00
parent 3e63f64875
commit 07ac63b5bb
952 changed files with 6465 additions and 79209 deletions

View File

@@ -14,9 +14,15 @@
</view>
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('code')" prop="code" required borderBottom>
<u-input fontSize="28rpx" v-model.trim="formData.code" disabled clearable
placeholderStyle="color: #888" :placeholder="t('codePlaceholderNew')" />
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('name')" prop="name" required borderBottom>
<u-input fontSize="28rpx" v-model.trim="formData.name" border="none" clearable
<u-input fontSize="28rpx" v-model.trim="formData.name" clearable
placeholderStyle="color: #888" :placeholder="t('namePlaceholder')" />
</u-form-item>
</view>
@@ -33,7 +39,7 @@
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('spec')" prop="spec" borderBottom>
<u-input fontSize="28rpx" v-model.trim="formData.spec" border="none" clearable
<u-input fontSize="28rpx" v-model.trim="formData.spec" clearable
placeholderStyle="color: #888" :placeholder="t('specPlaceholder')" />
</u-form-item>
</view>
@@ -41,30 +47,55 @@
<view class="mt-[16rpx]">
<u-form-item :label="t('minWarning')" prop="min_warning" borderBottom>
<u-input fontSize="28rpx" type="number" v-model="formData.min_warning"
:placeholder="t('minWarningPlaceholder')" border="none"></u-input>
:placeholder="t('minWarningPlaceholder')" ></u-input>
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('maxWarning')" prop="max_warning" borderBottom>
<u-input fontSize="28rpx" type="number" v-model="formData.max_warning" border="none" clearable
<u-input fontSize="28rpx" type="number" v-model="formData.max_warning" clearable
maxlength="120" :placeholder="t('maxWarningPlaceholder')" placeholderStyle="color: #888" />
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('expiryTerm')" prop="expiry_term" borderBottom>
<u-input fontSize="28rpx" type="number" v-model="formData.expiry_term" clearable
maxlength="120" :placeholder="t('expiryTermPlaceholder')" placeholderStyle="color: #888" />
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('expiryAlertTerm')" prop="expiry_alert_term" borderBottom>
<u-input fontSize="28rpx" type="number" v-model="formData.expiry_alert_term" clearable
maxlength="120" :placeholder="t('expiryAlertTermPlaceholder')" placeholderStyle="color: #888" />
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('remark')" prop="remark">
<u-textarea fontSize="28rpx" v-model="formData.remark" :placeholder="t('remarkPlaceholder')"
border="none"></u-textarea>
></u-textarea>
</u-form-item>
</view>
<view class="mt-[16rpx]">
<u-form-item :label="t('image')" prop="image" borderBottom>
<up-upload
:fileList="imageFileList"
@afterRead="afterRead"
@delete="imageDelete"
multiple
:maxCount="5"
accept="image"
:capture="['camera']"
></up-upload>
</u-form-item>
</view>
</view>
</u-form>
<!-- 产品分类 -->
<!-- 食材分类 -->
<u-action-sheet class="" :actions="pidList" :show="pidSheetShow" :closeOnClickOverlay="true"
:safeAreaInsetBottom="true" @close="pidSheetShow = false" @select="updateSex"></u-action-sheet>
<!-- 产品单位 -->
<!-- 食材单位 -->
<u-action-sheet class="" :actions="unitList" :show="unitSheetShow" :closeOnClickOverlay="true"
:safeAreaInsetBottom="true" @close="unitSheetShow = false" @select="updateSexUnit"></u-action-sheet>
@@ -87,8 +118,17 @@
import { onLoad } from '@dcloudio/uni-app';
import { getProductTypeSelect, getProductUnitSelect, addProduct } from '@/addon/erp/api/product';
import { generatedCode } from '@/addon/erp/utils/common';
import {uploadImage } from '@/app/api/system'
import { redirect } from '@/utils/common';
import { checkBtnPermission } from '@/utils/auth';
import useMemberStore from '@/stores/member'
const memberStore = useMemberStore()
interface FileItem {
url: string;
status?: string;
message?: string;
}
const formRef : any = ref(null)
const loading = ref(false)
@@ -110,7 +150,7 @@
trigger: ['blur', 'change'],
},
'product_unit_id': {
type: 'string',
type: 'number',
required: true,
message: t('productUnitIdPlaceholder'),
trigger: ['blur', 'change'],
@@ -126,7 +166,7 @@
const formData = ref({
id: "",
code: generatedCode("P"),
code:generatedCode("P"),
name: "",
product_type_id: "",
product_type_name: "",
@@ -137,9 +177,12 @@
remark: "",
product_unit_id: "",
product_unit_name: "",
expiry_term :"",
expiry_alert_term:"",
image: "",
})
const imageFileList=ref<FileItem[]>([])
/**
* 分类
*/
@@ -182,15 +225,63 @@
})
}
const afterRead = async (event: any) => {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists:FileItem[] = [].concat(event.file) ;
let fileListLen = imageFileList.value.length;
lists = lists.filter((item:FileItem) => item.url);
lists.map((item: any) => {
imageFileList.value.push({
url: item.url,
status: 'uploading',
message: '上传中',
});
})
for (let i = 0; i < lists.length; i++) {
const result = await uploadFilePromise(lists[i].url);
let item = imageFileList.value[fileListLen];
imageFileList.value.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result as string,
});
fileListLen++;
}
}
const imageDelete = (event:any) => {
if (event.index !== undefined && event.file !== undefined) {
const imageIndex = event.index;
const currentFileList = imageFileList.value;
currentFileList.splice(imageIndex, 1);
imageFileList.value = [...imageFileList.value];
}
}
const uploadFilePromise = (url: any) => {
return new Promise((resolve, reject) => {
let a = uploadImage({
filePath:url,
name: 'file'
}).then((res:any)=>{
setTimeout(() => {
resolve(res.data.url as string);
}, 1000);
})
});
}
// 保存
const handSave = () => {
const handSave = async() => {
const hasPermission = await checkBtnPermission(memberStore.btnPermission, 'erp_product_add')
if (!hasPermission) return
formRef.value.validate().then(() => {
if (loading.value) return
loading.value = true
if(imageFileList.value.length > 0){
const imgUrls=imageFileList.value.map((item:any)=>item.url)
formData.value.image=imgUrls.join(',')
}
addProduct(formData.value).then((res : any) => {
loading.value = false
if (res.code == 1) {

View File

@@ -0,0 +1,152 @@
<template>
<view class="min-h-[100vh]" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" height="auto" @up="getListFn"
:top="mescrollTop">
<view class="sidebar-margin body-bottom" v-if="productList.length">
<u-checkbox-group class="w-full" v-model="checkProductList" placement="column">
<view class="mb-[15rpx]" v-for="(item,index) in productList" :key="index">
<up-collapse class="bg-[#ffffff] rounded-10rpx">
<up-collapse-item>
<template #title>
<view class="flex" style="display: flex;align-items: center;">
<u-checkbox :name="item"></u-checkbox>
<view>{{item.product?.name}}</view>
</view>
</template>
<view class="body">
<view class="flex justify-start flex-col p-[20rpx]">
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
食材编号:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.product?.code}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
食材类型:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.product?.productType?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
食材规格:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.product?.spec}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
批次号:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.batch_number}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
库存数量:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.inventory}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
食材单位:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.product?.productUnit?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
供应商:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.supplier?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
创建时间:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.create_time}}</text>
</view>
</view>
</view>
</up-collapse-item>
</up-collapse>
</view>
</u-checkbox-group>
</view>
<mescroll-empty v-if="!productList.length && !loading &&!listLoading"></mescroll-empty>
</mescroll-body>
<loading-page :loading="loading"></loading-page>
<view class="sidebar-margin mt-[20rpx] body-bottom">
<u-button @click="onConfirm" type="primary" shape="circle" text="确认选择"></u-button>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue'
import { topTabar } from '@/utils/topTabbar';
import { t } from '@/locale';
import { redirect, pxToRpx } from '@/utils/common';
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { getProductList,getProductListByWarehouseNew} from '@/addon/erp/api/product';
import { onLoad, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
const { downCallback, mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
const checkProductList = ref<any[]>([]);
const queryType = ref<any>('all'); // 查询方式 all 获取全部食材, warehouse 根据仓库ID ,获取对应的食材
const warehouse_id = ref<any>(undefined); // 仓库Id
const supplier_id= ref<any>(undefined); // 供应商Id
// 页面加载
onLoad((option : any) => {
queryType.value = option.type ? option.type : '';
warehouse_id.value = option.warehouse_id ? option.warehouse_id : undefined
supplier_id.value = option.supplier_id ? option.supplier_id : undefined
})
const mescrollTop = "20rpx"
const productList = ref<Array<any>>([]),
loading = ref<boolean>(true),
listLoading = ref<boolean>(true),
mescrollRef = ref(null);
interface mescrollStructure {
num : number,
size : number,
endSuccess : Function,
[propName : string] : any
}
const getListFn = (mescroll : mescrollStructure) => {
listLoading.value = true;
let data : Object = {
page: mescroll.num,
limit: mescroll.size,
warehouse_id: warehouse_id.value,
supplier_id: supplier_id.value
};
let getDataApi =
queryType.value == "all" ? getProductList : getProductListByWarehouseNew;
getDataApi(data).then((res : any) => {
let newArr = res.data.data;
mescroll.endSuccess(newArr.length);
//设置列表数据
if (mescroll.num == 1) {
productList.value = []; //如果是第一页需手动制空列表
}
productList.value = productList.value.concat(newArr);
listLoading.value = false;
loading.value = false;
}).catch((err) => {
// 如果是4001没有绑定企业账号强制跳转绑定
if (err.code == 4001) {
redirect({ url: '/addon/erp/pages/member/bind' })
}
listLoading.value = false;
loading.value = false;
mescroll.endErr(); // 请求失败, 结束加载
})
}
// 确认选择
const onConfirm = () => {
uni.$emit('choose_product-out', checkProductList.value);
// 返回上一页
uni.navigateBack({
delta: 1
});
}
</script>
<style>
</style>

View File

@@ -1,53 +1,49 @@
<template>
<view class="bg-[var(--page-bg-color)] min-h-[100vh]" :style="themeColor()">
<view class="min-h-[100vh]" :style="themeColor()">
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" height="auto" @up="getListFn"
:top="mescrollTop">
<view class="sidebar-margin body-bottom" v-if="productList.length">
<u-checkbox-group class="w-full" v-model="checkProductList" placement="column">
<view class="mb-[15rpx]" v-for="(item,index) in productList" :key="index">
<view class="bg-[#ffffff] rounded-10rpx">
<view class="head border-0 border-b-1 border-solid border-[#ddd]">
<view class="flex justify-between p-[20rpx]">
<view class="u-body-item-title u-line-2">{{item.name}}</view>
</view>
</view>
<view class="body">
<view class="flex justify-start flex-col p-[20rpx]">
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('code') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.code}}</text>
<up-collapse class="bg-[#ffffff] rounded-10rpx">
<up-collapse-item>
<template #title>
<view class="flex" style="display: flex;align-items: center;">
<u-checkbox :name="item"></u-checkbox>
<view>{{item.name}}</view>
</view>
</template>
<view class="body">
<view class="flex justify-start flex-col p-[20rpx]">
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('code') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.code}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('productTypeId') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.productType?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('spec') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.spec}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('inventory') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.inventory}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('productUnitId') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.productUnit?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('createTime') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.create_time}}</text>
</view>
</view>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('productTypeId') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.productType?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('spec') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.spec}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('inventory') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.inventory}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('productUnitId') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.productUnit?.name}}</text>
</view>
<view class="flex justify-start mb-[18rpx] text-[12px] text-[#6a6a6a]">
{{ t('createTime') }}:<text
class="ml-[20rpx] text-[var(--primary-color)]">{{item.create_time}}</text>
</view>
</view>
</view>
<view class="foot border-0 border-t-1 border-solid border-[#ddd]">
<view class="flex justify-start p-[20rpx]">
<u-checkbox :name="item" :label="t('choose')"></u-checkbox>
</view>
</view>
</view>
</up-collapse-item>
</up-collapse>
</view>
</u-checkbox-group>
</view>
@@ -70,14 +66,14 @@
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
import { getProductList, getProductListByWarehouse } from '@/addon/erp/api/product';
import { getProductList, getProductListByWarehouse,getProductListByWarehouseNew} from '@/addon/erp/api/product';
import { onLoad, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
const { downCallback, mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
const checkProductList = ref<any[]>([]);
const queryType = ref<any>('all'); // 查询方式 all 获取全部产品 warehouse 根据仓库ID ,获取对应的产品
const queryType = ref<any>('all'); // 查询方式 all 获取全部食材 warehouse 根据仓库ID ,获取对应的食材
const warehouse_id = ref<any>(undefined); // 仓库Id
// 页面加载
onLoad((option : any) => {
@@ -108,7 +104,7 @@
warehouse_id: warehouse_id.value
};
let getDataApi =
queryType.value == "all" ? getProductList : getProductListByWarehouse;
queryType.value == "all" ? getProductList :queryType.value == "new" ?getProductListByWarehouseNew: getProductListByWarehouse;
getDataApi(data).then((res : any) => {
let newArr = res.data.data;

View File

@@ -11,7 +11,7 @@
</view>
</u-form-item>
<u-form-item :label="t('name')" prop="name" borderBottom required>
<u-input v-model="formData.name" :placeholder="t('namePlaceholder')" border="none"></u-input>
<u-input v-model="formData.name" :placeholder="t('namePlaceholder')" ></u-input>
</u-form-item>
</view>
</u-form>
@@ -35,6 +35,10 @@
import { onLoad } from '@dcloudio/uni-app';
import { getProductTypeSelect, getProductTypeInfo, addProductType, editProductType } from '@/addon/erp/api/product';
import { redirect } from '@/utils/common';
import { checkBtnPermission } from '@/utils/auth';
import useMemberStore from '@/stores/member'
const memberStore = useMemberStore()
const formRef: any = ref(null)
const loading = ref(false)
@@ -102,7 +106,9 @@
}
// 保存
const handSave = () => {
const handSave = async() => {
const hasPermission = await checkBtnPermission(memberStore.btnPermission, 'erp_product_type_add')
if (!hasPermission) return
formRef.value.validate().then(() => {
if (loading.value) return
loading.value = true

View File

@@ -4,7 +4,7 @@
labelWidth="160rpx">
<view class="sidebar-margin card-template mt-[var(--top-m)] py-[20rpx]">
<u-form-item :label="t('name')" prop="name" borderBottom required>
<u-input v-model="formData.name" :placeholder="t('namePlaceholder')" border="none"></u-input>
<u-input v-model="formData.name" :placeholder="t('namePlaceholder')" ></u-input>
</u-form-item>
</view>
</u-form>
@@ -28,6 +28,10 @@
import { onLoad } from '@dcloudio/uni-app';
import { getProductUnitInfo, addProductUnit, editProductUnit } from '@/addon/erp/api/product';
import { redirect } from '@/utils/common';
import { checkBtnPermission } from '@/utils/auth';
import useMemberStore from '@/stores/member'
const memberStore = useMemberStore()
const formRef: any = ref(null)
const loading = ref(false)
@@ -66,7 +70,9 @@
}
// 保存
const handSave = () => {
const handSave = async() => {
const hasPermission = await checkBtnPermission(memberStore.btnPermission, 'erp_product_unit_add')
if (!hasPermission) return
formRef.value.validate().then(() => {
if (loading.value) return
loading.value = true