From 06c7a41fe4680ae98d8ccd25b17d715b2a036532 Mon Sep 17 00:00:00 2001 From: 陶杰 <1378534974@qq.com> Date: 星期一, 09 九月 2024 19:00:54 +0800 Subject: [PATCH] 1、 245-小程序-供应商-商品管理-回收站-平台或花农删除的商品全部到回收站,回收站增加恢复和删除的按钮,恢复可以将商品恢复到原来的状态,删除可以将此商品彻底删除 目前在回收站点击编辑上架等功能显示“商品未找到”点击删除也删不了商品 2、 255-小程序-供应商-增加同品类同等级价格排名,方便花农根据排名改价格(前后端修改) 3、252-小程序-花店-首页搜索、交易大厅搜索-1.点击分类显示下拉选择效果 2.热区扩大一些,点击<无法切换 --- uni_modules/um-dropdown/changelog.md | 19 + pages/home/components/home-search.vue | 19 + uni_modules/um-dropdown/components/um-dropdown/um-dropdown.vue | 322 ++++++++++++++++++++++++++ uni_modules/um-dropdown/readme.md | 88 +++++++ uni_modules/um-dropdown/components/um-icon/iconfont.ttf | 0 sub_pages/supplier/flower-manage/flower-manage.vue | 115 +++++++++ uni_modules/um-dropdown/components/um-icon/um-icon.vue | 63 +++++ uni_modules/um-dropdown/components/um-icon/icons.js | 3 uni_modules/um-dropdown/package.json | 84 +++++++ 9 files changed, 708 insertions(+), 5 deletions(-) diff --git a/pages/home/components/home-search.vue b/pages/home/components/home-search.vue index 5194327..d8a366c 100644 --- a/pages/home/components/home-search.vue +++ b/pages/home/components/home-search.vue @@ -1,12 +1,15 @@ <template> <view class="p15 bg-white"> <view class="search-container m-t-12 flex"> - <view class="flex m-r-20" @click="changeType"> + <!-- <view class="flex m-r-20" @click="changeType"> <view class="m-r-10" style="line-height: 80rpx;" > {{type=='flower'?'按鲜花':'按店铺'}} </view> <u-icon name="arrow-down"></u-icon> + </view> --> + <view class="flex m-r-20"> + <um-dropdown width="200rpx" @change="fnChange" :defaultIndex="def" rangeKey="label" :optionList="typeList"></um-dropdown> </view> <view class="flex1 input"> <u-input placeholder="请输入花名" v-model="search_flow" clearable @confirm="buttonSearchFlow" @clear="()=>{ @@ -52,6 +55,17 @@ history_flower: [], type: 'flower', //supplierName + def: 0, + typeList:[ + { + label: '按鲜花', + value: 'flower', + }, + { + label: '按店铺', + value: 'supplier', + }, + ], } }, onShow() { @@ -72,6 +86,9 @@ } }, methods: { + fnChange(e) { + this.type = e.value + }, changeType() { if (this.type == 'flower') { this.type = 'supplier' diff --git a/sub_pages/supplier/flower-manage/flower-manage.vue b/sub_pages/supplier/flower-manage/flower-manage.vue index 6d2ce88..53dd868 100644 --- a/sub_pages/supplier/flower-manage/flower-manage.vue +++ b/sub_pages/supplier/flower-manage/flower-manage.vue @@ -7,17 +7,23 @@ <view @click.stop="clickButton('inpass')" class="button button-search-inpass" style="flex:5"></view> <view @click.stop="clickButton('delete')" class="button button-search-delete" style="margin-top: -1rpx;"> </view> - + </view> + <view class="top-buttons" v-if="type==='delete'"> + <view v-if="type === 'delete'" class="button t-red " @click.stop="deleteSelected()">删除</view> + <view v-if="type === 'delete'" class="button " @click.stop="recoverSelected()">恢复</view> </view> <view class="p15" style="min-height: calc(100vh - 500rpx);"> <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + <view v-for="(item,index) in list" :key="index" class="m-b-24 flow-manage-list"> + <!-- <view v-if="type === 'delete'"><checkbox class="checkbox" :value="item.id" v-model="selectedFlowers" /> </view> + --> + <view class="flow-manage-list-item-radio" v-if="type === 'delete'"><radio :checked="isSelected(item.id)" @click="changeItem(item)"></radio></view> <view class="flow-manage-list-item"> <view class="flex m-r-6"> - <view class="img flower-img m-r-6"> + <view class="img flower-img m-r-6"> <image class="flower-img img100 " :src="item.cover" :class="[!item.stock?'component-stock-zero':'']" @click="previewImg(item.cover)"> - </image> <view class="status" :class="[!item.stock?'zero':'']" v-if="item.statusStr"> {{ item.statusStr}} @@ -27,6 +33,8 @@ <view class="flex1"> <view class=" flex"> <view class="title">{{item.name}}<span class="level">{{item.levelStr}}</span></view> + <view class="m-l-a m-r-0" ><span class="label">排名</span><span class="value">{{item.typeRank || '-'}}</span></view> + <view class="m-l-a m-r-0"> {{item.categoryStr || '-'}} </view> @@ -133,6 +141,8 @@ currentInputDto: {}, currentInputKey: '', inputplaceholder: '', + selectedFlowers: [], // 存储选中的花的 ID + ids: [], } }, onShow() { @@ -304,6 +314,78 @@ }) } }, + // 删除选中的花卉 + async deleteSelected() { + if (this.selectedFlowers.length === 0) { + this.$message.showToast('请选择要删除的商品'); + return; + } + + // 确认框 + await this.$message.confirm('确定删除此商品吗') + + var dto = { + ids: this.selectedFlowers, + } + + this.$message.showLoading() + this.$http.request('post', '/api/supplier/flower/list/delete/batch' , { + data: dto + }).then(res => { + if (res.code == 0) { + this.$message.showToast('操作成功') + this.refreshList() + + } + }).finally(() => { + this.$message.hideLoading() + }) + + + }, + async recoverSelected() { + if (this.selectedFlowers.length === 0) { + this.$message.showToast('请选择恢复的商品'); + return; + } + + // 确认框 + await this.$message.confirm('确定恢复此商品吗') + + var dto = { + ids: this.selectedFlowers, + } + + this.$message.showLoading() + this.$http.request('post', '/api/supplier/flower/list/restore/batch' , { + data: dto + }).then(res => { + if (res.code == 0) { + this.$message.showToast('操作成功') + this.refreshList() + } + }).finally(() => { + this.$message.hideLoading() + }) + + + }, + changeItem(item) { + const id = item.id; + // 判断selectedFlowers里面是否有item.id, 如果有则去掉,没有就加入 + if (this.selectedFlowers.includes(id)) { + // 移除选中的ID + this.selectedFlowers = this.selectedFlowers.filter(flowerId => flowerId !== id); + } else { + // 添加选中的ID + this.selectedFlowers.push(id); + } + }, + isSelected(id) { + // 检查ID是否在selectedFlowers中 + return this.selectedFlowers.includes(id); + } + } } </script> @@ -317,6 +399,12 @@ // padding: 20rpx 30rpx; padding: 22rpx 22rpx 20rpx 22rpx; background-color: #fff; + display: flex; + + .flow-manage-list-item-radio{ + width: 50rpx; + height: 50rpx; + } .flow-manage-list-item { .title { @@ -332,6 +420,25 @@ line-height: 40rpx; margin-left: 20rpx; } + } + .label { + + font-weight: 400; + font-size: 24rpx; + color: #666666; + text-align: left; + // padding-left: 10rpx; + // padding-right: 10rpx; + } + + .label::after { + content: ": " + } + + .value { + font-weight: 400; + font-size: 24rpx; + color: #666666; } .buttons { @@ -413,7 +520,7 @@ } } } - + .top-buttons { display: flex; padding: 22rpx 42rpx; diff --git a/uni_modules/um-dropdown/changelog.md b/uni_modules/um-dropdown/changelog.md new file mode 100644 index 0000000..abdf977 --- /dev/null +++ b/uni_modules/um-dropdown/changelog.md @@ -0,0 +1,19 @@ +## 1.0.8(2023-11-23) +*修复:异步加载数据时,默认下标为0时无法选中 +## 1.0.7(2023-10-09) +*修复:异步加载数据时,默认下标为0时无法选中 +## 1.0.6(2023-08-29) +*新增-H5环境下点击列表外部区域,列表自动收起(小程序目前没有实现该功能) +*优化-小程序环境下列表在页面加载时会闪动 +## 1.0.5(2023-08-29) +*新增-发生点击事件时,目标不是下拉菜单会自动收起,当界面存在多个下拉菜单时,点击其中一个其余的下拉菜单会收起 +## 1.0.4(2023-04-06) +优化异步数据下设置默认值报错的情况 +## 1.0.3(2023-03-21) +代码优化,新增自定义列表和菜单样式 +## 1.0.2(2023-03-20) +新增自定义列表和菜单样式 +## 1.0.1(2023-02-12) +优化缩小组件体积 +## 1.0.0(2023-02-12) +1.0.0 diff --git a/uni_modules/um-dropdown/components/um-dropdown/um-dropdown.vue b/uni_modules/um-dropdown/components/um-dropdown/um-dropdown.vue new file mode 100644 index 0000000..fadbeda --- /dev/null +++ b/uni_modules/um-dropdown/components/um-dropdown/um-dropdown.vue @@ -0,0 +1,322 @@ +<template> + <view class="option" :style="{'width': width,'height': height}" ref="dropdown"> + <view class="option-select-title" @click="fnShowOptionList()"> + <input class="inp-select" placeholder="请选择" :value="value" disabled /> + <!-- 箭头图标 --> + <view class="trans" :class="showOptionList?'trans-from':''"> + <um-icon name="down"></um-icon> + </view> + </view> + <!-- 下拉列表 --> + <view class="option-list" :style="[{height: ListHeightVal}, addStyle(listStyle)]"> + <view class="option-list-padding"> + <block v-for="(item, index) in optionList" :key="index"> + <view class="option-item" :style="[addStyle(selectItemIdx == index ? selectedItemStyle: itemStyle)]" + @click.stop="fnChangeOption(item, index)"> + {{rangeKey? item[rangeKey]: item}} + </view> + </block> + </view> + </view> + </view> +</template> + +<script> + /** + * @param optionList {Array} 下拉列表数据 + * @example <um-dropdown :optionList="optionList"></um-dropdown>/> + */ + export default { + props: { + // 菜单选择中时的样式 + itemStyle: { + type: [String, Object], + default: () => ({ + color: '#333', + fontSize: '28rpx' + }) + }, + // 菜单非选中时的样式 + selectedItemStyle: { + type: [String, Object], + default: () => ({ + color: '#2973F8', + fontSize: '28rpx', + background: '#F5F7FA' + }) + }, + // 自定义列表样式 + listStyle: { + type: [String, Object], + default: '', + }, + // 列表数据 + optionList: { + type: Array, + default: function() { + return [] + } + }, + // 选择框的宽度 + width: { + type: String, + default: '100%' + }, + // 选择框的高度 + height: { + type: String, + default: '100%' + }, + // 如果数组包含对象时,需要显示的key值 + rangeKey: { + type: String, + default: '' + }, + // 默认选中的下标 + defaultIndex: { + type: [String, Number], + default: '' + }, + // 列表高度,若不设置会展示所有列表选项 + listHeight: { + type: String, + default: '' + }, + + }, + data() { + return { + selectItem: '', // 选中的值 + selectItemIdx: null, // 选中的下标 + showOptionList: false, // 显示下拉 + } + }, + computed: { + value() { + if (!this.selectItem && this.defaultIndex !== '' && this.optionList.length) { + this.selectItemIdx = this.defaultIndex + let _val = this.rangeKey ? this.optionList[this.defaultIndex][this.rangeKey] : this.optionList[this + .defaultIndex] + this.$emit('change', this.optionList[this.defaultIndex]) + return _val + } else if (this.selectItem) { + return this.rangeKey ? this.selectItem[this.rangeKey] : this.selectItem + } else { + return '' + } + }, + ListHeightVal() { + if (this.showOptionList) { + if (this.listHeight) { + return this.listHeight + } else { + // 70是单行高度,24是列表上下内边距 + return (this.optionList.length * 70 + 24) + 'rpx' + } + } else { + return '0' + } + + } + }, + // #ifdef H5 + mounted() { + document.addEventListener('click', this.handleDocumentClick); + }, + beforeDestroy() { + document.removeEventListener('click', this.handleDocumentClick); + }, + // #endif + methods: { + // 点击组件外部区域时自动收起菜单 + handleDocumentClick(e) { + const dropdown = this.$refs.dropdown.$el; + if (dropdown && !dropdown.contains(e.target)) { + this.showOptionList = false; + } + }, + // 控制列表显示与隐藏 + fnShowOptionList() { + this.$emit('click') + if (this.optionList.length) { + this.showOptionList = !this.showOptionList + } else { + // 如果列表为空,发送一个事件 + this.$emit('openNull') + console.log('mu-dropdown列表数据唯空无法展开') + } + + }, + // 点击列表时触发 + fnChangeOption(item, index) { + this.selectItem = item + this.selectItemIdx = index + this.showOptionList = false + this.$emit('change', item) + }, + /** + * @description 样式转换 + * 对象转字符串,或者字符串转对象 + * @param {object | string} customStyle 需要转换的目标 + * @param {String} target 转换的目的,object-转为对象,string-转为字符串 + * @returns {object|string} + */ + addStyle(customStyle, target = 'object') { + // 字符串转字符串,对象转对象情形,直接返回 + if (this.empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === + 'string' && + typeof(customStyle) === 'string') { + return customStyle + } + // 字符串转对象 + if (target === 'object') { + // 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的 + customStyle = this.trim(customStyle) + // 根据";"将字符串转为数组形式 + const styleArray = customStyle.split(';') + const style = {} + // 历遍数组,拼接成对象 + for (let i = 0; i < styleArray.length; i++) { + // 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤 + if (styleArray[i]) { + const item = styleArray[i].split(':') + style[this.trim(item[0])] = this.trim(item[1]) + } + } + return style + } + // 这里为对象转字符串形式 + let string = '' + for (const i in customStyle) { + // 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名 + const key = i.replace(/([A-Z])/g, '-$1').toLowerCase() + string += `${key}:${customStyle[i]};` + } + // 去除两端空格 + return this.trim(string) + }, + + /** + * @description 去除空格 + * @param String str 需要去除空格的字符串 + * @param String pos both(左右)|left|right|all 默认both + */ + trim(str, pos = 'both') { + str = String(str) + if (pos == 'both') { + return str.replace(/^\s+|\s+$/g, '') + } + if (pos == 'left') { + return str.replace(/^\s*/, '') + } + if (pos == 'right') { + return str.replace(/(\s*$)/g, '') + } + if (pos == 'all') { + return str.replace(/\s+/g, '') + } + return str + }, + /** + * 判断是否为空 + */ + empty(value) { + switch (typeof value) { + case 'undefined': + return true + case 'string': + if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true + break + case 'boolean': + if (!value) return true + break + case 'number': + if (value === 0 || isNaN(value)) return true + break + case 'object': + if (value === null || value.length === 0) return true + for (const i in value) { + return false + } + return true + } + return false + } + + } + } +</script> + +<style lang="scss"> + // 去掉列表滚动条 + ::-webkit-scrollbar { + display: none; + } + + .mask { + width: 100vw; + height: 100vh; + position: fixed; + position: relative; + background: #A3A3A3; + opacity: .5; + z-index: 9; + } + + .option { + width: 100%; + height: 100%; + position: relative; + + .option-select-title { + height: 100%; + padding: 0 20rpx; + display: flex; + justify-content: space-between; + align-items: center; + + .inp-select { + width: 100%; + height: 100%; + } + + .trans { + transition: transform 0.2s; + } + + .trans-from { + transform: rotate(-180deg); + } + + } + + .option-list { + box-sizing: content-box; + width: calc(100% - 20rpx); + // height: 0; + border-radius: 25rpx; + background: #FFF; + overflow: scroll; + position: absolute; + top: calc(100% + 20rpx); + left: 10rpx; + right: 10rpx; + z-index: 10; + box-shadow: 0 0 15rpx #A3A3A3; + transition: height .2s; + + .option-list-padding { + padding: 12rpx 0; + } + + .option-item { + height: 70rpx; + text-align: center; + line-height: 70rpx; + } + + } + + + } +</style> \ No newline at end of file diff --git a/uni_modules/um-dropdown/components/um-icon/iconfont.ttf b/uni_modules/um-dropdown/components/um-icon/iconfont.ttf new file mode 100644 index 0000000..6c2d2af --- /dev/null +++ b/uni_modules/um-dropdown/components/um-icon/iconfont.ttf Binary files differ diff --git a/uni_modules/um-dropdown/components/um-icon/icons.js b/uni_modules/um-dropdown/components/um-icon/icons.js new file mode 100644 index 0000000..17f24a6 --- /dev/null +++ b/uni_modules/um-dropdown/components/um-icon/icons.js @@ -0,0 +1,3 @@ +export default { + 'mu-icon-down': '\ue63b', +} diff --git a/uni_modules/um-dropdown/components/um-icon/um-icon.vue b/uni_modules/um-dropdown/components/um-icon/um-icon.vue new file mode 100644 index 0000000..ddbea5c --- /dev/null +++ b/uni_modules/um-dropdown/components/um-icon/um-icon.vue @@ -0,0 +1,63 @@ +<template> + <text :class="['iconfont',customClass]" :style="{ 'color': color, 'font-size': size }"> + {{ icon }} + <!--  --> + </text> +</template> + +<script> + // 引入图标名称,以及对应的unicode + import icons from './icons' + export default { + props: { + // 图标类名 + name: { + type: String + }, + // 字体大小,注意加上单位,例如:12px + size: { + type: String + }, + // 图标颜色 + color: { + type: String, + default: '#919399' + }, + // 自定义class类名 + customClass: { + type: String, + default: '' + } + }, + computed: { + // 通过图标名,查找对应的图标 + icon() { + // 如果内置的图标中找不到对应的图标,就直接返回name值,因为用户可能传入的是unicode代码 + return icons['mu-icon-' + this.name] || this.name + } + }, + } +</script> + +<style lang="scss" scoped> + @font-face { + font-family: 'iconfont'; + src: url('iconfont.ttf') format('truetype'); + // src: url('~@/static/font/iconfont.ttf/iconfont.woff2') format('woff2'), + // url('~@/static/font/iconfont.woff') format('woff'), + // url('~@/static/font/iconfont.ttf') format('truetype'); + } + + .iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + // .iconfont:before { + // //  + // content: '\e63b'; + // } +</style> \ No newline at end of file diff --git a/uni_modules/um-dropdown/package.json b/uni_modules/um-dropdown/package.json new file mode 100644 index 0000000..74b8ad7 --- /dev/null +++ b/uni_modules/um-dropdown/package.json @@ -0,0 +1,84 @@ +{ + "id": "um-dropdown", + "displayName": "um-dropdown", + "version": "1.0.8", + "description": "下拉菜单,用于弹出一个下拉菜单给用户选择操作。样式简洁,支持自定义菜单样式,自定义列表数据", + "keywords": [ + "dropdown", + "下拉菜单", + "下拉选项", + "um-dropdown" +], + "repository": "", + "engines": { + "HBuilderX": "^3.4.17" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "n", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/um-dropdown/readme.md b/uni_modules/um-dropdown/readme.md new file mode 100644 index 0000000..3f03f93 --- /dev/null +++ b/uni_modules/um-dropdown/readme.md @@ -0,0 +1,88 @@ +<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">um-dropdown</h3> +<h3 align="center">下拉菜单</h3> + +## 说明 +um-dropdown 是基于[uni-app](https://uniapp.dcloud.io/)生态的一款下拉菜单组件,可自定义文本框样式,列表类容支持数组,数组内可使用object类型 + +## 使用方法 + 符合[uni-app](https://uniapp.dcloud.io/)的插件模块化规范配置,直接引用即可。 + +```html +<template> + <view style="width: 100px;height: 100px;"> + + <um-dropdown @change="fnChange" rangeKey="label" :optionList="listData" selectedItemStyle="color:2973F8;"></um-dropdown> + + </view> +</template> +<script> + export default { + data() { + return { + optionVal: '', // 选中列表的值 + listData: [ // 列表数据 + { + label: '北京', + value: '1', + }, + { + label: '上海', + value: '2', + }, + { + label: '重庆', + value: '3', + }, + { + label: '成都', + value: '4', + } + ] + } + }, + + methods: { + // 列表选中时触发事件,带出选中的值 + fnChange(e) { + this.optionVal = e + } + } + } +</script> +``` +## API + +Props + +| 属性名 | 说明 | 类型 | +| ---- | ---- | ---- | +| optionList | 菜单列表数据 | Array | +| rangeKey | 如果数据中包含对象时,需要显示的key值 | String | +| listHeight | 列表高度,设置后列表可以滑动(默认展示所有数据) | String | +| defaultIndex | 默认选中的下标 | String,Number | +| width | 菜单宽度(默认继承父元素width) | String | +| height | 菜单高度(默认继承父元素height) | String | +| listStyle | 自定义列表样式 | String,Object | +| itemStyle | 自定义菜单样式 | String,Object | +| selectedItemStyle | 菜单选中时的样式 | String,Object | + + +Events + +| 属性名 | 说明 | 类型 | +| ---- | ---- | ---- | +| change | 列表点击事件,值发生改变时触发 | Handler | +| click | 菜单点击事件 | Handler | +| openNull | 菜单点击事件,列表为空时触发 | Handler | + +平台差异 + +| 平台 | 说明 | +| ---- | ---- | +| H5 | 点击组件外部区域列表会自动收起 | +| 微信小程序 | 点击组件外部区域,列表不会自动收起 | +| 其他 | 问题待测,持续更新中 | + +## 交流反馈 + +留言信息无法实时查看,如需及时交流和反馈可加入QQ群:368365360 \ No newline at end of file -- Gitblit v1.9.3