Compare commits

..

8 Commits

Author SHA1 Message Date
duanshuwen
9546662cc9 Merge branch 'order-729'
合并order-729分支代码
2025-08-03 18:08:22 +08:00
60d23d8077 feat: 实现了我的设置页面的相关操作 2025-08-03 17:54:11 +08:00
f77633f04a feat: 替换了域名 2025-08-03 16:36:33 +08:00
5805d83af2 feat: 替换了抽屉的实现方案 2025-08-03 16:36:13 +08:00
a88d909a90 feat: 调整了markdown 的样式 2025-08-03 14:55:25 +08:00
6c9fc5f222 feat: 打开日历选择日期 2025-08-03 14:19:06 +08:00
6422530057 Merge branch 'main' of https://git.brother7.cn/zoujing/YGChatCS 2025-08-03 13:53:42 +08:00
73d3f164b9 feat: 完成对话结束的标签 2025-08-03 13:53:38 +08:00
20 changed files with 666 additions and 352 deletions

View File

@ -1,3 +1,3 @@
const isProd = true const isProd = true
export const BASE_URL = 'http://8.138.234.141/ingress' export const BASE_URL = 'https://onefeel.brother7.cn/ingress' //'http://8.138.234.141/ingress'

View File

@ -1,7 +1,7 @@
<template> <template>
<view class="container"> <view class="container">
<view class="chat-ai"> <view class="chat-ai">
<ChatMarkdown v-if="text.length > 0" :text="text"></ChatMarkdown> <ChatMarkdown :text="text"></ChatMarkdown>
<slot name="content"></slot> <slot name="content"></slot>
</view> </view>
<slot name="footer"></slot> <slot name="footer"></slot>
@ -34,7 +34,7 @@
min-width: 80px; min-width: 80px;
background: rgba(255,255,255,0.4); background: rgba(255,255,255,0.4);
box-shadow: 2px 2px 10px 0px rgba(0,0,0,0.1); box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.1);
border-radius: 4px 20px 20px 20px; border-radius: 4px 20px 20px 20px;
border: 1px solid; border: 1px solid;
border-color: #FFFFFF; border-color: #FFFFFF;

View File

