同步代码

This commit is contained in:
GaoHao
2025-02-07 14:49:20 +08:00
commit 0740c3f349
1141 changed files with 167372 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
<template>
<view class="mask u-fixed position-all u-flex u-col-bottom" v-if="show" @tap="close">
<view class="bg-fff w-full" @tap.stop="nullFunction">
<view class="u-p-30">
<view class="font-bold u-text-center u-font-32">选择团购券分类</view>
<view class="u-m-t-32 u-flex">
<view class="u-flex-1 u-p-r-16">
<view class="u-m-b-12">分类名称</view>
<uni-easyinput v-model="goods.query.name" placeholder="请输入团购券分类名称" />
</view>
<!-- <view class="u-flex-1 u-p-l-16">
<view class="u-m-b-12">商品分类</view>
<uni-data-picker :clear-icon="false" :map="{text:'name',value:'id'}" placeholder="请选择分类"
popup-title="请选择分类" :localdata="category" v-model="goods.query.categoryId">
</uni-data-picker>
</view> -->
</view>
<view class="u-m-t-32 u-flex u-row-right">
<view class="u-flex-1 u-p-r-16">
<my-button type="cancel" plain @tap="resetQuery">重置</my-button>
</view>
<view class="u-flex-1 u-p-l-16">
<my-button @tap="getGoods">查询</my-button>
</view>
</view>
</view>
<scroll-view :scroll-x="false" scroll-y="true" :style="computedStyle()">
<view class="u-p-l-30 u-p-r-30">
<view class="u-flex u-row-between no-wrap">
<view>
<my-radio @change="radioAllChange" v-model="goods.allChecked" shape="square" :size="20"></my-radio>
</view>
<view>名称</view>
<view>状态</view>
</view>
<view class="u-m-t-12 u-flex u-row-between" v-for="(item,index) in goods.list" :key="index">
<my-radio @change="radioChange" v-model="item.checked" shape="square" :size="20"></my-radio>
<view>
{{item.name}}
</view>
<view>
<my-switch v-model="item.status" disabled></my-switch>
<!-- {{item.status}} -->
</view>
</view>
</view>
</scroll-view>
<view class="u-p-30">
<my-pagination :totalElements="goods.totalElements" :size="goods.query.size" @change="pageChange"></my-pagination>
<view class="u-m-t-20 u-flex">
<view class="u-flex-1 u-p-r-16">
<my-button type="cancel" plain @tap="close">取消</my-button>
</view>
<view class="u-flex-1 u-p-l-16">
<my-button @tap="confrim">确定</my-button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import myButton from '@/components/my-components/my-button';
import myRadio from '@/components/my-components/my-radio';
import mySwitch from '@/components/my-components/my-switch';
import myPagination from '@/components/my-components/my-pagination'
import $coupon from '@/http/yskApi/couponCategory.js';
$coupon.get()
import {
reactive,
onMounted,
ref,
watch
} from 'vue';
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
height: {
type: [Number, String],
default: '40vh'
}
})
function nullFunction() {
}
const show = ref(props.modelValue)
function open(arr) {
show.value = true
if(arr){
for(let i in goods.list){
console.log(arr.includes(goods.list[i].id));
goods.list[i].checked=arr.includes(goods.list[i].id)
}
}
}
function close() {
show.value = false
}
function resetQuery() {
Object.assign(goods.query, $quey)
}
function computedStyle() {
return `height:${typeof props.height==='string'?props.height:props.height+'rpx'};`
}
const emits = defineEmits(['update:modelValue','confirm'])
const $quey = {
name: '',
page: 0,
size: 10,
}
const query = reactive({
...$quey
})
const goods=reactive({
list:[],
allChecked:false,
totalElements:0,
query:{
...$quey
}
})
function getGoods() {
$coupon.get(goods.query).then(res=>{
goods.list=res.content.map(v=>{
return {...v,checked:false}
})
goods.allChecked=false
goods.totalElements=res.totalElements
})
}
getGoods()
function pageChange(page){
goods.query.page=page-1
getGoods()
}
function radioChange(newval){
goods.allChecked=goods.list.filter(v=>v.checked).length!=0
}
function radioAllChange(newval){
goods.list.forEach(i=>{i.checked=newval})
}
function confrim(){
const arr= goods.list.filter(v=>v.checked)
console.log(arr);
emits('confirm',arr)
}
defineExpose({open,close})
</script>
<style lang="scss" scoped>
.mask {
background: rgba(51, 51, 51, 0.5);
z-index: 900;
}
.coverImg{
width: 60rpx;
height: 60rpx;
border-radius: 10rpx;
}
</style>

View File

