feat:树形分类的新增和修改

This commit is contained in:
weiwei committed 2025-09-12 17:08:00 +08:00
1 parent 4b02337db3
commit 1b1642e51d
10 files changed
+275 -176

No files matched your search

+1 -10
View File
@@ -59,16 +59,7 @@
</view> </view>
</z-paging> </z-paging>
<tm-drawer <tm-drawer title="" :showClose="false" :showFooter="false" size="98%" v-model:show="state.showDrawer" :duration="100" zIndex="100">
title=""
:showClose="false"
:showFooter="false"
size="98%"
placement="bottom"
v-model:show="state.showDrawer"
:duration="100"
zIndex="100"
>
<z-paging <z-paging
ref="pageRef" ref="pageRef"
:fixed="true" :fixed="true"
@@ -79,7 +79,6 @@
:showClose="true" :showClose="true"
:showFooter="false" :showFooter="false"
size="auto" size="auto"
placement="bottom"
v-model:show="showDatePicker" v-model:show="showDatePicker"
:duration="100" :duration="100"
zIndex="100" zIndex="100"
+82 -9
View File
@@ -7,8 +7,8 @@
<text class="c-#0094ff! sub-text-24 mr-20rpx px-2 bg-#0094ff22 rounded-2">{{ item.status == "0" ? "正常" : "禁用" }}</text> <text class="c-#0094ff! sub-text-24 mr-20rpx px-2 bg-#0094ff22 rounded-2">{{ item.status == "0" ? "正常" : "禁用" }}</text>
</view> </view>
<view class="flex-row-center gap-2"> <view class="flex-row-center gap-2">
<tm-button class="px-2" size="xs" @click="">编辑</tm-button> <tm-button class="px-2" size="xs" @click="editCategary(item)">编辑</tm-button>
<tm-button class="px-2" size="xs" :linear="['to right', '#FFC328', '#E2000099']" @click="">删除</tm-button> <tm-button class="px-2" size="xs" :linear="['to right', '#FFC328', '#E2000099']" @click="delCategary(item.id)">删除</tm-button>
</view> </view>
</view> </view>
<view class="h-100rpx"></view> <view class="h-100rpx"></view>
@@ -20,18 +20,39 @@
<tm-drawer <tm-drawer
title="分类" title="分类"
:showClose="true" :showClose="true"
:showFooter="true" :showFooter="false"
size="90%" size="90%"
placement="bottom"
v-model:show="categaryFormDrawer" v-model:show="categaryFormDrawer"
:duration="100" :duration="100"
zIndex="100" zIndex="100"
bgColor="#F5F5F5" bgColor="#F5F5F5"
> >
<view>分类名称:</view> <view class="card p-4 mb-2">
<tm-input v-model="form.name" type="text" :showClear="true" placeholder="请输入分类名称"></tm-input> <view class="prefix_title mb-2">基本信息</view>
<view>父级分类:</view> <tm-form @submit="saveCategary" v-model="form" :rules="[]" direction="horizontal">
<shop-categary-tree :node-data="categoryTree" @currentNode="currentNode" /> <tm-form-item name="name" label="分类名称">
<tm-input v-model="form.name" type="text" :showClear="true" placeholder="请输入分类名称"></tm-input>
</tm-form-item>
<tm-form-item name="status" label="状态">
<tm-radio-group v-model="form.status" align="flex-end">
<tm-radio
:value="item.value"
:label="item.label"
v-for="(item, index) in [
{ label: '正常', value: '0' },
{ label: '下架', value: '1' },
]"
:key="index"
></tm-radio>
</tm-radio-group>
</tm-form-item>
<view class="prefix_title mb-2">父级分类</view>
<view class="card my-2">
<shop-categary-tree v-model="selectedNode" :node-data="categoryTree" @currentNode="currentNode" />
</view>
<tm-button form-type="submit" block>提 交</tm-button>
</tm-form>
</view>
</tm-drawer> </tm-drawer>
</crud-layout> </crud-layout>
</template> </template>
@@ -47,9 +68,11 @@ const categaryFormDrawer = ref(false)
const form = reactive({ const form = reactive({
id: "", id: "",
name: "", name: "",
status: "0", // 状态(0正常,1下架)
parentId: "", parentId: "",
}) })
const categoryTree = ref([]) const categoryTree = ref([])
const selectedNode = ref<any>({})
onLoad(() => { onLoad(() => {
getGoodsCategory() getGoodsCategory()
@@ -69,10 +92,60 @@ const getCategaryTree = async () => {
const addCategary = () => { const addCategary = () => {
getCategaryTree() getCategaryTree()
Object.assign(form, {
id: "",
name: "",
status: "0",
parentId: "",
})
selectedNode.value = {}
categaryFormDrawer.value = true
}
const editCategary = (item) => {
getCategaryTree()
Object.assign(form, item)
selectedNode.value = { id: item.parentId }
categaryFormDrawer.value = true categaryFormDrawer.value = true
} }
const currentNode = (item) => { const currentNode = (item) => {
form.parentId = item.categoryId // form.parentId = item.categoryId
}
const saveCategary = async () => {
console.log(form)
if (!form.name) return uni.showToast({ title: "请填写分类名称", icon: "none" })
if (selectedNode.value.id === form.id) return uni.showToast({ title: "父级分类不能是自身", icon: "none" })
try {
const params = { ...form, parentId: selectedNode.value.id }
uni.showLoading({ title: "保存中..." })
const { code, data, msg } = await (form.id ? prosperityShopApi.editCategary(params) : prosperityShopApi.addCategary(params))
if (code != 0) return uni.showToast({ title: msg || "保存失败", icon: "none" })
uni.showToast({ title: "保存成功", icon: "none" })
categaryFormDrawer.value = false
await getGoodsCategory()
} finally {
uni.hideLoading()
}
}
// 删除分类
const delCategary = async (id: string) => {
if (!id) return uni.showToast({ title: "分类id不存在", icon: "none" })
uni.showModal({
title: "确定删除分类吗?",
content: "",
success: async (res) => {
if (res.confirm) {
uni.showLoading({ title: "正在删除" })
const { code, msg } = await prosperityShopApi.delCategary(id)
if (code != 0) return uni.showToast({ title: msg || "删除失败", icon: "none" })
uni.showToast({ title: "删除成功", icon: "none" })
getGoodsCategory()
uni.hideLoading()
}
},
})
} }
</script> </script>
-1
View File
@@ -152,7 +152,6 @@
:showClose="true" :showClose="true"
:showFooter="false" :showFooter="false"
size="auto" size="auto"
placement="bottom"
v-model:show="showCategaryPicker" v-model:show="showCategaryPicker"
:duration="100" :duration="100"
zIndex="100" zIndex="100"
+1 -1
View File
@@ -83,7 +83,7 @@
</view> </view>
</z-paging> </z-paging>
<tm-drawer title="退款" :showClose="true" size="90%" placement="bottom" bgColor="#EBF6FF" v-model:show="state.showDrawer" zIndex="999"> <tm-drawer title="退款" :showClose="true" size="90%" bgColor="#EBF6FF" v-model:show="state.showDrawer" zIndex="999">
<view class="bg-white rounded-16rpx px-10rpx m-b-10rpx animate-both"> <view class="bg-white rounded-16rpx px-10rpx m-b-10rpx animate-both">
<z-tabs <z-tabs
:list="['同意退款', '拒绝退款']" :list="['同意退款', '拒绝退款']"
-1
View File
@@ -102,7 +102,6 @@
:showClose="false" :showClose="false"
:showFooter="true" :showFooter="true"
size="70%" size="70%"
placement="bottom"
v-model:show="state.showDrawer" v-model:show="state.showDrawer"
:duration="100" :duration="100"
zIndex="1200" zIndex="1200"
+23
View File
@@ -78,4 +78,27 @@ export default {
data, data,
}) })
}, },
// 删除商品分类
delCategary: (id: any): Promise<any> => {
return request({
url: `/supermarket/app/mall/merchant/category/${id}`,
method: "DELETE",
})
},
// 新增商品分类
addCategary: (data: any): Promise<any> => {
return request({
url: `/supermarket/app/mall/merchant/category/create`,
method: "POST",
data,
})
},
// 编辑商品分类
editCategary: (data: any): Promise<any> => {
return request({
url: `/supermarket/app/mall/merchant/category/update`,
method: "PUT",
data,
})
},
} }
@@ -1,6 +1,6 @@
<template> <template>
<view class="max-h-[60vh] overflow-y-auto mb-20rpx"> <view class="max-h-[60vh] overflow-y-auto mb-20rpx">
<shop-categary-tree :node-data="categoryTree" @currentNode="currentNode" /> <shop-categary-tree v-model="selectedNode" :node-data="categoryTree" @currentNode="currentNode" />
<view v-if="categoryTree.length === 0" class="text-center text-[#888] py-[40rpx]">暂无数据</view> <view v-if="categoryTree.length === 0" class="text-center text-[#888] py-[40rpx]">暂无数据</view>
</view> </view>
<view class="px-[20rpx] py-2 flex justify-between sticky bottom-0 bg-white"> <view class="px-[20rpx] py-2 flex justify-between sticky bottom-0 bg-white">
@@ -22,19 +22,18 @@ defineProps({
}) })
const emit = defineEmits(["confirm", "cancel"]) const emit = defineEmits(["confirm", "cancel"])
const selectedNode = ref<any>({})
const selectedCategary = ref<any>({}) const selectedCategary = ref<any>({})
const currentNode = (item) => { const currentNode = (item) => {
console.log(item)
selectedCategary.value = item selectedCategary.value = item
} }
function onConfirm() { function onConfirm() {
if (!selectedCategary.value) { if (!selectedNode.value) {
return uni.showToast({ title: "请选择分类", icon: "none" }) return uni.showToast({ title: "请选择分类", icon: "none" })
} }
emit("confirm", { categoryId: selectedCategary.value.id, categoryName: selectedCategary.value.name }) emit("confirm", { ...selectedNode, categoryId: selectedNode.value.id, categoryName: selectedNode.value.name })
} }
</script> </script>
+5 -6
View File
@@ -1,11 +1,12 @@
<template> <template>
<view class="tree-container"> <view class="tree-container">
<view v-for="item in nodeData" :key="item.id"> <view v-for="item in nodeData" :key="item.id">
<view class="tree-item" @click.stop="toCurrentNode(item)"> <view class="tree-item" :style="{ backgroundColor: item.id == selectedNode.id ? '#4b93ff' : '' }" @click.stop="toCurrentNode(item)">
<text>{{ item.name }}</text> <text>{{ item.name }}</text>
</view> </view>
<shop-categary-tree <shop-categary-tree
v-model="selectedNode"
v-if="item.children && item.children.length" v-if="item.children && item.children.length"
:node-data="item.children" :node-data="item.children"
:style="{ marginLeft: `${getLevel() * 60}rpx` }" :style="{ marginLeft: `${getLevel() * 60}rpx` }"
@@ -25,9 +26,11 @@ defineProps({
}, },
}) })
const emit = defineEmits(["currentNode"]) const emit = defineEmits(["currentNode"])
const selectedNode = defineModel<any>("modelValue")
const toCurrentNode = (item) => { const toCurrentNode = (item) => {
emit("currentNode", item) // emit("currentNode", item)
selectedNode.value = item
} }
const getLevel = () => { const getLevel = () => {
@@ -43,10 +46,6 @@ const getLevel = () => {
border-bottom: 1rpx solid #e4e7ed; border-bottom: 1rpx solid #e4e7ed;
display: flex; display: flex;
padding: 10rpx 0 10rpx 20rpx; padding: 10rpx 0 10rpx 20rpx;
}
.tree-item:hover {
background-color: #4b93ff;
border-radius: 10rpx; border-radius: 10rpx;
color: #fff;
} }
</style> </style>
@@ -1,9 +1,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, watch, type PropType, getCurrentInstance, onUpdated, nextTick } from 'vue'; import { ref, computed, onMounted, onBeforeUnmount, watch, type PropType, getCurrentInstance, onUpdated, nextTick } from "vue"
import { arrayNumberValid, arrayNumberValidByStyleMP, covetUniNumber, arrayNumberValidByStyleBorderColor, linearValid, getUnit, getUid } from "../../libs/tool"; import {
import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors"; arrayNumberValid,
import { useTmConfig } from "../../libs/config"; arrayNumberValidByStyleMP,
import { onPageScroll } from '@dcloudio/uni-app'; covetUniNumber,
arrayNumberValidByStyleBorderColor,
linearValid,
getUnit,
getUid,
} from "../../libs/tool"
import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors"
import { useTmConfig } from "../../libs/config"
import { onPageScroll } from "@dcloudio/uni-app"
/** /**
* @displayName 抽屉 * @displayName 抽屉
@@ -15,7 +23,7 @@ import { onPageScroll } from '@dcloudio/uni-app';
| --- | --- | --- | --- | | --- | --- | --- | --- |
| ☑️| ☑️ | ☑️ | ☑️ | ☑️ | 1.0.0 | | ☑️| ☑️ | ☑️ | ☑️ | ☑️ | 1.0.0 |
*/ */
defineOptions({ name: 'TmDrawer' }); defineOptions({ name: "TmDrawer" })
const { config } = useTmConfig() const { config } = useTmConfig()
const props = defineProps({ const props = defineProps({
@@ -24,84 +32,84 @@ const props = defineProps({
*/ */
customStyle: { customStyle: {
type: String, type: String,
default: "" default: "",
}, },
/** /**
* 标题 * 标题
*/ */
title: { title: {
type: String, type: String,
default: "标题" default: "标题",
}, },
/** /**
* 显示底部操作栏 * 显示底部操作栏
*/ */
showFooter: { showFooter: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 是否显示标题 * 是否显示标题
*/ */
showTitle: { showTitle: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
/** /**
* 是否显示底部关闭按钮 * 是否显示底部关闭按钮
*/ */
showClose: { showClose: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 遮罩是否允许点击被关闭 * 遮罩是否允许点击被关闭
*/ */
overlayClick: { overlayClick: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
/** /**
* 显示可v-model:show双向绑定 * 显示可v-model:show双向绑定
*/ */
show: { show: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 显示取消按钮 * 显示取消按钮
*/ */
showCancel: { showCancel: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
/** /**
* 取消按钮的文本 * 取消按钮的文本
*/ */
cancelText: { cancelText: {
type: String, type: String,
default: "取消" default: "取消",
}, },
/** /**
* 确认按钮的文本 * 确认按钮的文本
*/ */
confirmText: { confirmText: {
type: String, type: String,
default: "确认" default: "确认",
}, },
/** /**
* 动画时间 * 动画时间
*/ */
duration: { duration: {
type: Number, type: Number,
default: 300 default: 300,
}, },
/** /**
* 打开方向。 * 打开方向。
*/ */
position: { position: {
type: String as PropType<"top" | "bottom" | "left" | "right">, type: String as PropType<"top" | "bottom" | "left" | "right">,
default: "bottom" default: "bottom",
}, },
/** /**
* 打开方向为上和下时的圆角 * 打开方向为上和下时的圆角
@@ -109,7 +117,7 @@ const props = defineProps({
*/ */
round: { round: {
type: [String, Number], type: [String, Number],
default: "" default: "",
}, },
/** /**
* 左右时为内容宽, * 左右时为内容宽,
@@ -118,7 +126,7 @@ const props = defineProps({
*/ */
size: { size: {
type: [String, Number], type: [String, Number],
default: "50%" default: "50%",
}, },
/** /**
* 弹层最大的高度值,默认为屏幕的可视高 * 弹层最大的高度值,默认为屏幕的可视高
@@ -126,21 +134,21 @@ const props = defineProps({
*/ */
maxHeight: { maxHeight: {
type: String, type: String,
default: "" default: "",
}, },
/** /**
* 背景颜色 * 背景颜色
*/ */
bgColor: { bgColor: {
type: String, type: String,
default: 'white' default: "white",
}, },
/** /**
* 暗黑背景颜色,如果不提供默认读取全局的sheet配置 * 暗黑背景颜色,如果不提供默认读取全局的sheet配置
*/ */
darkBgColor: { darkBgColor: {
type: String, type: String,
default: '' default: "",
}, },
/** /**
@@ -150,14 +158,14 @@ const props = defineProps({
*/ */
disabledScroll: { disabledScroll: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 内容区域左右和下的边距。 * 内容区域左右和下的边距。
*/ */
contentMargin: { contentMargin: {
type: String, type: String,
default: '24' default: "24",
}, },
/** /**
* 宽屏时是否让内容剧中显示 * 宽屏时是否让内容剧中显示
@@ -166,21 +174,21 @@ const props = defineProps({
*/ */
widthCoverCenter: { widthCoverCenter: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 距离顶部的偏移量 * 距离顶部的偏移量
*/ */
offsetTop: { offsetTop: {
type: [String, Number], type: [String, Number],
default: '0' default: "0",
}, },
/** /**
* 弹层的层级 * 弹层的层级
*/ */
zIndex: { zIndex: {
type: [String, Number], type: [String, Number],
default: 1100 default: 1100,
}, },
/** /**
* 懒加载 * 懒加载
@@ -189,50 +197,50 @@ const props = defineProps({
*/ */
lazy: { lazy: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* 关闭前执行,可以是异步函数,只有当用户点击confirm时才会触发。如果返回false将阻止关闭。true允许关闭。 * 关闭前执行,可以是异步函数,只有当用户点击confirm时才会触发。如果返回false将阻止关闭。true允许关闭。
*/ */
beforeClose: { beforeClose: {
type: [Function, Boolean] as PropType<() => Promise<boolean>>, type: [Function, Boolean] as PropType<() => Promise<boolean>>,
default: true default: true,
} },
}) })
const emit = defineEmits([ const emit = defineEmits([
/** /**
* 点击遮罩事件 * 点击遮罩事件
*/ */
'click', "click",
/** /**
* 关闭是触发 * 关闭是触发
*/ */
'close', "close",
/** /**
* 打开时触发 * 打开时触发
*/ */
'open', "open",
/** /**
* 打开前执行 * 打开前执行
*/ */
'beforeOpen', "beforeOpen",
/** /**
* 关闭前执行 * 关闭前执行
*/ */
'beforeClose', "beforeClose",
/** /**
* 等同v-model:show * 等同v-model:show
*/ */
'update:show', "update:show",
/** /**
* 取消时触发 * 取消时触发
*/ */
'cancel', "cancel",
/** /**
* 确认时触发 * 确认时触发
*/ */
'confirm' "confirm",
]) ])
const isLoading = ref(false) const isLoading = ref(false)
@@ -251,13 +259,16 @@ const windtopReal = ref(0)
const tantiaoTrue = ref(false) const tantiaoTrue = ref(false)
const safeFooterHeight = ref(0) const safeFooterHeight = ref(0)
const lezyShowModal = ref(props.lazy ? false : true) const lezyShowModal = ref(props.lazy ? false : true)
watch(() => props.show, (newVal) => { watch(
if (newVal) { () => props.show,
showAlert() (newVal) => {
} else { if (newVal) {
closeAlert() showAlert()
} } else {
}) closeAlert()
}
},
)
const _lazy = computed(() => props.lazy) const _lazy = computed(() => props.lazy)
const _customStyle = computed(() => props.customStyle) const _customStyle = computed(() => props.customStyle)
@@ -276,10 +287,10 @@ const _round = computed(() => {
let radius = covetUniNumber(round, config.unit) let radius = covetUniNumber(round, config.unit)
let _r = "none" let _r = "none"
if (props.position == 'top') { if (props.position == "top") {
_r = `0px 0px ${radius} ${radius}` _r = `0px 0px ${radius} ${radius}`
} }
if (props.position == 'bottom') { if (props.position == "bottom") {
_r = `${radius} ${radius} 0px 0px` _r = `${radius} ${radius} 0px 0px`
} }
return _r return _r
@@ -288,7 +299,7 @@ const _offset = computed(() => {
let offset = covetUniNumber(props.offsetTop, config.unit) let offset = covetUniNumber(props.offsetTop, config.unit)
let x = parseFloat(offset) let x = parseFloat(offset)
let unit = getUnit(offset) let unit = getUnit(offset)
if (unit == 'rpx') { if (unit == "rpx") {
x = uni.upx2px(x) x = uni.upx2px(x)
} }
return x return x
@@ -298,7 +309,7 @@ const _contentMargin = computed(() => covetUniNumber(props.contentMargin, config
const _showFooter = computed(() => props.showFooter) const _showFooter = computed(() => props.showFooter)
const _maxHeight = computed(() => { const _maxHeight = computed(() => {
if (props.maxHeight == "") return "" if (props.maxHeight == "") return ""
if (props.position == 'left' || props.position == 'right') return "" if (props.position == "left" || props.position == "right") return ""
return covetUniNumber(props.maxHeight, config.unit) return covetUniNumber(props.maxHeight, config.unit)
}) })
@@ -308,8 +319,8 @@ const _confirmText = computed(() => props.confirmText)
const _animationFun = computed(() => config.animation) const _animationFun = computed(() => config.animation)
const _bgColor = computed(() => { const _bgColor = computed(() => {
let bgcolor = props.bgColor let bgcolor = props.bgColor
if (config.mode == 'dark') { if (config.mode == "dark") {
if (props.darkBgColor != '') { if (props.darkBgColor != "") {
bgcolor = props.darkBgColor bgcolor = props.darkBgColor
} else { } else {
bgcolor = config.sheetDarkColor bgcolor = config.sheetDarkColor
@@ -318,19 +329,19 @@ const _bgColor = computed(() => {
return getDefaultColor(bgcolor) return getDefaultColor(bgcolor)
}) })
const __height = computed(() => { const __height = computed(() => {
let h = '100%' let h = "100%"
// #ifdef WEB // #ifdef WEB
h = `calc(100% - ${windtopReal.value}px)` h = `calc(100% - ${windtopReal.value}px)`
// #endif // #endif
// #ifdef APP // #ifdef APP
if (_offset.value > 0) { if (_offset.value > 0) {
h = _height.value + 'px' h = _height.value + "px"
} }
// #endif // #endif
return h return h
}) })
const _titleFontSize = computed(() => (config.fontSizeScale * 16).toString() + 'px') const _titleFontSize = computed(() => (config.fontSizeScale * 16).toString() + "px")
const _isDark = computed(() => config.mode == 'dark') const _isDark = computed(() => config.mode == "dark")
// Lifecycle hooks // Lifecycle hooks
onMounted(() => { onMounted(() => {
@@ -340,8 +351,8 @@ onMounted(() => {
_width.value = sys.windowWidth _width.value = sys.windowWidth
_height.value = sys.windowHeight _height.value = sys.windowHeight
windtop.value = sys.windowTop + (_position.value == 'bottom' ? 0 : _offset.value) windtop.value = sys.windowTop + (_position.value == "bottom" ? 0 : _offset.value)
windtopReal.value = _position.value == 'bottom' ? (sys.windowTop + _offset.value) : sys.windowTop windtopReal.value = _position.value == "bottom" ? sys.windowTop + _offset.value : sys.windowTop
// #endif // #endif
// #ifdef APP // #ifdef APP
_width.value = sys.windowWidth _width.value = sys.windowWidth
@@ -360,26 +371,25 @@ onBeforeUnmount(() => {
}) })
const cancelEvt = () => { const cancelEvt = () => {
emit('cancel') emit("cancel")
closeAlert() closeAlert()
} }
const confirmEvt = async () => { const confirmEvt = async () => {
emit('confirm') emit("confirm")
let isPass = true; let isPass = true
if (typeof props.beforeClose == 'function') { if (typeof props.beforeClose == "function") {
isLoading.value = true; isLoading.value = true
// @ts-ignore // @ts-ignore
isPass = await props.beforeClose(); isPass = await props.beforeClose()
} }
isLoading.value = false; isLoading.value = false
if (!isPass) { if (!isPass) {
return; return
} }
closeAlert() closeAlert()
} }
const onClickOverflowy = (evt: Event) => { const onClickOverflowy = (evt: Event) => {
evt.stopPropagation() evt.stopPropagation()
/** /**
@@ -392,22 +402,21 @@ const onClickOverflowy = (evt: Event) => {
tantiaoTrue.value = true tantiaoTrue.value = true
tid2.value = setTimeout(() => { tid2.value = setTimeout(() => {
tantiaoTrue.value = false tantiaoTrue.value = false
}, 200); }, 200)
return; return
} }
closeAlert() closeAlert()
} }
const closeAlert = () => { const closeAlert = () => {
if (actinon.value || isLoading.value) return if (actinon.value || isLoading.value) return
if (status.value == 'close') return if (status.value == "close") return
actinon.value = true actinon.value = true
status.value = 'close' status.value = "close"
/** /**
* 关闭前执行 * 关闭前执行
*/ */
emit('beforeClose') emit("beforeClose")
clearTimeout(tid.value) clearTimeout(tid.value)
tid.value = setTimeout(() => { tid.value = setTimeout(() => {
@@ -417,17 +426,17 @@ const closeAlert = () => {
const showAlert = () => { const showAlert = () => {
if (actinon.value) return if (actinon.value) return
if (status.value == 'open') return if (status.value == "open") return
showOverflay.value = true showOverflay.value = true
actinon.value = true actinon.value = true
/** /**
* 打开前执行 * 打开前执行
*/ */
emit('beforeOpen') emit("beforeOpen")
clearTimeout(tid.value) clearTimeout(tid.value)
tid.value = setTimeout(() => { tid.value = setTimeout(() => {
status.value = 'open' status.value = "open"
tid.value = setTimeout(() => { tid.value = setTimeout(() => {
onEnd() onEnd()
}, _duration.value) }, _duration.value)
@@ -435,35 +444,30 @@ const showAlert = () => {
} }
function openDrawer() { function openDrawer() {
showAlert(); showAlert()
} }
function onEnd() { function onEnd() {
actinon.value = false; actinon.value = false
if (status.value === 'close') { if (status.value === "close") {
showOverflay.value = false; showOverflay.value = false
emit('close'); emit("close")
emit('update:show', false); emit("update:show", false)
if (_lazy.value) { if (_lazy.value) {
lezyShowModal.value = false; lezyShowModal.value = false
} }
} else { } else {
emit('open'); emit("open")
if (_lazy.value) { if (_lazy.value) {
lezyShowModal.value = true; lezyShowModal.value = true
} }
} }
} }
function maskerMove(evt: TouchEvent) { function maskerMove(evt: TouchEvent) {
evt.preventDefault(); evt.preventDefault()
} }
</script> </script>
<script lang="ts"> <script lang="ts">
export default { export default {
@@ -473,7 +477,7 @@ export default {
addGlobalClass: true, addGlobalClass: true,
multipleSlots: true, multipleSlots: true,
}, },
}; }
</script> </script>
<template> <template>
<view> <view>
@@ -490,33 +494,49 @@ export default {
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<root-portal> <root-portal>
<!-- #endif --> <!-- #endif -->
<view @click="onClickOverflowy" @touchmove="maskerMove" v-if="showOverflay" :id="id" ref="tmDrawerWrap" <view
class="tmDrawerWrap" :class="[ @click="onClickOverflowy"
status == 'open' ? 'tmModalWrap_on' : 'tmModalWrap_off', @touchmove="maskerMove"
(_position == 'top' || _position == 'bottom') && _widthCoverCenter ? 'tmDrawerWrapContentMinwidthWrapDir' : '', v-if="showOverflay"
'tmDrawerWrap_' + _position :id="id"
]" :style="[{ ref="tmDrawerWrap"
width: '100%', class="tmDrawerWrap"
top: (windtop + 'px'), :class="[
height: __height, status == 'open' ? 'tmModalWrap_on' : 'tmModalWrap_off',
zIndex: zIndex, (_position == 'top' || _position == 'bottom') && _widthCoverCenter ? 'tmDrawerWrapContentMinwidthWrapDir' : '',
'transition-timing-function': _animationFun 'tmDrawerWrap_' + _position,
}, _customStyle]"> ]"
:style="[
<view @click.stop="" ref="tmDrawerWrapContent" class="tmDrawerWrapContent" :class="[ {
(_position == 'top' || _position == 'bottom') && _widthCoverCenter ? 'tmDrawerWrapContentMinwidth' : '', width: '100%',
'tmDrawerWrapContent_' + _position + (status == 'open' ? '_on' : ''), top: windtop + 'px',
tantiaoTrue ? 'tmModalWrapContent_Tantiao' : '' height: __height,
]" :id="wrapId" :style="{ zIndex: zIndex,
width: _position == 'left' || _position == 'right' ? _size : '100%', 'transition-timing-function': _animationFun,
height: _position == 'left' || _position == 'right' ? '100%' : _size, },
borderRadius: _round, _customStyle,
maxHeight: _maxHeight != '' ? _maxHeight : '100%', ]"
minHeight: _size == 'auto' ? '350rpx' : '0px', >
'transition-timing-function': _animationFun, <view
backgroundColor: _bgColor @click.stop=""
}"> ref="tmDrawerWrapContent"
class="tmDrawerWrapContent"
:class="[
(_position == 'top' || _position == 'bottom') && _widthCoverCenter ? 'tmDrawerWrapContentMinwidth' : '',
'tmDrawerWrapContent_' + _position + (status == 'open' ? '_on' : ''),
tantiaoTrue ? 'tmModalWrapContent_Tantiao' : '',
]"
:id="wrapId"
:style="{
width: _position == 'left' || _position == 'right' ? _size : '100%',
height: _position == 'left' || _position == 'right' ? '100%' : _size,
borderRadius: _round,
maxHeight: _maxHeight != '' ? _maxHeight : '100%',
minHeight: _size == 'auto' ? '350rpx' : '0px',
'transition-timing-function': _animationFun,
backgroundColor: _bgColor,
}"
>
<view v-if="_showClose" class="tmDrawerXclose"> <view v-if="_showClose" class="tmDrawerXclose">
<tm-icon @click="closeAlert" color="#dcdcdc" size="52" name="close-circle-fill"></tm-icon> <tm-icon @click="closeAlert" color="#dcdcdc" size="52" name="close-circle-fill"></tm-icon>
</view> </view>
@@ -529,14 +549,15 @@ export default {
<slot name="title" :show="show"> <slot name="title" :show="show">
<text <text
:style="{ fontSize: _titleFontSize, color: _isDark ? 'white' : 'black', opacity: '0.64' }" :style="{ fontSize: _titleFontSize, color: _isDark ? 'white' : 'black', opacity: '0.64' }"
class="tmDrawertitleBox">{{ _title }}</text> class="tmDrawertitleBox"
>{{ _title }}</text
>
</slot> </slot>
</view> </view>
</view> </view>
<view v-if="!disabledScroll && _size != 'auto'" style="flex: 1;" class="tmModalWrapBoxContent"> <view v-if="!disabledScroll && _size != 'auto'" style="flex: 1" class="tmModalWrapBoxContent">
<scroll-view style="height:100%;position:absolute;width:100%;" :scroll-y="true" <scroll-view style="height: 100%; position: absolute; width: 100%" :scroll-y="true" :rebound="false">
:rebound="false">
<view :style="{ padding: `0px ${_contentMargin} 0px ${_contentMargin}` }"> <view :style="{ padding: `0px ${_contentMargin} 0px ${_contentMargin}` }">
<!-- <!--
@slot 默认插槽 @slot 默认插槽
@@ -545,36 +566,36 @@ export default {
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<view v-else <view v-else :style="{ height: '100%', padding: `0px ${_contentMargin} 0px ${_contentMargin}` }">
:style="{ height: '100%', padding: `0px ${_contentMargin} 0px ${_contentMargin}` }">
<!-- <!--
@slot 默认插槽 @slot 默认插槽
--> -->
<slot></slot> <slot></slot>
</view> </view>
<view v-if="showFooter && lezyShowModal" class="tmDrawerFooter" :style="{ backgroundColor: _bgColor }">
<view v-if="showFooter && lezyShowModal" class="tmDrawerFooter"
:style="{ backgroundColor: _bgColor }">
<view :style="{ height: _contentMargin }"></view> <view :style="{ height: _contentMargin }"></view>
<!-- <!--
@slot 底部操作栏 @slot 底部操作栏
--> -->
<slot name="footer"> <slot name="footer">
<view <view style="flex-direction: row; align-items: center; justify-content: center; display: flex; margin: 0 20rpx">
style="flex-direction: row;align-items: center;justify-content: center;display:flex;"> <tm-button
<tm-button :loading="isLoading" width="0px" @click="cancelEvt" v-if="_showCancel" :loading="isLoading"
skin="thin" style="margin-right: 16px;flex:1">{{ _cancelText }}</tm-button> width="0px"
<tm-button :loading="isLoading" width="0px" @click="confirmEvt" style="flex:1">{{ @click="cancelEvt"
_confirmText v-if="_showCancel"
}}</tm-button> skin="thin"
style="margin-right: 16px; flex: 1"
>{{ _cancelText }}</tm-button
>
<tm-button :loading="isLoading" width="0px" @click="confirmEvt" style="flex: 1">{{ _confirmText }}</tm-button>
</view> </view>
</slot> </slot>
<view :style="{ height: safeFooterHeight + 'px' }"></view> <view :style="{ height: safeFooterHeight + 'px' }"></view>
</view> </view>
</view> </view>
</view> </view>
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
</root-portal> </root-portal>
@@ -613,7 +634,6 @@ export default {
line-clamp: 1; line-clamp: 1;
display: -webkit-box; display: -webkit-box;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.tmDrawerWrap_bottom { .tmDrawerWrap_bottom {
@@ -661,13 +681,12 @@ export default {
} }
@keyframes bottomAnimate3d { @keyframes bottomAnimate3d {
0% { 0% {
transform: translate(0%, 100%) translate3d(0%, 20px, 0px) rotateX(45deg) transform: translate(0%, 100%) translate3d(0%, 20px, 0px) rotateX(45deg);
} }
100% { 100% {
transform: translate(0%, 0%) translate3d(0, 0, 0px) rotateX(0deg) transform: translate(0%, 0%) translate3d(0, 0, 0px) rotateX(0deg);
} }
} }
@@ -736,7 +755,6 @@ export default {
75% { 75% {
transform: scale(0.97); transform: scale(0.97);
opacity: 0.9; opacity: 0.9;
} }
85% { 85% {
@@ -746,7 +764,6 @@ export default {
100% { 100% {
transform: scale(1); transform: scale(1);
opacity: 1; opacity: 1;
} }
} }