@ -33,7 +33,8 @@
<CreateServiceOrder v-else-if="item.toolCall.componentName === CompName.createWorkOrderCard"/> <CreateServiceOrder v-else-if="item.toolCall.componentName === CompName.createWorkOrderCard"/>
</template> </template>
<template #footer > <template #footer >
<!-- <text> 这个是底部 </text> --> <!-- 这个是底部 -->
<AttachListComponent v-if="item.question" :question="item.question" @replySent="handleReply"/>
</template> </template>
</ChatCardAI> </ChatCardAI>
</template> </template>
@ -93,6 +94,7 @@
import DiscoveryCardComponent from '../module/discovery/DiscoveryCardComponent.vue'; import DiscoveryCardComponent from '../module/discovery/DiscoveryCardComponent.vue';
import ActivityListComponent from '../module/banner/ActivityListComponent.vue'; import ActivityListComponent from '../module/banner/ActivityListComponent.vue';
import RecommendPostsComponent from '../module/recommend/RecommendPostsComponent.vue'; import RecommendPostsComponent from '../module/recommend/RecommendPostsComponent.vue';
import AttachListComponent from '../module/attach/AttachListComponent.vue';
import CreateServiceOrder from '@/components/CreateServiceOrder/index.vue' import CreateServiceOrder from '@/components/CreateServiceOrder/index.vue'
@ -186,6 +188,9 @@
const handleReplyInstruct = (item) => { const handleReplyInstruct = (item) => {
if(item.type === 'MyOrder') { if(item.type === 'MyOrder') {
/// ///
uni.navigateTo({
url: '/pages/order/list'
})
return return
} }
commonType = item.type commonType = item.type
@ -365,7 +370,6 @@
if (chunk && chunk.finish) { if (chunk && chunk.finish) {
// //
const finishInterval = setInterval(() => { const finishInterval = setInterval(() => {
console.log('aiMsgBuffer.length:', aiMsgBuffer.length)
if (aiMsgBuffer.length === 0) { if (aiMsgBuffer.length === 0) {
clearInterval(finishInterval); clearInterval(finishInterval);
clearInterval(loadingTimer); clearInterval(loadingTimer);
@ -382,11 +386,16 @@
chatMsgList.value[aiMsgIndex].msg = ''; chatMsgList.value[aiMsgIndex].msg = '';
} }
} }
//
if(chunk.toolCall) { if(chunk.toolCall) {
console.log('chunk.toolCall:', chunk.toolCall) console.log('chunk.toolCall:', chunk.toolCall)
chatMsgList.value[aiMsgIndex].toolCall = chunk.toolCall chatMsgList.value[aiMsgIndex].toolCall = chunk.toolCall
} }
//
if(chunk.question && chunk.question.length > 0) {
chatMsgList.value[aiMsgIndex].question = chunk.question
}
isSessionActive = false; isSessionActive = false;
scrollToBottom(); scrollToBottom();

View File

@ -1,20 +1,31 @@
<template> <template>
<view class="nav-bar"> <view class="nav-bar">
<view class="nav-item" @click="openDrawer"> <view class="nav-item" @click="showDrawer('showLeft')">
<image src="/static/drawer_icon.png" mode="aspectFit" class="nav-item-icon"></image> <image class="nav-item-icon" src="/static/drawer_icon.png" mode="aspectFit"></image>
</view> </view>
<uni-drawer ref="showLeft" mode="left" :width="320">
<DrawerHome @closeDrawer="closeDrawer('showLeft')" />
</uni-drawer>
</view> </view>
</template> </template>
<script setup> <script setup>
import { defineEmits } from 'vue' import { defineEmits, ref } from 'vue'
import DrawerHome from "@/pages/drawer/DrawerHome.vue";
const emits = defineEmits(['openDrawer']) const showLeft = ref(false)
const openDrawer = () => { //
emits('openDrawer') const showDrawer = (e) => {
console.log('=============打开抽屉') showLeft.value.open()
} }
//
const closeDrawer = (e) => {
showLeft.value.close()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -4,7 +4,7 @@
<!-- :style="backgroundStyle" --> <!-- :style="backgroundStyle" -->
<view class="top-item1-left"> <view class="top-item1-left">
<image :src="initPageImages.welcomeImageUrl"></image> <image :src="initPageImages.welcomeImageUrl"></image>
<text>{{ currentDate }} 多云 -36 cc </text> <text>{{ currentDate }} 多云 -36 dd </text>
</view> </view>
<view class="top-item1-right"> <view class="top-item1-right">
<image :src="initPageImages.logoImageUrl"></image> <image :src="initPageImages.logoImageUrl"></image>

View File

@ -1,48 +1,23 @@
<template> <template>
<view class="drawer-home"> <view class="drawer-home">
<view class="drawer-home-nav"> <view class="drawer-home-nav">
<text>抽屉页面</text> <uni-icons type="closeempty" size="22" color="#333333" class="close-icon" @click="closeDrawer"></uni-icons>
</view> <text class="title">我的</text>
<button @click="closeDrawer" type="default">关闭</button>
<button @click="login" type="default">登录</button>
<button @click="sendChat" type="default">会话测试</button>
<view class="drawer-list">
<view v-for="(item,index) in 100" :key="index">
<text class="message-item">{{item}}</text>
</view>
</view> </view>
<MineSetting/>
</view> </view>
</template> </template>
<script setup> <script setup>
import MineSetting from './MineSetting.vue'
import { defineEmits } from 'vue' import { defineEmits } from 'vue'
const emits = defineEmits(['closeDrawer']) const emits = defineEmits(['closeDrawer'])
import * as loginMnager from '@/manager/LoginManager'
import request from '../../request/base/request'
const closeDrawer = () => { const closeDrawer = () => {
emits('closeDrawer') emits('closeDrawer')
console.log('=============关闭抽屉')
} }
const login = () => {
loginMnager.loginAuth()
.then(res => {
console.log('登录成功', res)
// token
})
.catch(err => {
console.error('登录失败', err)
//
})
console.log('=============登录')
//
}
</script> </script>
@ -50,43 +25,26 @@
.drawer-home { .drawer-home {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
background-color: #E9F3F7; background-color: #fff;
padding-top: 44px; padding-top: 44px;
}
.drawer-home-nav {
position: relative;
padding: 12px;
display: flex;
justify-content: center; /* 文字水平居中 */
align-items: center; /* 垂直居中 */
.drawer-home-nav { .title {
padding: 12px; font-size: 18px;
display: flex; text-align: center;
justify-content: center; color: #333333;
text {
font-size: 20px;
text-align: center;
}
} }
.drawer-list { .close-icon {
display: flex; position: absolute;
flex-direction: column; left: 12px; /* 距离左边12px */
height: 100%;
overflow-y: scroll;
}
.message-item {
display: flex;
justify-content: center;
background-color: white;
margin: 6px 12px;
padding: 8px 24px;
border-radius: 4px;
font-size: 14px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
text {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #333333;
}
} }
} }
</style> </style>

View File

@ -0,0 +1,149 @@
<template>
<view class="page">
<!-- 顶部用户信息 -->
<view class="user-card">
<view class="row avatar-row">
<text class="label">头像 </text>
<image class="avatar" :src="userInfo.avatar" mode="aspectFill" />
</view>
<view class="row">
<text class="label">昵称</text>
<text class="value">{{ userInfo.nickname }}</text>
</view>
<view class="row">
<text class="label">手机号</text>
<text class="value">{{ userInfo.phone }}</text>
</view>
</view>
<!-- 中间功能入口循环渲染 -->
<view class="menu-card">
<view
class="menu-item"
v-for="(item, index) in menuList"
:key="index"
@click="handleMenuClick(item)"
>
<text class="label">{{ item.label }}</text>
<uni-icons type="right" size="14" color="#ccc"></uni-icons>
</view>
</view>
<!-- 底部退出按钮 -->
<button class="logout-btn" @click="handleLogout">退出登录</button>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
//
const userInfo = ref({
avatar: '/static/default-avatar.png',
nickname: '微信用户',
phone: '182****0628'
})
// type
const menuList = ref([
// { label: '', type: 'navigate', url: '/pages/change-phone/change-phone' },
{ label: '账号注销', type: 'navigate', url: '/pages/cancel-account/cancel-account' },
// { label: '&', type: 'navigate', url: '/pages/agreement/agreement' },
{ label: '联系客服', type: 'action', action: 'contactService' }
])
//
onMounted(() => {
// TODO:
})
//
const handleMenuClick = (item) => {
if (item.type === 'navigate' && item.url) {
uni.navigateTo({ url: item.url })
} else if (item.type === 'action') {
if (item.action === 'contactService') {
uni.showToast({ title: '联系客服功能待实现', icon: 'none' })
}
}
}
// 退
const handleLogout = () => {
uni.showModal({
title: '温馨提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
uni.clearStorageSync()
uni.reLaunch({ url: '/pages/login/index' })
}
}
})
}
</script>
<style scoped>
.page {
padding: 24rpx;
background-color: #f6f6f6;
min-height: 100vh;
}
.user-card,
.menu-card {
background-color: #fff;
border-radius: 12rpx;
padding-left: 24rpx;
margin-bottom: 20rpx;
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 28rpx 24rpx 28rpx 0;
border-bottom: 1px solid #f0f0f0;
}
.row:last-child {
border-bottom: none;
}
.avatar-row .avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.label {
font-size: 28rpx;
color: #333;
}
.value {
font-size: 28rpx;
color: #666;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 28rpx 24rpx 28rpx 0;
border-bottom: 1px solid #f0f0f0;
}
.menu-item:last-child {
border-bottom: none;
}
.logout-btn {
width: 90%;
margin: 80rpx auto;
background-color: #fff;
color: #333;
border-radius: 8rpx;
border: none;
}
</style>

View File

@ -1,40 +1,18 @@
<template> <template>
<ex-drawer ref="drawer" width="488">
<!-- 抽屉页面 --> <view class="container">
<view class="mian-drawer" slot="drawerContent"> <ChatMainList/>
<drawer-home @closeDrawer="closeDrawer"></drawer-home> </view>
</view>
<!-- 主页面 -->
<view class="mian-container" slot="containerContent">
<chat-main-list @openDrawer="openDrawer"></chat-main-list>
</view>
</ex-drawer>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue";
import exDrawer from "@/third/ex-drawer/ex-drawer.vue";
import DrawerHome from "@/pages/drawer/DrawerHome.vue";
import ChatMainList from "../chat/ChatMainList.vue"; import ChatMainList from "../chat/ChatMainList.vue";
const drawer = ref();
const openDrawer = () => {
drawer.value.open();
};
const closeDrawer = () => {
drawer.value.close();
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mian-drawer { .container {
height: 100vh;
background-color: #ffffff;
}
.mian-container {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background-color: #ffffff; background-color: #ffffff;

View File

@ -0,0 +1,65 @@
<template>
<view class="tag-list">
<view
v-for="(item, index) in tags"
:key="index"
class="tag-item"
@click="handleClick(item)"
>
<text class="tag-text">{{ item }}</text>
</view>
</view>
</template>
<script setup>
import { ref, nextTick, defineEmits } from 'vue'
import { onMounted } from 'vue'
import { SCROLL_TO_BOTTOM } from '@/constant/constant'
const props = defineProps({
question: {
type: String,
default: ''
}
})
const tags = ref([])
const emits = defineEmits(['replySent']);
const handleClick = (item) => {
emits('replySent', item)
}
onMounted(() => {
tags.value = props.question.split('&').filter(tag => tag.trim() !== '')
nextTick(() => {
setTimeout(() => {
uni.$emit(SCROLL_TO_BOTTOM, true)
}, 300)
});
})
</script>
<style scoped lang="scss">
.tag-list {
display: flex;
flex-wrap: wrap;
padding: 6px 12px;
}
.tag-item {
background-color: #ffffff;
border-radius: 8px;
padding: 4px 10px;
margin-right: 8px;
margin-bottom: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.tag-text {
color: #00A6FF; /* 蓝色文字,可根据设计调整 */
font-size: 14px;
}
</style>

View File

@ -18,16 +18,41 @@
<text class="calendar-text">日历</text> <text class="calendar-text">日历</text>
</view> </view>
</view> </view>
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"
mode="single"
:default-value="selectedDate"
@close="handleCalendarClose"
@select="handleDateSelect"
/>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
const emit = defineEmits(['update:date']); // const emit = defineEmits(['update:date']); //
import Calender from '@/components/Calender/index.vue';
const activeIndex = ref(2); // const activeIndex = ref(2); //
const dates = ref([]); const dates = ref([]);
const calendarVisible = ref(false)
const selectedDate = ref('')
//
const handleCalendarClose = () => {
calendarVisible.value = false
}
//
const handleDateSelect = (data) => {
selectedDate.value = data.date
calendarVisible.value = false
console.log('选择的日期:', data.date)
emit('update:date', { fullDate: selectedDate.value}); //
}
// //
const initDates = () => { const initDates = () => {
const today = new Date(); const today = new Date();
@ -51,7 +76,7 @@ const selectDate = (index) => {
}; };
const openCalendar = () => { const openCalendar = () => {
uni.showToast({ title: '打开日历', icon: 'none' }); calendarVisible.value = true
}; };
onMounted(() => { onMounted(() => {

View File

@ -22,7 +22,7 @@
<text class="card-unit">/</text> <text class="card-unit">/</text>
</view> </view>
<text class="card-btn">下单</text> <text class="card-btn" @click="placeOrderHandle(item)">下单</text>
</view> </view>
</view> </view>
</view> </view>
@ -39,6 +39,13 @@
default: {} default: {}
} }
}) })
///
const placeOrderHandle = (item) => {
uni.navigateTo({
url: `/pages/goods/index?commodityId=${item.commodityId}`,
})
}
</script> </script>

View File

@ -15,7 +15,7 @@ function quickBookingComponent(selectedData) {
/// 探索发现卡片组件 /// 探索发现卡片组件
function discoveryCradComponent() { function discoveryCradComponent() {
return request.get('/hotelBiz/mainScene//discoveryComponent', {}); return request.get('/hotelBiz/mainScene/discoveryComponent', {});
} }

View File

@ -1,98 +0,0 @@
## 已实现
1. 正常手势操作
2. 方法开关
3. 显示/隐藏比例自动吸附
4. 动画
5. 独立滑动
6. .....编不出来了 自行测试吧
## 使用说明
和正常组件使用方式一样
```js
// 1.引入
import exDrawer from '@/components/ex-drawer/ex-drawer.vue'
// 2.挂载
components:{
exDrawer
}
```
```html
// 3.使用
<ex-drawer ref='drawer' width="488">
<view class="drawer" slot="drawerContent">
<button @click="close" type="default">关闭</button>
drawer
</view>
<view class="container" slot="containerContent">
<button @click="open" type="default">打开</button>
<view class="" v-for="(item,index) in 100" :key="index">
{{item}}
</view>
</view>
</ex-drawer>
```
具体请查看demo
## props
1. width(string) // 抽屉宽度
2. 没了 主容器宽高和抽屉高度都可以被自动撑开 自行设置即可
## 插槽
1. drawerContent // 抽屉插槽
2. containerContent // 主容器插槽
## 方法
1. this.$refs.drawer.open() //打开
2. this.$refs.drawer.colse() //关闭
## 之后预计更新
1. 自定义进出吸附比例
2. 看需求....
```html
<template>
<view>
<ex-drawer ref='drawer' width="488">
<view class="drawer" slot="drawerContent">
<button @click="close" type="default">关闭</button>
drawer
</view>
<view class="container" slot="containerContent">
<button @click="open" type="default">打开</button>
<view class="" v-for="(item,index) in 100" :key="index">
{{item}}
</view>
</view>
</ex-drawer>
</view>
</template>
```
```js
<script>
import exDrawer from '@/components/ex-drawer/ex-drawer.vue'
export default {
data() {
return {
}
},
components:{
exDrawer
},
methods: {
open(){
this.$refs.drawer.open()
},
close(){
this.$refs.drawer.close()
}
}
}
</script>
```
```css
<style>
.drawer{
background-color: #ffffff;
height: 100vh;
}
.container{
background-color: #19BE6B;
width: 750rpx;
}
</style>
```

View File

@ -1,128 +0,0 @@
<template>
<!-- <view class="ex-drawer" @touchstart="containerStart" @touchend="containerEnd" @touchmove="containerMove"> -->
<!-- 移除手势 -->
<view class="ex-drawer">
<!-- 抽屉 -->
<view class="ex-drawer-warp" :class="{ move: move }" :style="{ width: `${width}rpx`, left: `-${width}rpx`, transform: `translate3d(${differential}px,0,0)`,backfaceVisibility:`hidden`, }">
<!-- 抽屉内容插槽 -->
<slot name="drawerContent"></slot>
</view>
<!-- 主容器 -->
<view class="ex-container-warp" :class="maskShow == true ? 'container prevent' : 'container'">
<!-- 遮罩 -->
<view v-show="maskShow" class="mask" @tap="close"></view>
<!-- 主容器内容插槽 -->
<slot name="containerContent"></slot>
</view>
</view>
</template>
<script>
export default {
data() {
return {
maskShow: false,
startX: 0,
startY: 0,
moveX: 0,
moveY: 0,
startExcursion: 0,
differential: 0,
isDirection: null,
iswidth: null,
move: false
};
},
props: {
width: {
type: String,
default: ''
}
},
methods: {
containerStart(e) {
this.isDirection = null;
this.move = false;
this.startX = e.changedTouches[0].clientX;
this.startY = e.changedTouches[0].clientY;
this.startExcursion = this.differential;
},
containerMove(e) {
this.moveX = e.changedTouches[0].clientX;
this.moveY = e.changedTouches[0].clientY;
let X = Math.abs(this.moveX - this.startX);
let Y = Math.abs(this.moveY - this.startY);
let differential = this.startExcursion + this.moveX - this.startX;
differential = Math.min(uni.upx2px(this.width), differential);
differential = Math.max(0, differential);
this.isDirection == null ? (this.isDirection = Y / X > Math.sqrt(3) / 3) : ``;
if (!this.isDirection) {
this.differential = differential;
if(this.differential == 0 ){
this.containerEnd()
}else{
this.maskShow = true
}
}
},
containerEnd() {
if (this.isDirection != null) {
if (!this.isDirection) {
this.iswidth = this.differential > (uni.upx2px(this.width) * 2) / 6;
this.differential > 0 && this.differential < uni.upx2px(this.width) ? (this.move = true) : ``;
}
this.differential = this.iswidth ? uni.upx2px(this.width) : 0;
this.differential == 0 ? this.maskShow = false : ``;
}
},
close(){
if(this.maskShow){
this.move = true
this.differential = 0;
if(this.differential == 0 ){
this.maskShow = false
this.iswidth=false
}
}
},
open(){
if(!this.maskShow){
this.move = true
this.differential = uni.upx2px(this.width);
if(this.differential == uni.upx2px(this.width) ){
this.maskShow = true
this.iswidth=true
}
}
}
}
};
</script>
<style>
.ex-drawer {
display: flex;
align-items: flex-start;
justify-content: flex-start;
}
.ex-drawer-warp {
position: fixed;
z-index: 1000;
touch-action: none;
}
.mask {
position: fixed;
left: 0rpx;
width: 100vw;
height: 100vh;
z-index: 999;
background-color:#000000;filter:Alpha(Opacity=60);opacity:0.3;
}
.prevent {
touch-action: none;
}
.move {
transition: transform 0.3s ease;
}
</style>

View File

@ -0,0 +1,13 @@
## 1.2.12021-11-22
- 修复 vue3中个别scss变量无法找到的问题
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-drawer](https://uniapp.dcloud.io/component/uniui/uni-drawer)
## 1.1.12021-07-30
- 优化 vue3下事件警告的问题
## 1.1.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-05-12
- 新增 组件示例地址
## 1.0.62021-02-04
- 调整为uni_modules目录规范

View File

@ -0,0 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
// this.$once('hook:beforeDestroy', () => {
// document.removeEventListener('keyup', listener)
// })
},
render: () => {}
}
// #endif

View File

@ -0,0 +1,183 @@
<template>
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer" @touchmove.stop.prevent="clear">
<view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close('mask')" />
<view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}" :style="{width:drawerWidth+'px'}">
<slot />
</view>
<!-- #ifdef H5 -->
<keypress @esc="close('mask')" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif
/**
* Drawer 抽屉
* @description 抽屉侧滑菜单
* @tutorial https://ext.dcloud.net.cn/plugin?id=26
* @property {Boolean} mask = [true | false] 是否显示遮罩
* @property {Boolean} maskClick = [true | false] 点击遮罩是否关闭
* @property {Boolean} mode = [left | right] Drawer 滑出位置
* @value left 从左侧滑出
* @value right 从右侧侧滑出
* @property {Number} width 抽屉的宽度 vue 页面生效
* @event {Function} close 组件关闭时触发事件
*/
export default {
name: 'UniDrawer',
components: {
// #ifdef H5
keypress
// #endif
},
emits:['change'],
props: {
/**
* 显示模式只在初始化生效
*/
mode: {
type: String,
default: ''
},
/**
* 蒙层显示状态
*/
mask: {
type: Boolean,
default: true
},
/**
* 遮罩是否可点击关闭
*/
maskClick:{
type: Boolean,
default: true
},
/**
* 抽屉宽度
*/
width: {
type: Number,
default: 220
}
},
data() {
return {
visibleSync: false,
showDrawer: false,
rightMode: false,
watchTimer: null,
drawerWidth: 220
}
},
created() {
// #ifndef APP-NVUE
this.drawerWidth = this.width
// #endif
this.rightMode = this.mode === 'right'
},
methods: {
clear(){},
close(type) {
// fixed by mehaotian
if((type === 'mask' && !this.maskClick) || !this.visibleSync) return
this._change('showDrawer', 'visibleSync', false)
},
open() {
// fixed by mehaotian
if(this.visibleSync) return
this._change('visibleSync', 'showDrawer', true)
},
_change(param1, param2, status) {
this[param1] = status
if (this.watchTimer) {
clearTimeout(this.watchTimer)
}
this.watchTimer = setTimeout(() => {
this[param2] = status
this.$emit('change',status)
}, status ? 50 : 300)
}
}
}
</script>
<style lang="scss" scoped>
$uni-mask: rgba($color: #000000, $alpha: 0.4) ;
//
$drawer-width: 220px;
.uni-drawer {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 999;
}
.uni-drawer__content {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
top: 0;
width: $drawer-width;
bottom: 0;
background-color: $uni-bg-color;
transition: transform 0.3s ease;
}
.uni-drawer--left {
left: 0;
/* #ifdef APP-NVUE */
transform: translateX(-$drawer-width);
/* #endif */
/* #ifndef APP-NVUE */
transform: translateX(-100%);
/* #endif */
}
.uni-drawer--right {
right: 0;
/* #ifdef APP-NVUE */
transform: translateX($drawer-width);
/* #endif */
/* #ifndef APP-NVUE */
transform: translateX(100%);
/* #endif */
}
.uni-drawer__content--visible {
transform: translateX(0px);
}
.uni-drawer__mask {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 0;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: $uni-mask;
transition: opacity 0.3s;
}
.uni-drawer__mask--visible {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 1;
}
</style>

View File

@ -0,0 +1,87 @@
{
"id": "uni-drawer",
"displayName": "uni-drawer 抽屉",
"version": "1.2.1",
"description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。",
"keywords": [
"uni-ui",
"uniui",
"drawer",
"抽屉",
"侧滑导航"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"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"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,10 @@
## Drawer 抽屉
> **组件名uni-drawer**
> 代码块: `uDrawer`
抽屉侧滑菜单。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-drawer)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -30,7 +30,7 @@ export default {
}, },
themeColor: { themeColor: {
type: String, type: String,
default: '#007AFF' default: '#00A6FF'
}, },
codeBgColor: { codeBgColor: {
type: String, type: String,
@ -200,51 +200,51 @@ export default {
`, `,
// //
h1: ` h1: `
margin:18px 0 10px 0; margin:12px 0 10px 0;
font-size: 24px; font-size: 22px;
color: ${themeColor}; color: ${themeColor};
`, `,
// //
h2: ` h2: `
margin:14px 0 10px 0; margin:10px 0 10px 0;
font-size: 20px; font-size: 20px;
color: ${themeColor}; color: ${themeColor};
`, `,
// //
h3: ` h3: `
margin:12x 0 8px 0; margin:8x 0 8px 0;
font-size: 18px; font-size: 18px;
color: ${themeColor}; color: ${themeColor};
`, `,
// //
h4: ` h4: `
margin:12px 0 8px 0; margin:6px 0 8px 0;
font-size: 16px; font-size: 16px;
color: ${themeColor}; color: ${themeColor};
`, `,
// //
h5: ` h5: `
margin:10px 0 8px 0; margin:6px 0 8px 0;
font-size: 16px; font-size: 16px;
color: ${themeColor}; color: ${themeColor};
`, `,
// //
h6: ` h6: `
margin:8px 0 8px 0; margin:6px 0 8px 0;
font-size: 16px; font-size: 16px;
color: ${themeColor} color: ${themeColor}
`, `,
// //
blockquote: ` blockquote: `
margin:15px 0; margin:12px 0;
font-size:15px; font-size:14px;
color: #777777; color: #777777;
border-left: 4px solid #dddddd; border-left: 4px solid #dddddd;
padding: 0 10px; padding: 0 10px;
`, `,
// //
ul: ` ul: `
margin: 10px 0; margin: 8px 0;
color: #555; color: #555;
`, `,
li: ` li: `
@ -272,14 +272,14 @@ export default {
border:none; border:none;
text-align:center; text-align:center;
background-image:linear-gradient(to right,rgba(248,57,41,0),${themeColor},rgba(248,57,41,0)); background-image:linear-gradient(to right,rgba(248,57,41,0),${themeColor},rgba(248,57,41,0));
margin:10px 0; margin:8px 0;
`, `,
// //
table: ` table: `
border-spacing:0; border-spacing:0;
overflow:auto; overflow:auto;
min-width:100%; min-width:100%;
margin:10px 0; margin:8px 0;
border-collapse: collapse; border-collapse: collapse;
`, `,
th: ` th: `