@@ -0,0 +1,163 @@
<template>
<view class="u-relative choose-haocai">
<!-- <view class="input u-flex" @click="toggle" >
<up-input @blur="blur" @change="filterHaocaiList" border="none" v-model="text" placeholder="请选择"></up-input>
<up-icon :size="10" name="arrow-down-fill"></up-icon>
</view> -->
<view class="input u-flex" >
<view>{{text||''}}</view>
<!-- <up-input @blur="blur" disabled="true" @change="filterHaocaiList" border="none" v-model="text" placeholder="请选择"></up-input> -->
</view>
<view class="u-absolute" v-if="popShow">
<scroll-view scroll-y="true" class="scroll">
<view class="item" v-for="(item,index) in $haocaiList" :key="index" @click="haocaiClick(item,index)">
{{item.name}}
</view>
<view class="item no-wrap" @click="toggle" v-if="text&&!$haocaiList.length">没有该单位</view>
</scroll-view>
</view>
</view>
</template>
<script setup>
import {
reactive,
ref,
watch,
onMounted
} from 'vue';
const props = defineProps({
listMap: {
type: Object,
default: () => {}
},
list: {
type: Array,
default: () => []
},
modelValue: {
type: [String, Number],
default: ''
},
show: {
type: Boolean,
default: false
},
})
let text = ref('')
let popShow = ref(props.show)
const emits = defineEmits(['update:show', 'close', 'confirm', 'update:modelValue'])
function close() {
popShow.value = false
}
function confirm() {
popShow.value = false
}
watch(() => props.show, (newval) => {
popShow.value = newval
})
watch(() => popShow.value, (newval) => {
console.log(newval);
emits('update:show', newval)
})
let $haocaiList = ref(props.list)
watch(() => props.list, (newval) => {
$haocaiList.value = newval
setText()
})
watch(() => props.modelValue, (newval) => {
console.log(newval);
setText()
})
function setText() {
// const item = props.listMap[props.modelValue]
// text.value = item ? item.name : ''
text.value=props.modelValue
}
function toggle(e) {
popShow.value = !popShow.value
}
function filterHaocaiList(e) {
if (e === '') {
return $haocaiList.value = props.list
}
const arr = props.list.filter(v => v.name.match(e))
$haocaiList.value = arr
}
function haocaiClick(item, index) {
console.log(item);
// if (item.id != props.modelValue) {
// emits('update:modelValue', item.id)
// }
if(item.name!=props.modelValue){
emits('update:modelValue', item.name)
}
popShow.value = false
}
function focus(){
console.log('focus');
popShow.value = true
}
function blur() {
console.log('blur');
// setTimeout(()=>{
// popShow.value = false
// },100)
}
onMounted(() => {
setText()
})
</script>
<style lang="scss" scoped>
.choose-haocai {
.input {
width: 172rpx;
padding: 10rpx 16rpx;
height: 60rpx;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 8rpx 8rpx 8rpx 8rpx;
display: flex;
align-items: center;
justify-content: space-between;
border: 2rpx solid #E5E5E5;
overflow: hidden;
}
.u-absolute {
top: calc(100% + 10rpx);
border: 1px solid #E5E5E5;
left: 0;
background-color: #fff;
z-index: 10;
right: 0;
border-radius: 8rpx;
.scroll {
$line-h: 60rpx;
max-height: calc($line-h * 4);
.item {
line-height: $line-h;
padding: 0 20rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,268 @@
<template>
<view class="mask u-fixed position-all u-flex u-col-bottom u-font-28" v-if="show" @tap="close">
<view class="bg-fff w-full " @tap.stop="nullFunction">
<view class="u-p-30">
<view class="font-bold u-text-center">选择商品</view>
<view class="u-m-t-32 u-flex">
<view class=" ">
<uni-data-picker :clear-icon="false" :map="{text:'name',value:'id'}" placeholder="请选择分类"
popup-title="请选择分类" :localdata="category" v-model="goods.query.categoryId">
<view class="u-flex u-font-28" >
<text class=" u-line-1"
style="max-width: 100rpx;">{{goods.query.categoryId||'分类' }}</text>
<up-icon name="arrow-down" size="16"></up-icon>
</view>
</uni-data-picker>
</view>
<view class="u-flex-1 u-p-l-16">
<up-search @custom="getGoods" v-model="goods.query.name" placeholder="请输入商品名称" @search="getGoods" @clear="getGoods"></up-search>
</view>
</view>
</view>
<scroll-view :scroll-x="false" scroll-y="true" :style="computedStyle()">
<view class="u-p-l-30 u-p-r-30 table">
<view class="u-flex u-row-between no-wrap title">
<view>
<my-radio @change="radioAllChange" v-model="goods.allChecked" shape="square"
:size="20"></my-radio>
</view>
<view>商品信息</view>
<view>规格</view>
<!-- <view>是否售尽</view> -->
<!-- <view>是否分销</view> -->
<view>售价</view>
<view>销量/库存</view>
<view>分类名称</view>
</view>
<view @click="changeChecked(item)" class="u-m-t-12 u-flex u-p-24 u-row-between row" v-for="(item,index) in goods.list" :key="index">
<view class="">
<my-radio @change="radioChange($event,item)" v-model="item.checked" shape="square" :size="20"></my-radio>
</view>
<view class="u-text-left u-flex-1 u-p-l-20">
<!-- <view class="u-flex">
<image lazy-load class="coverImg" :src="item.coverImg" mode=""></image>
</view> -->
<view class="">{{item.name}}</view>
</view>
<view class="u-flex-1 u-p-l-4 u-p-r-4 box-size-border">
{{item.typeEnum}}
</view>
<view class="u-flex-1">
{{ item.lowPrice }}
</view>
<view class="u-flex-1">
<!-- {{ item.realSalesNumber }}/{{ item.stockNumber }} -->
{{ item.stockNumber }}
</view>
<view class="u-flex-1">
{{item.categoryName}}
</view>
</view>
</view>
</scroll-view>
<view class="u-p-30">
<my-pagination :totalElements="goods.totalElements" :size="goods.query.size"
@change="pageChange"></my-pagination>
<view class="u-m-t-20 u-flex">
<view class="u-flex-1 u-p-r-16">
<my-button type="cancel" plain @tap="close">取消</my-button>
</view>
<view class="u-flex-1 u-p-l-16">
<my-button @tap="confrim">确定</my-button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
$tbProductList
} from '@/http/yskApi/goods.js';
import {
reactive,
onMounted,
ref,
watch
} from 'vue';
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
height: {
type: [Number, String],
default: '50vh'
},
category: {
type: Array,
default: () => {
return []
}
}
})
function changeChecked(item){
item.checked=!item.checked
if(!item.checked&&$selGoodsMap[item.id]){
delete $selGoodsMap[item.id]
}else{
$selGoodsMap[item.id]=item
}
goods.allChecked = goods.list.filter(v => v.checked).length != 0
}
function nullFunction() {
}
const show = ref(props.modelValue)
let selArr=[]
let $selGoodsMap={}
async function open(arr) {
show.value = true
selArr=arr
console.log(arr);
for(let i in arr){
$selGoodsMap[arr[i].proId
]=arr[i]
}
getGoods()
}
function close() {
show.value = false
resetQuery()
$selGoodsMap={}
}
function resetQuery() {
Object.assign(goods.query, $quey)
}
function computedStyle() {
return `height:${typeof props.height==='string'?props.height:props.height+'rpx'};`
}
const emits = defineEmits(['update:modelValue', 'confirm'])
const $quey = {
categoryId: "",
createdAt: [],
id: "",
name: "",
sort: "createdAt,desc",
type: "",
page: 0,
size: 10,
}
const query = reactive({
...$quey
})
const goods = reactive({
list: [],
allChecked: false,
totalElements: 0,
query: {
...$quey
}
})
getGoods()
function getGoods() {
const arr=selArr
$tbProductList(goods.query).then(res => {
let selLen=0;
goods.list = res.content.map(v => {
const checked=$selGoodsMap[v.id]?true:false
selLen+=(checked?1:0)
return {
...v,
checked
}
})
goods.allChecked = selLen==res.content.length?true:false
goods.totalElements = res.totalElements
})
}
function pageChange(page) {
goods.query.page = page - 1
getGoods()
}
function radioChange(newval,item) {
if(!newval&&$selGoodsMap[item.id]){
delete $selGoodsMap[item.id]
}else{
$selGoodsMap[item.id]=item
}
goods.allChecked = goods.list.filter(v => v.checked).length != 0
}
function radioAllChange(newval) {
goods.list.forEach(i => {
i.checked = newval
if($selGoodsMap[i.id]&&!newval){
delete $selGoodsMap[i.id]
}else{
$selGoodsMap[i.id]=i
}
})
}
function confrim() {
for(let i in goods.list){
const item=goods.list[i]
if($selGoodsMap[item.id]&&!item.checked){
delete $selGoodsMap[item.id]
}
}
console.log($selGoodsMap);
const arr = Object.values($selGoodsMap)
emits('confirm', arr)
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.bg-fff{
border-radius: 24rpx 24rpx 0 0 ;
}
.mask {
background: rgba(51, 51, 51, 0.5);
z-index: 900;
}
.box-size-border{
box-sizing: border-box;
}
.coverImg {
width: 60rpx;
height: 60rpx;
border-radius: 10rpx;
}
.table {
background: #F9F9F9;
border-radius: 8rpx;
overflow: hidden;
.title {
padding: 12rpx 24rpx 12rpx 24rpx;
background: #AEBAD2;
border-radius: 8rpx 8rpx 0rpx 0rpx;
color: #fff;
}
.row:nth-of-type(2n+1) {
background: #F0F0F0;
}
}
</style>

View File

@@ -0,0 +1,164 @@
<template>
<view class="mask u-fixed position-all u-flex u-col-bottom u-font-28" v-if="show" @tap="close">
<view class="bg-fff w-full " @tap.stop="nullFunction">
<view class="u-p-30">
<view class="font-bold u-text-center">选择规格</view>
</view>
<scroll-view :scroll-x="false" scroll-y="true" :style="computedStyle()">
<view class="u-p-l-30 u-p-r-30 ">
<view class="u-flex u-flex-wrap w-full gap-10 u-col-top">
<view class="skd" v-for="(item,index) in skuList" :key="index"
:class="{active:sel.id==item.id}"
@click="guigeClick(item,index)">
<text>{{item.specSnap||item.name}}</text>
<view class="tag-primary tag" v-if="item.isGrounding">上架中</view>
<view class="tag-gray tag" v-if="item.isPauseSale">已售罄</view>
<view class="tag-gray tag" v-if="!item.isGrounding">已下架</view>
</view>
</view>
</view>
</scroll-view>
<view class="u-p-30">
<view class="u-m-t-20 u-flex">
<view class="u-flex-1 u-p-r-16">
<my-button type="cancel" plain @tap="close">取消</my-button>
</view>
<view class="u-flex-1 u-p-l-16">
<my-button @tap="confrim">确定</my-button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
$tbProduct
} from '@/http/yskApi/goods.js';
import {
reactive,
onMounted,
ref,
watch
} from 'vue';
import infoBox from '@/commons/utils/infoBox.js'
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
})
let skuList=ref([])
function nullFunction() {
}
const show = ref(props.modelValue)
async function open(arr,sel) {
show.value = true
skuList.value=arr
}
function close() {
show.value = false
sel.value={}
}
let sel=ref({
})
function guigeClick(item,index){
if(sel.value.id==item.id){
return sel.value={}
}
sel.value=item
}
function computedStyle() {
return `height:${typeof props.height==='string'?props.height:props.height+'rpx'};`
}
const emits = defineEmits(['update:modelValue', 'confirm'])
function confrim() {
if(!sel.value.id){
return infoBox.showToast('请选择选择一个规格')
}
emits('confirm', sel.value)
close()
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.bg-fff{
border-radius: 24rpx 24rpx 0 0 ;
}
.mask {
background: rgba(51, 51, 51, 0.5);
z-index: 900;
}
.skd {
padding: 10rpx 38rpx 8rpx 40rpx;
background: #F0F2F5;
border-radius: 4rpx;
position: relative;
color: #666;
overflow: hidden;
margin-bottom: 10rpx;
font-size: 24rpx;
border: 1px solid transparent;
&.active{
border-color: $my-main-color;
}
.tag {
position: absolute;
right: 0;
top: 0;
font-size: 12rpx;
height: 18rpx;
line-height: 18rpx;
right: 0;
border-radius: 0rpx 2rpx 2rpx 8rpx;
}
.tag-primary {
background-color: $my-main-color;
color: #fff;
}
.tag-gray {
background-color: rgb(144, 147, 153);
color: #fff;
}
}
.coverImg {
width: 60rpx;
height: 60rpx;
border-radius: 10rpx;
}
.table {
background: #F9F9F9;
border-radius: 8rpx;
overflow: hidden;
.title {
padding: 12rpx 24rpx 12rpx 24rpx;
background: #AEBAD2;
border-radius: 8rpx 8rpx 0rpx 0rpx;
color: #fff;
}
.row:nth-of-type(2n+1) {
background: #F0F0F0;
}
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<up-popup :round="10" :show="popShow" :closeable="true" @close="close">
<view class="u-text-center font-bold u-font-32 u-p-t-30">选择状态</view>
<view style="height: 20rpx;"></view>
<view class="u-p-30 all-list u-flex u-flex-wrap gap-20">
<view class="all-list-item" :class="{active:statusItemIndex==statusData.allListSel}" @click="changeAllListSel(statusItemIndex)" v-for="(statusItem,statusItemIndex) in statusData.allList" :key="statusItemIndex">
{{statusItem.label}}
</view>
</view>
<view class="u-flex u-p-t-30 u-p-b-30 u-p-l-20 u-p-r-20 gap-20">
<up-button @click="close">取消</up-button>
<up-button type="primary" @click="confirm">确定</up-button>
</view>
</up-popup>
</template>
<script setup>
import { ref, watch } from 'vue';
const props=defineProps({
show:{
type:Boolean,
default:false
}
})
let popShow=ref(props.show)
const emits=defineEmits(['update:show','close','confirm'])
function close(){
popShow.value=false
}
function confirm(){
popShow.value=false
}
watch(()=>props.show,(newval)=>{
popShow.value=newval
})
watch(()=>popShow.value,(newval)=>{
emits('update:show',newval)
})
</script>
<style lang="scss" scoped>
.all-list-item{
text-align: center;
width: 156rpx;
white-space: nowrap;
color: #666;
padding: 10rpx 20rpx;
border-radius: 8rpx;
transition: all .2s ease-in-out;
border: 1px solid #eee;
&.active {
color: $my-main-color;
border-color: $my-main-color;
}
}
</style>

View File

@@ -0,0 +1,149 @@
<template>
<view class="u-relative choose-haocai">
<view class="input u-flex" @click="toggle">
<!-- <view>
<text v-if="modelValue">{{modelValue}}</text>
<text v-else class="color-666">请选择</text>
</view> -->
<up-input @blur="blur" @change="filterHaocaiList" border="none" v-model="text" placeholder="请选择"></up-input>
<up-icon :size="10" name="arrow-down-fill"></up-icon>
</view>
<view class="u-absolute" v-if="popShow">
<scroll-view scroll-y="true" class="scroll">
<view class="item" v-for="(item,index) in $haocaiList" :key="index" @click="haocaiClick(item,index)">
{{item.conName}}
</view>
<view class="item no-wrap" @click="toggle" v-if="text&&!$haocaiList.length">没有该耗材</view>
</scroll-view>
</view>
</view>
</template>
<script setup>
import {
reactive,
ref,
watch,
onMounted
} from 'vue';
const props = defineProps({
listMap: {
type: Object,
default: () => {}
},
list: {
type: Array,
default: () => []
},
modelValue: {
type: [String, Number],
default: ''
},
show: {
type: Boolean,
default: false
},
})
let text = ref('')
let popShow = ref(props.show)
const emits = defineEmits(['update:show', 'close', 'confirm', 'update:modelValue','change'])
function close() {
popShow.value = false
}
function confirm() {
popShow.value = false
}
watch(() => props.show, (newval) => {
popShow.value = newval
})
watch(() => popShow.value, (newval) => {
emits('update:show', newval)
})
let $haocaiList = ref(props.list)
watch(() => props.list, (newval) => {
$haocaiList.value = newval
setText()
})
watch(() => props.modelValue, (newval) => {
setText()
})
function setText() {
const item = props.listMap[props.modelValue]
text.value = item ? item.conName : ''
}
function toggle(e) {
popShow.value = !popShow.value
}
function filterHaocaiList(e) {
if (e === '') {
return $haocaiList.value = props.list
}
const arr = props.list.filter(v => v.conName.match(e))
$haocaiList.value = arr
}
function haocaiClick(item, index) {
console.log(item);
if (item.id != props.modelValue) {
emits('update:modelValue', item.id)
emits('change', item)
}
popShow.value = false
}
function blur() {
// setTimeout(()=>{
// popShow.value = false
// },100)
}
onMounted(() => {
setText()
})
</script>
<style lang="scss" scoped>
.choose-haocai {
.input {
width: 172rpx;
padding: 10rpx 16rpx;
height: 60rpx;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 8rpx 8rpx 8rpx 8rpx;
display: flex;
align-items: center;
justify-content: space-between;
border: 2rpx solid #E5E5E5;
overflow: hidden;
}
.u-absolute {
top: calc(100% + 10rpx);
border: 1px solid #E5E5E5;
left: 0;
background-color: #fff;
z-index: 10;
right: 0;
border-radius: 8rpx;
.scroll {
$line-h: 60rpx;
max-height: calc($line-h * 4);
.item {
line-height: $line-h;
padding: 0 20rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,440 @@
<template>
<view>
<view class="default-box-padding bg-fff border-r-18">
<view class="u-flex u-row-between">
<view>商品名称</view>
<!-- <template v-if="isSku"> -->
<view class="u-flex u-font-24 color-666">
<view class="u-m-r-20">绑定至规格</view>
<view class="u-flex u-relative">
<up-switch :size="18" v-model="isBindGuige" :disabled="!isSku">绑定至规格</up-switch>
<view class="u-absolute position-all" style="z-index: 1;" v-if="!isSku"
@click="infoBox.showToast('该商品是单规格商品,只有多规格商品可绑定至规格',3)"></view>
</view>
</view>
<!-- </template> -->
</view>
<view class="border-bottom u-m-t-16 u-p-b-32">{{goods.name}}</view>
<view class="">
<template v-if="isBindGuige&&isSku">
<view class="list">
<view class="u-p-b-32 u-p-t-32 border-bottom" v-for="(sku,index) in skuList" :key="index">
<view>规格名称</view>
<view class="u-m-t-16">{{sku.specSnap}}</view>
<view class="color-666 u-m-t-24 u-flex">
<view class="xuhao">序号</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">
<view class="u-flex-1">耗材名称</view>
<view class="u-flex-1">单位</view>
<view class="u-flex-1">用量</view>
</view>
</view>
<view class="u-m-t-32 color-666">
<view class="u-m-t-24" v-for="(item,haocaiIndex) in sku.haoCaiList" :key="haocaiIndex">
<view class=" u-flex">
<view class="xuhao">{{haocaiIndex+1}}</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">
<view class="u-flex-1 ">
<choose-haocai @change="conInfosChange($event,item)"
:listMap="$haocaiMap" :list="haoCaiList"
v-model="item.conInfoId"></choose-haocai>
</view>
<view class="u-flex-1 ">
<choose-danwei :listMap="$danweiMap" :list="danweiList"
v-model="item.conUnit"></choose-danwei>
</view>
<view class="u-flex input">
<up-input border="none" v-model="item.surplusStock"></up-input>
<up-icon @click="delGuigeHaocao(index,haocaiIndex)" color="#EA4025"
:size="16" name="minus-circle-fill"></up-icon>
</view>
</view>
</view>
<view class="u-flex u-m-t-16 color-666 u-font-24">
<view class="xuhao">
</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">库存{{item.stockNumber}}
</view>
</view>
</view>
</view>
<view class="u-flex">
<view class=" u-p-t-32 u-flex" @click="addGuigeHaocai(index)">
<up-icon :size="18" color="#318AFE" name="plus-circle-fill"></up-icon>
<view class="u-m-l-16">添加耗材</view>
</view>
</view>
</view>
</view>
</template>
<template v-else>
<view class="list">
<view class="u-p-b-32 u-p-t-32 border-bottom" v-for="(item,index) in conInfos" :key="index">
<view class="color-666 u-flex">
<view class="xuhao">序号</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">
<view class="u-flex-1">耗材名称</view>
<view class="u-flex-1">单位</view>
<view class="u-flex-1">用量</view>
</view>
</view>
<view class="u-m-t-32 color-666">
<view class=" u-m-t-24 u-flex">
<view class="xuhao">{{index+1}}</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">
<view class="u-flex-1 ">
<choose-haocai @change="conInfosChange($event,item)" :listMap="$haocaiMap"
:list="haoCaiList" v-model="item.conInfoId"></choose-haocai>
<!-- <view class="u-flex input">
<view>{{item.conName}}</view>
<up-icon :size="10" name="arrow-down-fill"></up-icon>
</view> -->
</view>
<view class="u-flex-1 ">
<choose-danwei :listMap="$danweiMap" :list="danweiList"
v-model="item.conUnit"></choose-danwei>
<!-- <view class="u-flex input">
<view>{{item.conUnit}}</view>
<up-icon :size="10" name="arrow-down-fill"></up-icon>
</view> -->
</view>
<view class="u-flex-1 ">
<view class="u-flex input">
<up-input border="none" v-model="item.surplusStock"></up-input>
<up-icon @click="delHaocai(index)" color="#EA4025" :size="16"
name="minus-circle-fill"></up-icon>
</view>
</view>
</view>
</view>
<view class="u-flex u-m-t-16 u-font-24" v-if="item.stockNumber">
<view class="xuhao">
</view>
<view class="u-flex u-flex-1 u-p-l-32 gap-20">库存{{item.stockNumber}}
{{item.conUnit}}
</view>
</view>
</view>
</view>
</view>
</template>
<template v-if="!isBindGuige">
<view class="u-flex">
<view class=" u-p-t-32 u-flex" @click="addHaocai">
<up-icon :size="18" color="#318AFE" name="plus-circle-fill"></up-icon>
<view class="u-m-l-16">添加耗材</view>
</view>
</view>
</template>
</view>
</view>
<view class="default-box-padding bg-fff border-r-18 u-flex u-row-between u-m-t-32">
<view>当某个耗材的使用库存不足时商品自动
售罄</view>
<!-- <view class="u-flex u-p-l-32">
<up-switch :size="20"></up-switch>
</view> -->
</view>
<view class="bottom">
<my-button type="primary" shape="circle" font-weight="700" @click="save">保存</my-button>
<my-button bgColor="#F9F9F9" shape="circle" color="#999" @click="cancel">取消</my-button>
</view>
</view>
</template>
<script setup>
import {
ref,
reactive,
toRefs,
watch,
computed,
onMounted
}
from 'vue';
import {
getviewConSku,
gettbProductSpec,
gettbConsInfo,
posttbProskuCons,
puttbProskuCon,
deletetbProskuCon,
} from "@/http/yskApi/consumable.js";
import {
tbShopCurrencyGet,
$hasPermission
} from '@/http/yskApi/shop.js'
import infoBox from '@/commons/utils/infoBox.js'
import chooseHaocai from './choose-haocai.vue';
import chooseDanwei from './choose-danwei.vue';
import {
$tbProskuConV2
} from '@/http/yskApi/goods.js'
import {
cloneWith
} from 'lodash';
import {
hasPermission
} from '@/commons/utils/hasPermission.js';
const emits = defineEmits(['cancel', 'updateGoods'])
function cancel() {
emits('cancel')
}
const props = defineProps({
goods: {
type: Object,
default: () => {
return {
conInfos: [],
skuList: [],
typeEnum: ''
}
}
}
})
const conInfos = ref(props.goods.conInfos)
watch(() => props.goods.conInfos, (newval) => {
console.log(newval);
conInfos.value = newval
})
function conInfosChange(newval, item) {
console.log(newval);
item.stockNumber = newval.balance
item.conUnit = newval.conUnit
}
const skuList = ref(props.goods.skuList)
watch(() => props.goods.skuList, (newval) => {
console.log(newval);
skuList.value = newval
})
const $baseicHaocaiData = {
conInfoId: '',
conUnit: '',
surplusStock: ''
}
function addHaocai() {
conInfos.value.push({
...$baseicHaocaiData
})
}
const popup = reactive({
haocai: {
show: true
}
})
function addGuigeHaocai(index) {
if (skuList.value[index].haoCaiList) {
skuList.value[index].haoCaiList.push({
...$baseicHaocaiData
})
} else {
skuList.value[index].haoCaiList = [{
...$baseicHaocaiData
}]
}
console.log(skuList.value[index]);
}
function delHaocai(index) {
const item = conInfos.value[index]
console.log(item);
uni.showModal({
title: '提示',
content: '是否删除该耗材',
success(res) {
if (res.confirm) {
if (item.id) {
deletetbProskuCon([item.id]).then(res1 => {
conInfos.value.splice(index, 1)
})
} else {
conInfos.value.splice(index, 1)
}
}
}
})
}
function delGuigeHaocao(guigeIndex, haocaiIndex) {
const item = skuList.value[guigeIndex].haoCaiList[haocaiIndex]
console.log(item);
uni.showModal({
title: '提示',
content: '是否删除该耗材',
success(res) {
if (res.confirm) {
if (item && item.id) {
deletetbProskuCon([item.id]).then(res1 => {
skuList.value[guigeIndex].haoCaiList.splice(haocaiIndex, 1)
})
} else {
skuList.value[guigeIndex].haoCaiList.splice(haocaiIndex, 1)
}
}
}
})
}
// 是否是多规格商品
const isSku = computed(() => {
return props.goods.typeEnum == 'sku'
})
let isBindGuige = ref(false)
watch(() => props.goods.typeEnum, (newval) => {
if(!newval){
isBindGuige.value = false
}
})
async function save() {
const bol = await hasPermission('允许修改商品')
if (!bol) {
return
}
console.log('save');
let isPas = false
if (!isBindGuige.value) {
//绑定至商品
isPas = conInfos.value.every(v => {
return v.conInfoId && v.conUnit && v.surplusStock > 0
})
} else {
//绑定至规格
isPas = skuList.value.filter(v => v.haoCaiList && v.haoCaiList.length).every(sku => {
console.log(sku.haoCaiList);
return sku.haoCaiList.every(v => {
return v.conInfoId && v.conUnit && v.surplusStock > 0
})
})
}
if (!isPas) {
return infoBox.showToast('请填写全部耗材选项值')
}
let ajaxData = {
productId: props.goods.id,
cons: []
}
if (!isBindGuige.value) {
//绑定至商品
ajaxData.cons = conInfos.value.map(v => {
return {
id: v.id || '',
conInfoId: v.conInfoId,
productId: props.goods.id,
shopId: uni.getStorageSync('shopId'),
productSkuId: 0,
surplusStock: v.surplusStock * 1,
status: 1
}
})
} else {
for (let i in skuList.value) {
const haocaiList = skuList.value[i].haoCaiList || []
for (let k in haocaiList) {
const v = haocaiList[k]
ajaxData.cons.push({
id: v.id || '',
conInfoId: v.conInfoId,
productId: props.goods.id,
shopId: uni.getStorageSync('shopId'),
productSkuId: skuList.value[i].id,
surplusStock: v.surplusStock * 1,
status: 1
})
}
}
}
console.log(ajaxData);
await $tbProskuConV2(ajaxData)
emits('updateGoods')
infoBox.showToast('修改成功')
}
let haoCaiList = ref([])
let $haocaiMap = reactive({})
let danweiList = ref([])
let $danweiMap = reactive({})
function init() {
gettbConsInfo({
"status": 1,
}).then(res => {
for (let i in res.content) {
const item = res.content[i]
$haocaiMap[item.id] = item
}
haoCaiList.value = res.content
})
tbShopCurrencyGet({
page: 0,
size: 200
}).then(res => {
for (let i in res.content) {
const item = res.content[i]
$danweiMap[item.id] = item
}
danweiList.value = res.content
})
}
onMounted(() => {
init()
const firstItem= props.goods.conInfos[0]
isBindGuige.value=firstItem?(firstItem.productSkuId==0?false:true):false
})
</script>
<style lang="scss" scoped>
.bottom {
padding: 84rpx 82rpx;
}
.xuhao {
width: 52rpx;
white-space: nowrap;
}
.input {
width: 172rpx;
padding: 10rpx 16rpx;
height: 60rpx;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 8rpx 8rpx 8rpx 8rpx;
display: flex;
align-items: center;
justify-content: space-between;
border: 2rpx solid #E5E5E5;
overflow: hidden;
}
.list .border-bottom:last-child {
border: none;
}
</style>

View File

@@ -0,0 +1,109 @@
<template>
<view class="u-flex number-box">
<view class="u-flex u-flex-1">
<up-input @blur="priceFormat" border="none" v-model="number" :type="inputType" :placeholder="placeholder"></up-input>
</view>
<view class="u-flex u-flex-col right">
<view class="u-flex-1 u-p-l-8 u-p-r-8" @click="changeNumber('add')">
<up-icon name="arrow-up" color="#E5E5E5"></up-icon>
</view>
<view class="line"></view>
<view class="u-flex-1 u-p-l-8 u-p-r-8" @click="changeNumber('reduce')">
<up-icon name="arrow-down" color="#E5E5E5"></up-icon>
</view>
</view>
</view>
</template>
<script setup>
import {
formatPrice
} from "@/commons/utils/format.js";
import {
ref,
watch,nextTick
} from 'vue';
const props = defineProps({
inputType:{
type:String,
default:'digit'
},
modelValue: {
type: [String, Number]
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 999999999
},
step: {
type: Number,
default: 1
},
placeholder: {
type: String,
default: '请输入'
}
})
let number = ref(props.modelValue)
function changeNumber(type) {
const newval = number.value + props.step * (type == 'add' ? 1 : -1)
if (newval < props.min) {
number.value = props.min
}
if (newval > props.max) {
number.value = props.max
}
priceFormat(newval)
}
function priceFormat(e) {
nextTick(() => {
const min = props
.min;
const max = props.max;
if (e === '') {
return
}
const newval = formatPrice(e, min, max, true)
if (typeof newval !== 'number') {
number.value = newval.value
uni.showToast({
title: `请输入${min}${max}范围内的数字`,
icon: 'none'
})
} else {
number.value = newval
}
})
}
watch(() => props.modelValue, (newval) => {
number.value = newval
})
const emits = defineEmits(['update:modelValue'])
watch(() => number.value, (newval) => {
emits('update:modelValue', newval)
})
</script>
<style lang="scss" scoped>
.line {
width: 100%;
height: 1px;
background-color: #E5E5E5;
}
.number-box {
border: 1px solid #E5E5E5;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding-left: 24rpx;
.right {
border-left: 1px solid #E5E5E5;
}
}
</style>

View File

@@ -0,0 +1,224 @@
<template>
<view class="u-p-30 min-page u-font-28">
<!-- <view class="u-flex">
<view style="width: 210rpx;">
<my-button shape="circle" @click="addTimer">添加定时器</my-button>
</view>
</view> -->
<view class="list u-m-t-20" v-if="list.length">
<view class="block" v-for="(item,index) in list" :key="index">
<!-- <view class="u-flex u-row-between">
<view>定时器{{index+1}}</view>
<uni-icons @click="delTimer(index)" type="trash"></uni-icons>
</view> -->
<view class="u-flex u-row-between">
<view>周期</view>
<view class="color-main" @click="selectAllClick(index)">
{{isAllChecked?'取消全选':'全选'}}
</view>
</view>
<view class="u-m-t-24">
<uni-data-checkbox :selectedColor="color.ColorMain" multiple v-model="item.cycleChecked" :localdata="cycle"></uni-data-checkbox>
</view>
<view class="u-m-t-24">
<view class="u-flex">
<view>上架时间:</view>
<view class="u-flex-1 u-m-l-10">
<picker mode="multiSelector" @change="listingTimeChange($event,index)"
:value="item.listingTime.index" :range="times">
<view class="bg-gray u-p-l-20 u-p-t-6 u-p-b-6 u-p-r-20 ">
{{item.listingTime.value}}
</view>
</picker>
</view>
</view>
<view class="u-flex u-m-t-16">
<view>下架时间:</view>
<view class="u-flex-1 u-m-l-10">
<picker mode="multiSelector" @change="offShelfChange($event,index)"
:value="item.offShelf.index" :range="times">
<view class="bg-gray u-p-l-20 u-p-t-6 u-p-b-6 u-p-r-20 ">
{{item.offShelf.value}}
</view>
</picker>
</view>
</view>
</view>
</view>
</view>
<view class="u-flex u-row-center u-m-t-60">
<my-button width="580" shape="circle" @click="save">保存</my-button>
</view>
</view>
</template>
<script setup>
import {
onLoad,
onReady
} from '@dcloudio/uni-app';
import {
computed,
ref
} from 'vue';
import go from '@/commons/utils/go.js';
import color from '@/commons/color.js'
import {
$getProductDetail,
} from '@/http/yskApi/goods.js'
//返回一天的时间 时分格式
function returnDayTime() {
return new Array(2).fill(1).map((v, index) => {
if (index === 0) {
return new Array(24).fill(1).map((hour, index) => {
return `0${index}`.slice(-2)
})
}
if (index === 1) {
return new Array(60).fill(1).map((hour, index) => {
return `0${index}`.slice(-2)
})
}
})
}
const times = ref(returnDayTime())
let defaultTimeIndex = ref(0)
function getTime(indexArr) {
const hour = times.value[0][indexArr[0]]
const month = times.value[1][indexArr[1]]
return `${hour}:${month}`
}
//获取$event.detail.value
function getEnentDetailValue(e) {
return e.detail.value
}
function setListTimeValue(index, key, time) {
list.value[index][key].value = time
}
function listingTimeChange(e, index) {
const indexArr = getEnentDetailValue(e)
const time = getTime(indexArr)
setListTimeValue(index, 'listingTime', time)
}
function offShelfChange(e, index) {
const indexArr = getEnentDetailValue(e)
const time = getTime(indexArr)
setListTimeValue(index, 'offShelf', time)
}
const cycle = [{
value: 0,
text: '星期一'
},
{
value: 1,
text: '星期二'
},
{
value: 2,
text: '星期三'
},
{
value: 3,
text: '星期四'
},
{
value: 4,
text: '星期五'
},
{
value: 5,
text: '星期六'
},
{
value: 6,
text: '星期日'
}
]
const ListDataconstructor = {
cycleChecked: [0, 1, 2, 3, 4, 5, 6],
}
function returnBasicTimeConstructor() {
return {
listingTime: {
value: '00:00',
index: [0, 0]
},
offShelf: {
value: '00:00',
index: [0, 0]
}
}
}
const list = ref([returnBasicDataConstructor()])
function returnBasicDataConstructor() {
return {
...ListDataconstructor,
...returnBasicTimeConstructor()
}
}
function addTimer() {
list.value.push(returnBasicDataConstructor())
}
function delTimer(index) {
list.value.splice(index,1)
}
const isAllChecked=computed(()=>{
return list.value[0].cycleChecked.length==cycle.length?true:false
})
function selectAllClick(index){
if(isAllChecked.value){
list.value[index].cycleChecked=[]
}else{
list.value[index].cycleChecked=ListDataconstructor.cycleChecked
}
}
// 触发定时器保存事件将数据给到添加商品页面
function emitTimerSave(){
uni.$emit('timerSave',list.value)
go.back()
}
function save(){
console.log(list.value);
emitTimerSave()
}
let goodsDetail=ref({})
function returnTimer(res){
return []
}
onLoad(async(opt)=>{
let res=null
if(opt.productId){
res=await $getProductDetail(opt.productId)
goodsDetail.value=res
}
const arr=res?returnTimer(res):[]
if(arr.length){
list.value=arr
}
})
</script>
<style lang="scss">
.min-page {
background-color: #F9F9F9;
}
.block {
background: #FFFFFF;
border-radius: 18rpx 18rpx 18rpx 18rpx;
padding: 32rpx 28rpx;
margin-bottom: 32rpx;
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<view class="u-p-30 min-page u-font-28">
<!-- <view class="u-flex">
<view style="width: 210rpx;">
<my-button shape="circle" @click="addTimer">添加定时器</my-button>
</view>
</view> -->
<view class="list u-m-t-20" v-if="list.length">
<view class="block" v-for="(item,index) in list" :key="index">
<!-- <view class="u-flex u-row-between">
<view>定时器{{index+1}}</view>
<uni-icons @click="delTimer(index)" type="trash"></uni-icons>
</view> -->
<view class="u-flex u-row-between">
<view>周期</view>
<view class="color-main" @click="selectAllClick(index)">
{{isAllChecked?'取消全选':'全选'}}
</view>
</view>
<view class="u-m-t-24">
<uni-data-checkbox :selectedColor="color.ColorMain" multiple v-model="item.cycleChecked"
:localdata="cycle"></uni-data-checkbox>
</view>
<view class="u-m-t-24">
<view class="u-flex">
<view>上架时间:</view>
<view class="u-flex-1 u-m-l-10">
<picker mode="multiSelector" @change="startTimeChange($event,index)"
:value="item.startTime.index" :range="times">
<view class="bg-gray u-p-l-20 u-p-t-6 u-p-b-6 u-p-r-20 ">
{{item.startTime.value}}
</view>
</picker>
</view>
</view>
<view class="u-flex u-m-t-16">
<view>下架时间:</view>
<view class="u-flex-1 u-m-l-10">
<picker mode="multiSelector" @change="endTimeChange($event,index)"
:value="item.endTime.index" :range="times">
<view class="bg-gray u-p-l-20 u-p-t-6 u-p-b-6 u-p-r-20 ">
{{item.endTime.value}}
</view>
</picker>
</view>
</view>
</view>
</view>
</view>
<view class="u-flex u-row-center u-m-t-60">
<my-button width="580" shape="circle" @click="save">保存</my-button>
</view>
</view>
</template>
<script setup>
import {
onLoad,
onReady
} from '@dcloudio/uni-app';
import {
computed,
ref
} from 'vue';
import go from '@/commons/utils/go.js';
import color from '@/commons/color.js'
import {
$getProductDetail,
} from '@/http/yskApi/goods.js'
//返回一天的时间 时分格式
function returnDayTime() {
return new Array(3).fill(1).map((v, index) => {
if (index === 0) {
return new Array(24).fill(1).map((hour, index) => {
return `0${index}`.slice(-2)
})
}
if (index === 1 || index === 2) {
return new Array(60).fill(1).map((hour, index) => {
return `0${index}`.slice(-2)
})
}
})
}
const times = ref(returnDayTime())
let defaultTimeIndex = ref(0)
function getTime(indexArr) {
const hour = times.value[0][indexArr[0]]
const month = times.value[1][indexArr[1]]
const s = times.value[2][indexArr[2]]
// return `${hour}:${month}:${s}`
return `${hour}:${month}`
}
//获取$event.detail.value
function getEnentDetailValue(e) {
return e.detail.value
}
function setListTimeValue(index, key, time) {
list.value[index][key].value = time
}
function startTimeChange(e, index) {
const indexArr = getEnentDetailValue(e)
const time = getTime(indexArr)
setListTimeValue(index, 'startTime', time)
}
function endTimeChange(e, index) {
const indexArr = getEnentDetailValue(e)
const time = getTime(indexArr)
setListTimeValue(index, 'endTime', time)
}
const cycle = [{
value: 'Monday',
text: '星期一'
},
{
value: 'Tuesday',
text: '星期二'
},
{
value: 'Wednesday',
text: '星期三'
},
{
value: 'Thursday',
text: '星期四'
},
{
value: 'Friday',
text: '星期五'
},
{
value: 'Saturday',
text: '星期六'
},
{
value: 'Sunday',
text: '星期日'
}
]
const ListDataconstructor = {
cycleChecked: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
}
function returnBasicTimeConstructor() {
return {
startTime: {
value: '00:00',
index: [0, 0, 0]
},
endTime: {
value: '23:59',
index: [0, 0, 0]
}
}
}
const list = ref([returnBasicDataConstructor()])
function returnBasicDataConstructor() {
return {
...ListDataconstructor,
...returnBasicTimeConstructor()
}
}
function addTimer() {
list.value.push(returnBasicDataConstructor())
}
function delTimer(index) {
list.value.splice(index, 1)
}
const isAllChecked = computed(() => {
return list.value[0].cycleChecked.length == cycle.length ? true : false
})
function selectAllClick(index) {
if (isAllChecked.value) {
list.value[index].cycleChecked = []
} else {
list.value[index].cycleChecked = ListDataconstructor.cycleChecked
}
}
// 触发定时器保存事件将数据给到添加商品页面
function emitTimerSave() {
const par = {
days: list.value[0].cycleChecked.join(','),
startTime: list.value[0].startTime.value,
endTime: list.value[0].endTime.value
}
console.log(par);
uni.$emit('timerSave', par)
go.back()
}
function save() {
emitTimerSave()
}
let goodsDetail = ref({})
function returnTimeIndex(time) {
console.log(time);
return time.split(':').map(v => {
return v * 1
})
}
function returnTimer(res) {
return [{
cycleChecked: res.days ? res.days.split(',').filter(v => v) : [],
startTime: res.startTime ? {
value: res.startTime,
index: returnTimeIndex(res.startTime)
} : returnBasicTimeConstructor.startTime,
endTime: res.endTime ? {
value: res.endTime,
index: returnTimeIndex(res.endTime)
} : returnBasicTimeConstructor.endTime
}]
}
onLoad(async (opt) => {
let res = null
if (opt.productId) {
res = await $getProductDetail(opt.productId)
goodsDetail.value = res
}
const arr = res ? returnTimer(res) : [];
console.log(arr);
if (arr.length) {
list.value = arr
}
})
</script>
<style lang="scss">
.min-page {
background-color: #F9F9F9;
}
.block {
background: #FFFFFF;
border-radius: 18rpx 18rpx 18rpx 18rpx;
padding: 32rpx 28rpx;
margin-bottom: 32rpx;
}
</style>