Showing
94 changed files
with
4761 additions
and
0 deletions
Too many changes to show.
To preserve performance only 94 of 94+ files are displayed.
.gitignore
0 → 100644
App.vue
0 → 100644
api/index.js
0 → 100644
| 1 | +import { request } from '../utils/request.js'; | ||
| 2 | + | ||
| 3 | +export const getDeviceList = () => { | ||
| 4 | + return request({ | ||
| 5 | + url: '/device/list', | ||
| 6 | + method: 'GET', | ||
| 7 | + }); | ||
| 8 | +}; | ||
| 9 | + | ||
| 10 | +// 登录 | ||
| 11 | +export const loginApi = (data) => { | ||
| 12 | + return request({ | ||
| 13 | + url: '/api/login', | ||
| 14 | + method: 'POST', | ||
| 15 | + data, | ||
| 16 | + }); | ||
| 17 | +}; | ||
| 18 | + | ||
| 19 | +// 获取课程列表 | ||
| 20 | +export const courseListApi = (data) => { | ||
| 21 | + return request({ | ||
| 22 | + url: '/api/course/get-list', | ||
| 23 | + method: 'GET', | ||
| 24 | + data, | ||
| 25 | + }); | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +// 获取选班数据 | ||
| 29 | +export const getSelectApi = (data) => { | ||
| 30 | + return request({ | ||
| 31 | + url: '/api/course/get-detail', | ||
| 32 | + method: 'POST', | ||
| 33 | + data, | ||
| 34 | + }); | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +// 获取我的孩子 | ||
| 38 | +export const myStudentsApi = (data) => { | ||
| 39 | + return request({ | ||
| 40 | + url: '/api/student/my-students', | ||
| 41 | + method: 'GET', | ||
| 42 | + data, | ||
| 43 | + }); | ||
| 44 | +}; | ||
| 45 | + | ||
| 46 | +// 添加我的孩子 | ||
| 47 | +export const addStudentsApi = (data) => { | ||
| 48 | + return request({ | ||
| 49 | + url: '/api/student/create', | ||
| 50 | + method: 'POST', | ||
| 51 | + data, | ||
| 52 | + }); | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +// 报名 | ||
| 56 | +export const signUpApi = (data) => { | ||
| 57 | + return request({ | ||
| 58 | + url: '/api/course/sign-up', | ||
| 59 | + method: 'POST', | ||
| 60 | + data, | ||
| 61 | + }); | ||
| 62 | +}; |
index.html
0 → 100644
| 1 | +<!DOCTYPE html> | ||
| 2 | +<html lang="zh-CN"> | ||
| 3 | + <head> | ||
| 4 | + <meta charset="UTF-8" /> | ||
| 5 | + <script> | ||
| 6 | + var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || | ||
| 7 | + CSS.supports('top: constant(a)')) | ||
| 8 | + document.write( | ||
| 9 | + '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + | ||
| 10 | + (coverSupport ? ', viewport-fit=cover' : '') + '" />') | ||
| 11 | + </script> | ||
| 12 | + <title></title> | ||
| 13 | + <!--preload-links--> | ||
| 14 | + <!--app-context--> | ||
| 15 | + </head> | ||
| 16 | + <body> | ||
| 17 | + <div id="app"><!--app-html--></div> | ||
| 18 | + <script type="module" src="/main.js"></script> | ||
| 19 | + </body> | ||
| 20 | +</html> |
main.js
0 → 100644
manifest.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name" : "learn-tiny", | ||
| 3 | + "appid" : "__UNI__F0A7B80", | ||
| 4 | + "description" : "", | ||
| 5 | + "versionName" : "1.0.0", | ||
| 6 | + "versionCode" : "100", | ||
| 7 | + "transformPx" : false, | ||
| 8 | + /* 5+App特有相关 */ | ||
| 9 | + "app-plus" : { | ||
| 10 | + "usingComponents" : true, | ||
| 11 | + "nvueStyleCompiler" : "uni-app", | ||
| 12 | + "compilerVersion" : 3, | ||
| 13 | + "splashscreen" : { | ||
| 14 | + "alwaysShowBeforeRender" : true, | ||
| 15 | + "waiting" : true, | ||
| 16 | + "autoclose" : true, | ||
| 17 | + "delay" : 0 | ||
| 18 | + }, | ||
| 19 | + /* 模块配置 */ | ||
| 20 | + "modules" : {}, | ||
| 21 | + /* 应用发布信息 */ | ||
| 22 | + "distribute" : { | ||
| 23 | + /* android打包配置 */ | ||
| 24 | + "android" : { | ||
| 25 | + "permissions" : [ | ||
| 26 | + "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", | ||
| 27 | + "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", | ||
| 28 | + "<uses-permission android:name=\"android.permission.VIBRATE\"/>", | ||
| 29 | + "<uses-permission android:name=\"android.permission.READ_LOGS\"/>", | ||
| 30 | + "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", | ||
| 31 | + "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", | ||
| 32 | + "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", | ||
| 33 | + "<uses-permission android:name=\"android.permission.CAMERA\"/>", | ||
| 34 | + "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", | ||
| 35 | + "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", | ||
| 36 | + "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", | ||
| 37 | + "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", | ||
| 38 | + "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", | ||
| 39 | + "<uses-feature android:name=\"android.hardware.camera\"/>", | ||
| 40 | + "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" | ||
| 41 | + ] | ||
| 42 | + }, | ||
| 43 | + /* ios打包配置 */ | ||
| 44 | + "ios" : {}, | ||
| 45 | + /* SDK配置 */ | ||
| 46 | + "sdkConfigs" : {} | ||
| 47 | + } | ||
| 48 | + }, | ||
| 49 | + /* 快应用特有相关 */ | ||
| 50 | + "quickapp" : {}, | ||
| 51 | + /* 小程序特有相关 */ | ||
| 52 | + "mp-weixin" : { | ||
| 53 | + "appid" : "wxa0a9919d4066da95", | ||
| 54 | + "setting" : { | ||
| 55 | + "urlCheck" : false, | ||
| 56 | + "minified" : true | ||
| 57 | + }, | ||
| 58 | + "usingComponents" : true | ||
| 59 | + }, | ||
| 60 | + "mp-alipay" : { | ||
| 61 | + "usingComponents" : true | ||
| 62 | + }, | ||
| 63 | + "mp-baidu" : { | ||
| 64 | + "usingComponents" : true | ||
| 65 | + }, | ||
| 66 | + "mp-toutiao" : { | ||
| 67 | + "usingComponents" : true | ||
| 68 | + }, | ||
| 69 | + "uniStatistics" : { | ||
| 70 | + "enable" : false | ||
| 71 | + }, | ||
| 72 | + "vueVersion" : "3" | ||
| 73 | +} |
pages.json
0 → 100644
| 1 | +{ | ||
| 2 | + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages | ||
| 3 | + { | ||
| 4 | + "path": "pages/index/index", | ||
| 5 | + "style": { | ||
| 6 | + "navigationBarTitleText": "", | ||
| 7 | + "navigationStyle": "custom" | ||
| 8 | + } | ||
| 9 | + }, | ||
| 10 | + { | ||
| 11 | + "path": "pages/my/my", | ||
| 12 | + "style": { | ||
| 13 | + "navigationBarTitleText": "我的" | ||
| 14 | + } | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + "path" : "pages/login/login", | ||
| 18 | + "style" : | ||
| 19 | + { | ||
| 20 | + "navigationBarTitleText" : "登录" | ||
| 21 | + } | ||
| 22 | + }, | ||
| 23 | + { | ||
| 24 | + "path": "pages/signUp/signUp", | ||
| 25 | + "style": { | ||
| 26 | + "navigationBarTitleText": "报名" | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + { | ||
| 30 | + "path": "pages/addStudent/addStudent", | ||
| 31 | + "style": { | ||
| 32 | + "navigationBarTitleText": "添加孩子" | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + ], | ||
| 36 | + "tabBar": { | ||
| 37 | + "color": "#7A7E83", | ||
| 38 | + "selectedColor": "#f96118", | ||
| 39 | + "list": [{ | ||
| 40 | + "pagePath": "pages/index/index", | ||
| 41 | + "iconPath": "static/tabBar/home.png", | ||
| 42 | + "selectedIconPath": "static/tabBar/homeAc.png", | ||
| 43 | + "text": "发现" | ||
| 44 | + }, { | ||
| 45 | + "pagePath": "pages/my/my", | ||
| 46 | + "iconPath": "static/tabBar/my.png", | ||
| 47 | + "selectedIconPath": "static/tabBar/myAc.png", | ||
| 48 | + "text": "家长" | ||
| 49 | + }] | ||
| 50 | + }, | ||
| 51 | + "globalStyle": { | ||
| 52 | + "navigationBarTextStyle": "black", | ||
| 53 | + "navigationBarBackgroundColor": "#eaecfb" | ||
| 54 | + }, | ||
| 55 | + "uniIdRouter": {} | ||
| 56 | +} |
pages/addStudent/addStudent.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <uv-form labelPosition="left" :model="state.studentInfo" :rules="state.rules" ref="formRef" class="form-box"> | ||
| 4 | + <uv-form-item prop="name"> | ||
| 5 | + <uv-input v-model="state.studentInfo.name" shape="circle" placeholder="请输入学生真实姓名"> | ||
| 6 | + </uv-input> | ||
| 7 | + </uv-form-item> | ||
| 8 | + <uv-form-item prop="sex"> | ||
| 9 | + <view style="display: flex;justify-content: space-around;width: 100%;"> | ||
| 10 | + <view @click="state.studentInfo.sex = 0" class="select-item" :style="state.studentInfo.sex === 0 ? 'border-color:#6b75f6;' : ''"> | ||
| 11 | + <uv-icon name="man" color="#7175f0" size="16" style="margin-right: 10rpx;"></uv-icon>男 | ||
| 12 | + </view> | ||
| 13 | + <view @click="state.studentInfo.sex = 1" class="select-item" :style="state.studentInfo.sex === 1 ? 'border-color:#6b75f6;' : ''"> | ||
| 14 | + <uv-icon name="woman" color="#ff5d5c" size="16" style="margin-right: 10rpx;"></uv-icon>女 | ||
| 15 | + </view> | ||
| 16 | + <view @click="state.studentInfo.sex = 2" class="select-item" :style="state.studentInfo.sex === 2 ? 'border-color:#6b75f6;' : ''"> | ||
| 17 | + <uv-icon name="lock" color="#7175f0" size="16" style="margin-right: 10rpx;"></uv-icon>保密 | ||
| 18 | + </view> | ||
| 19 | + </view> | ||
| 20 | + </uv-form-item> | ||
| 21 | + <uv-form-item prop="city"> | ||
| 22 | + <uv-input v-model="state.studentInfo.city" shape="circle" placeholder="请输入学生所在城市" /> | ||
| 23 | + </uv-form-item> | ||
| 24 | + <uv-form-item prop="school"> | ||
| 25 | + <uv-input v-model="state.studentInfo.school" shape="circle" placeholder="请输入学生在读学校" /> | ||
| 26 | + </uv-form-item> | ||
| 27 | + <uv-form-item prop="grade"> | ||
| 28 | + <uv-input v-model="state.studentInfo.grade" shape="circle" placeholder="请输入学生在读年级" /> | ||
| 29 | + </uv-form-item> | ||
| 30 | + <uv-form-item> | ||
| 31 | + <view @click="submit" | ||
| 32 | + style="width: 100%;background-color: #7175f0;color: #fff;text-align: center;padding: 20rpx 0;border-radius: 9999rpx;"> | ||
| 33 | + 确认添加 | ||
| 34 | + </view> | ||
| 35 | + </uv-form-item> | ||
| 36 | + </uv-form> | ||
| 37 | + </view> | ||
| 38 | +</template> | ||
| 39 | + | ||
| 40 | +<script setup> | ||
| 41 | + import { | ||
| 42 | + reactive, | ||
| 43 | + ref | ||
| 44 | + } from "vue" | ||
| 45 | + import { addStudentsApi } from "@/api/index.js" | ||
| 46 | + | ||
| 47 | + const formRef = ref(null) | ||
| 48 | + | ||
| 49 | + const state = reactive({ | ||
| 50 | + studentInfo: { | ||
| 51 | + name: "", | ||
| 52 | + sex: "", | ||
| 53 | + city: "", | ||
| 54 | + school: "", | ||
| 55 | + grade: "" | ||
| 56 | + }, | ||
| 57 | + rules: { | ||
| 58 | + 'name': { | ||
| 59 | + type: 'string', | ||
| 60 | + required: true, | ||
| 61 | + message: '请输入学生真实姓名', | ||
| 62 | + trigger: ['blur', 'change'] | ||
| 63 | + }, | ||
| 64 | + 'sex': { | ||
| 65 | + type: 'number', | ||
| 66 | + required: true, | ||
| 67 | + message: '请选择性别', | ||
| 68 | + trigger: ['blur', 'change'] | ||
| 69 | + }, | ||
| 70 | + 'city': { | ||
| 71 | + type: 'string', | ||
| 72 | + required: true, | ||
| 73 | + message: '请输入学生所在城市', | ||
| 74 | + trigger: ['blur', 'change'] | ||
| 75 | + }, | ||
| 76 | + 'school': { | ||
| 77 | + type: 'string', | ||
| 78 | + required: true, | ||
| 79 | + message: '请输入学生在读学校', | ||
| 80 | + trigger: ['blur', 'change'] | ||
| 81 | + }, | ||
| 82 | + 'grade': { | ||
| 83 | + type: 'string', | ||
| 84 | + required: true, | ||
| 85 | + message: '请输入学生在读年级', | ||
| 86 | + trigger: ['blur', 'change'] | ||
| 87 | + }, | ||
| 88 | + } | ||
| 89 | + }) | ||
| 90 | + | ||
| 91 | + const submit = async () => { | ||
| 92 | + try { | ||
| 93 | + await formRef.value.validate() | ||
| 94 | + | ||
| 95 | + const res = await addStudentsApi(state.studentInfo) | ||
| 96 | + uni.showToast({ | ||
| 97 | + icon: 'success', | ||
| 98 | + title: '添加成功' | ||
| 99 | + }) | ||
| 100 | + formRef.value.resetFields() | ||
| 101 | + uni.navigateBack() | ||
| 102 | + } catch {} | ||
| 103 | + } | ||
| 104 | +</script> | ||
| 105 | + | ||
| 106 | +<style lang="scss" scoped> | ||
| 107 | + .container { | ||
| 108 | + background: linear-gradient(135deg, #eaecfb 10%, #f6f7fb 90%); | ||
| 109 | + background-color: red; | ||
| 110 | + height: calc(100vh - var(--tab-bar-height)); | ||
| 111 | + overflow-y: auto; | ||
| 112 | + padding: 0 24rpx; | ||
| 113 | + font-size: 28rpx; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + .form-box { | ||
| 117 | + margin-top: 80rpx; | ||
| 118 | + background-color: #fff; | ||
| 119 | + padding: 20rpx; | ||
| 120 | + border-radius: 40rpx; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + .select-item { | ||
| 124 | + background-color: #e9ecfc; | ||
| 125 | + width: 28%; | ||
| 126 | + display: flex; | ||
| 127 | + justify-content: center; | ||
| 128 | + align-items: center; | ||
| 129 | + padding: 10rpx 0; | ||
| 130 | + border-radius: 9999rpx; | ||
| 131 | + border: 3rpx solid #e8ecfd; | ||
| 132 | + } | ||
| 133 | +</style> |
pages/index/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <uv-navbar leftIcon="" placeholder bgColor="rgba(255, 255, 255, 0)"> | ||
| 4 | + <template v-slot:left> | ||
| 5 | + <view class="uv-nav-slot"> | ||
| 6 | + XXXX | ||
| 7 | + </view> | ||
| 8 | + </template> | ||
| 9 | + </uv-navbar> | ||
| 10 | + | ||
| 11 | + <view class="content-box"> | ||
| 12 | + <view style="display: grid;grid-template-columns: 47.5% 47.5%;gap: 5%;"> | ||
| 13 | + <view @click="showGradesPop" class="select-item"> | ||
| 14 | + {{ state.grade }}<uv-icon name="arrow-down-fill" color="#7175f0" size="20" | ||
| 15 | + style="margin-left: 6rpx;"></uv-icon> | ||
| 16 | + </view> | ||
| 17 | + <view @click="showAccountsPop" class="select-item"> | ||
| 18 | + {{ state.accounts }}<uv-icon name="arrow-down-fill" color="#7175f0" size="20" style="margin-left: 6rpx;"></uv-icon> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + | ||
| 22 | + <view class="course-list"> | ||
| 23 | + <view v-for="item in state.courses" class="course-box"> | ||
| 24 | + <image :src="item.img" style="width: 160rpx;height: 160rpx;border-radius: 20rpx;"></image> | ||
| 25 | + <view style="flex: 1;display: flex;"> | ||
| 26 | + <view style="flex: 1;padding: 0 20rpx;display: flex;flex-direction: column;justify-content: space-between;"> | ||
| 27 | + <view style="font-size: 30rpx;">{{ item.name }} - {{ item.subject }}</view> | ||
| 28 | + <view style="color: #ff3838;font-weight: 600;">¥{{ item.price }}</view> | ||
| 29 | + </view> | ||
| 30 | + <view style="width: 160rpx;display: flex;align-items: center;justify-content: flex-end;"> | ||
| 31 | + <view @click="gotoSignUp(item.id)" style="width: 100%;;background-color: #f57c28;color: #fff;text-align: center;padding: 10rpx 0;border-radius: 9999rpx;"> | ||
| 32 | + 去报名 | ||
| 33 | + </view> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | + </view> | ||
| 37 | + </view> | ||
| 38 | + </view> | ||
| 39 | + | ||
| 40 | + <!-- 年级弹窗 --> | ||
| 41 | + <uv-popup ref="gradesRef" safeAreaInsetBottom closeable :round="20"> | ||
| 42 | + <view class="pop-box"> | ||
| 43 | + <view class="content-pop"> | ||
| 44 | + <view @click="selectGrade('全部年级')" class="pop-inner-item" style="margin: 20rpx 0;" :style="state.grade === '全部年级' ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''"> | ||
| 45 | + 全部年级 | ||
| 46 | + </view> | ||
| 47 | + <view v-for="item in state.gradOptions" style="margin-bottom: 30rpx;"> | ||
| 48 | + <view class="pop-title"> | ||
| 49 | + {{ item.title }} | ||
| 50 | + </view> | ||
| 51 | + <view class="pop-inner"> | ||
| 52 | + <view v-for="item1 in item.content" @click="selectGrade(item1)" class="pop-inner-item" | ||
| 53 | + :style="state.grade === item1 ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''"> | ||
| 54 | + {{ item1 }} | ||
| 55 | + </view> | ||
| 56 | + </view> | ||
| 57 | + </view> | ||
| 58 | + </view> | ||
| 59 | + </view> | ||
| 60 | + </uv-popup> | ||
| 61 | + | ||
| 62 | + <!-- 科目弹窗 --> | ||
| 63 | + <uv-popup ref="accountsRef" safeAreaInsetBottom closeable :round="20"> | ||
| 64 | + <view class="pop-box"> | ||
| 65 | + <view class="content-pop"> | ||
| 66 | + <view @click="selectaccounts('全部科目')" class="pop-inner-item" style="margin: 20rpx 0;" :style="state.accounts === '全部科目' ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''"> | ||
| 67 | + 全部科目 | ||
| 68 | + </view> | ||
| 69 | + <view class="pop-inner"> | ||
| 70 | + <view v-for="item1 in state.accountsOptions" @click="selectaccounts(item1)" class="pop-inner-item" | ||
| 71 | + :style="state.accounts === item1 ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''"> | ||
| 72 | + {{ item1 }} | ||
| 73 | + </view> | ||
| 74 | + </view> | ||
| 75 | + </view> | ||
| 76 | + </view> | ||
| 77 | + </uv-popup> | ||
| 78 | + </view> | ||
| 79 | +</template> | ||
| 80 | + | ||
| 81 | +<script setup> | ||
| 82 | + import { | ||
| 83 | + reactive, | ||
| 84 | + ref, | ||
| 85 | + onMounted | ||
| 86 | + } from 'vue'; | ||
| 87 | + import { courseListApi } from "@/api/index.js" | ||
| 88 | + | ||
| 89 | + const gradesRef = ref(null) | ||
| 90 | + const accountsRef = ref(null) | ||
| 91 | + | ||
| 92 | + const state = reactive({ | ||
| 93 | + grade: "全部年级", | ||
| 94 | + accounts: "全部科目", | ||
| 95 | + courses: [], | ||
| 96 | + subject: [], | ||
| 97 | + gradOptions: [{ | ||
| 98 | + title: "小学", | ||
| 99 | + content: ["一年级", "二年级", "三年级", "四年级", "五年级", "六年级"] | ||
| 100 | + }, | ||
| 101 | + { | ||
| 102 | + title: "初中", | ||
| 103 | + content: ["初一", "初二", "初三"] | ||
| 104 | + }, | ||
| 105 | + { | ||
| 106 | + title: "高中", | ||
| 107 | + content: ["高一", "高二", "高三"] | ||
| 108 | + } | ||
| 109 | + ], | ||
| 110 | + accountsOptions: ["语文", "数学", "英语", "物理", "化学"] | ||
| 111 | + }) | ||
| 112 | + | ||
| 113 | + onMounted(() => { | ||
| 114 | + getCourseList() | ||
| 115 | + }) | ||
| 116 | + | ||
| 117 | + const gotoSignUp = id => { | ||
| 118 | + uni.navigateTo({ | ||
| 119 | + url: `/pages/signUp/signUp?id=${id}` | ||
| 120 | + }) | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + const getCourseList = async () => { | ||
| 124 | + try { | ||
| 125 | + const { data } = await courseListApi({ | ||
| 126 | + grade: state.grade === "全部年级" ? "" : state.grade, | ||
| 127 | + subject: state.accounts === "全部科目" ? "" : state.accounts | ||
| 128 | + }) | ||
| 129 | + state.courses = data.courses | ||
| 130 | + } catch {} | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + const showGradesPop = () => { | ||
| 134 | + gradesRef.value.open('bottom') | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + const showAccountsPop = () => { | ||
| 138 | + accountsRef.value.open('bottom') | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + const selectGrade = item => { | ||
| 142 | + state.grade = item | ||
| 143 | + gradesRef.value.close() | ||
| 144 | + getCourseList() | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + const selectaccounts = item => { | ||
| 148 | + state.accounts = item | ||
| 149 | + accountsRef.value.close() | ||
| 150 | + getCourseList() | ||
| 151 | + } | ||
| 152 | +</script> | ||
| 153 | + | ||
| 154 | +<style lang="scss" scoped> | ||
| 155 | + .container { | ||
| 156 | + background: linear-gradient(135deg, #d4d6fe 10%, #f6f7fb 90%); | ||
| 157 | + background-color: red; | ||
| 158 | + height: calc(100vh - var(--tab-bar-height)); | ||
| 159 | + display: flex; | ||
| 160 | + flex-direction: column; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + .content-box { | ||
| 164 | + flex: 1; | ||
| 165 | + overflow-y: auto; | ||
| 166 | + padding: 0 24rpx; | ||
| 167 | + display: flex; | ||
| 168 | + flex-direction: column; | ||
| 169 | + | ||
| 170 | + .course-list { | ||
| 171 | + margin-top: 20rpx; | ||
| 172 | + flex: 1; | ||
| 173 | + .course-box { | ||
| 174 | + display: flex; | ||
| 175 | + justify-content: space-between; | ||
| 176 | + margin-bottom: 30rpx; | ||
| 177 | + background-color: #fff; | ||
| 178 | + padding: 20rpx; | ||
| 179 | + border-radius: 20rpx; | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + .select-item { | ||
| 185 | + flex: 1; | ||
| 186 | + display: flex; | ||
| 187 | + align-items: center; | ||
| 188 | + justify-content: center; | ||
| 189 | + background-color: #fff; | ||
| 190 | + padding: 16rpx 0; | ||
| 191 | + border-radius: 9999rpx; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + .pop-box { | ||
| 195 | + padding: 70rpx 20rpx; | ||
| 196 | + padding-bottom: calc(var(--tab-bar-height) + 20rpx); | ||
| 197 | + | ||
| 198 | + .content-pop { | ||
| 199 | + max-height: 40vh; | ||
| 200 | + min-height: 200rpx; | ||
| 201 | + overflow-y: auto; | ||
| 202 | + | ||
| 203 | + scrollbar-width: none; | ||
| 204 | + -ms-overflow-style: none; | ||
| 205 | + | ||
| 206 | + &::-webkit-scrollbar { | ||
| 207 | + display: none; | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + .pop-title { | ||
| 213 | + margin-bottom: 20rpx; | ||
| 214 | + position: relative; | ||
| 215 | + padding-left: 12rpx; | ||
| 216 | + | ||
| 217 | + &:before { | ||
| 218 | + content: ""; | ||
| 219 | + width: 6rpx; | ||
| 220 | + height: 28rpx; | ||
| 221 | + border-radius: 3rpx; | ||
| 222 | + background-color: #ffb50f; | ||
| 223 | + position: absolute; | ||
| 224 | + top: 50%; | ||
| 225 | + left: 0; | ||
| 226 | + transform: translateY(-50%); | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + .pop-inner { | ||
| 231 | + display: grid; | ||
| 232 | + grid-template-columns: repeat(4, 1fr); | ||
| 233 | + gap: (20rpx); | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + .pop-inner-item { | ||
| 237 | + font-size: 28rpx; | ||
| 238 | + border: 2rpx solid #ccc; | ||
| 239 | + text-align: center; | ||
| 240 | + padding: 10rpx 0; | ||
| 241 | + border-radius: 9999rpx; | ||
| 242 | + } | ||
| 243 | +</style> |
pages/login/login.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <view class="input-box"> | ||
| 4 | + <uv-form labelPosition="left" :model="state.userInfo" :rules="state.rules" labelWidth="60" ref="formRef" | ||
| 5 | + :labelStyle="{ fontSize: '28rpx' }"> | ||
| 6 | + <view style="margin-bottom: 60rpx;"> | ||
| 7 | + 欢迎登录XXXXXXXX! | ||
| 8 | + </view> | ||
| 9 | + <uv-form-item label="姓名" prop="name" borderBottom> | ||
| 10 | + <uv-input v-model="state.userInfo.name" placeholder="请输入姓名" border="none"> | ||
| 11 | + </uv-input> | ||
| 12 | + </uv-form-item> | ||
| 13 | + <uv-form-item label="手机号" prop="phonenumber" borderBottom> | ||
| 14 | + <uv-input v-model="state.userInfo.phonenumber" placeholder="请输入手机号" border="none"></uv-input> | ||
| 15 | + </uv-form-item> | ||
| 16 | + <view @click="loginHandler" class="login-btn"> | ||
| 17 | + 登 录 | ||
| 18 | + </view> | ||
| 19 | + </uv-form> | ||
| 20 | + </view> | ||
| 21 | + </view> | ||
| 22 | +</template> | ||
| 23 | + | ||
| 24 | +<script setup> | ||
| 25 | + import { | ||
| 26 | + reactive, | ||
| 27 | + ref | ||
| 28 | + } from 'vue'; | ||
| 29 | + import { | ||
| 30 | + loginApi | ||
| 31 | + } from "@/api/index.js" | ||
| 32 | + | ||
| 33 | + const formRef = ref(null) | ||
| 34 | + | ||
| 35 | + const state = reactive({ | ||
| 36 | + userInfo: { | ||
| 37 | + name: "", | ||
| 38 | + phonenumber: "" | ||
| 39 | + }, | ||
| 40 | + rules: { | ||
| 41 | + 'name': { | ||
| 42 | + type: 'string', | ||
| 43 | + required: true, | ||
| 44 | + message: '请输入姓名', | ||
| 45 | + trigger: ['blur', 'change'] | ||
| 46 | + }, | ||
| 47 | + 'phonenumber': [{ | ||
| 48 | + type: 'string', | ||
| 49 | + required: true, | ||
| 50 | + message: '请输入手机号', | ||
| 51 | + trigger: ['blur', 'change'] | ||
| 52 | + }, { | ||
| 53 | + validator: (rule, value, callback) => { | ||
| 54 | + const mobileRegexLoose = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/ | ||
| 55 | + return mobileRegexLoose.test(value); | ||
| 56 | + }, | ||
| 57 | + message: '手机号码不正确', | ||
| 58 | + trigger: ['blur'], | ||
| 59 | + }], | ||
| 60 | + } | ||
| 61 | + }) | ||
| 62 | + | ||
| 63 | + const loginHandler = async () => { | ||
| 64 | + try { | ||
| 65 | + await formRef.value.validate() | ||
| 66 | + | ||
| 67 | + const { | ||
| 68 | + token | ||
| 69 | + } = await loginApi(state.userInfo) | ||
| 70 | + uni.showToast({ | ||
| 71 | + icon: 'success', | ||
| 72 | + title: '登录成功' | ||
| 73 | + }) | ||
| 74 | + uni.setStorageSync('token', token) | ||
| 75 | + uni.navigateBack() | ||
| 76 | + } catch {} | ||
| 77 | + } | ||
| 78 | +</script> | ||
| 79 | + | ||
| 80 | +<style lang="scss" scoped> | ||
| 81 | + .container { | ||
| 82 | + background: linear-gradient(135deg, #eaecfb 10%, #f6f7fb 90%); | ||
| 83 | + background-color: red; | ||
| 84 | + height: 100vh; | ||
| 85 | + overflow-y: auto; | ||
| 86 | + padding: 0 28rpx; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + .input-box { | ||
| 90 | + position: relative; | ||
| 91 | + margin-top: 120rpx; | ||
| 92 | + padding: 48rpx; | ||
| 93 | + padding-top: 80rpx; | ||
| 94 | + background-color: #fff; | ||
| 95 | + border-radius: 12rpx; | ||
| 96 | + box-shadow: 0 0 20rpx #eee; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + ::v-deep .uv-line { | ||
| 100 | + border-bottom-style: dashed !important; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + .login-btn { | ||
| 104 | + margin-top: 80rpx; | ||
| 105 | + background-color: #8386ef; | ||
| 106 | + color: #fff; | ||
| 107 | + text-align: center; | ||
| 108 | + padding: 16rpx 0; | ||
| 109 | + border-radius: 20rpx; | ||
| 110 | + } | ||
| 111 | +</style> |
pages/my/my.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <!-- 自定义标题栏 --> | ||
| 4 | + <uv-navbar leftIcon="" placeholder bgColor="/static/topBg.png"> | ||
| 5 | + <template v-slot:center> | ||
| 6 | + <view class="uv-nav-slot"> | ||
| 7 | + <image src="/static/my/myTitle.png" mode="heightFix" style="height: 44rpx;"></image> | ||
| 8 | + </view> | ||
| 9 | + </template> | ||
| 10 | + </uv-navbar> | ||
| 11 | + | ||
| 12 | + <view class="content-box"> | ||
| 13 | + <div class="content-padding"> | ||
| 14 | + <!-- 用户信息 --> | ||
| 15 | + <view class="user-info"> | ||
| 16 | + <view class="center-avatar"> | ||
| 17 | + <view class="center-inner"> | ||
| 18 | + <image src="/static/my/avatar.png" style="width: 100%;height: 100%;"></image> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + <view class="loginTo-btn"> | ||
| 22 | + 登录/注册 | ||
| 23 | + </view> | ||
| 24 | + </view> | ||
| 25 | + | ||
| 26 | + <view class="nav-list"> | ||
| 27 | + <view class="nav-item"> | ||
| 28 | + <view style="display: flex;align-items: center;"> | ||
| 29 | + <uv-icon name="/static/my/student.png" :size="22"></uv-icon> | ||
| 30 | + <view style="margin-left: 26rpx;color: #6a6a6a;">绑定学生</view> | ||
| 31 | + </view> | ||
| 32 | + <uv-icon name="arrow-right" :size="16"></uv-icon> | ||
| 33 | + </view> | ||
| 34 | + <view class="nav-item"> | ||
| 35 | + <view style="display: flex;align-items: center;"> | ||
| 36 | + <uv-icon name="/static/my/print.png" :size="24"></uv-icon> | ||
| 37 | + <view style="margin-left: 26rpx;color: #6a6a6a;">打印记录</view> | ||
| 38 | + </view> | ||
| 39 | + <uv-icon name="arrow-right" :size="16"></uv-icon> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | + </div> | ||
| 43 | + </view> | ||
| 44 | + </view> | ||
| 45 | +</template> | ||
| 46 | + | ||
| 47 | +<script setup> | ||
| 48 | + | ||
| 49 | +</script> | ||
| 50 | + | ||
| 51 | +<style lang="scss" scoped> | ||
| 52 | + .container { | ||
| 53 | + background-color: #f7f8fa; | ||
| 54 | + height: 100vh; | ||
| 55 | + overflow-y: auto; | ||
| 56 | + display: flex; | ||
| 57 | + flex-direction: column; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + .content-box { | ||
| 61 | + flex: 1; | ||
| 62 | + overflow-y: auto; | ||
| 63 | + background-image: url('~@/static/bottomBg.png'); | ||
| 64 | + background-repeat: no-repeat; | ||
| 65 | + background-size: 100% auto; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + .content-padding { | ||
| 69 | + padding: 0 28rpx; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + .user-info { | ||
| 73 | + width: 100%; | ||
| 74 | + height: 440rpx; | ||
| 75 | + background-image: url('~@/static/my/information.png'); | ||
| 76 | + background-repeat: no-repeat; | ||
| 77 | + background-size: 100% auto; | ||
| 78 | + background-position: bottom; | ||
| 79 | + background-color: transparent; | ||
| 80 | + position: relative; | ||
| 81 | + | ||
| 82 | + .center-avatar { | ||
| 83 | + position: absolute; | ||
| 84 | + top: 20rpx; | ||
| 85 | + left: 50%; | ||
| 86 | + transform: translateX(-50%); | ||
| 87 | + width: 34%; | ||
| 88 | + aspect-ratio: 1/1; | ||
| 89 | + background-color: #fff; | ||
| 90 | + border-radius: 50%; | ||
| 91 | + | ||
| 92 | + .center-inner { | ||
| 93 | + width: 100%; | ||
| 94 | + height: 100%; | ||
| 95 | + border-radius: 50%; | ||
| 96 | + overflow: hidden; | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + .loginTo-btn { | ||
| 101 | + position: absolute; | ||
| 102 | + left: 50%; | ||
| 103 | + bottom: 60rpx; | ||
| 104 | + transform: translateX(-50%); | ||
| 105 | + color: #fff; | ||
| 106 | + font-size: 44rpx; | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + .nav-list { | ||
| 111 | + background-color: #fff; | ||
| 112 | + border-radius: 12rpx; | ||
| 113 | + box-shadow: 0 0 20rpx #eee; | ||
| 114 | + padding: 10rpx 20rpx; | ||
| 115 | + box-sizing: border-box; | ||
| 116 | + margin-top: 40rpx; | ||
| 117 | + | ||
| 118 | + .nav-item { | ||
| 119 | + display: flex; | ||
| 120 | + justify-content: space-between; | ||
| 121 | + border-bottom: 2rpx dashed #d8d8d8; | ||
| 122 | + padding: 30rpx 0; | ||
| 123 | + | ||
| 124 | + &:last-child { | ||
| 125 | + border: none; | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | +</style> |
pages/signUp/signUp.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <view class="student-box"> | ||
| 4 | + <view class="title"> | ||
| 5 | + 报名学员 | ||
| 6 | + </view> | ||
| 7 | + <view style="display: flex;align-items: center;"> | ||
| 8 | + <template v-if="state.students.length"> | ||
| 9 | + <view @click="studentsRef.open('bottom')">{{ state.students[state.activeIndex].name }}</view> | ||
| 10 | + <uv-icon @click="studentsRef.open('bottom')" name="arrow-down" color="#7175f0" size="14" | ||
| 11 | + style="margin-left: 10rpx;"></uv-icon> | ||
| 12 | + </template> | ||
| 13 | + <template v-else> | ||
| 14 | + <view @click="addStudents" style="color: #7175f0;">点击添加</view> | ||
| 15 | + <uv-icon @click="addStudents" name="arrow-right" color="#7175f0" size="14" | ||
| 16 | + style="margin-left: 10rpx;"></uv-icon> | ||
| 17 | + </template> | ||
| 18 | + </view> | ||
| 19 | + </view> | ||
| 20 | + | ||
| 21 | + <view class="student-box" style="margin-top: 30rpx;display: block;"> | ||
| 22 | + <view class="title" style="margin-bottom: 30rpx;"> | ||
| 23 | + 选择地区 | ||
| 24 | + </view> | ||
| 25 | + <view style="display: grid;grid-template-columns: repeat(3, 1fr);gap: 20rpx;"> | ||
| 26 | + <view v-for="item in state.selectData.schoolArr" @click="select1(item)" | ||
| 27 | + :style="state.schoolName === item.text ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''" | ||
| 28 | + :class="item.status === '可选' ? 'select-item' : 'select-item no-select'"> | ||
| 29 | + {{ item.text }} | ||
| 30 | + </view> | ||
| 31 | + </view> | ||
| 32 | + </view> | ||
| 33 | + | ||
| 34 | + <view class="student-box" style="margin-top: 30rpx;display: block;"> | ||
| 35 | + <view class="title" style="margin-bottom: 30rpx;"> | ||
| 36 | + 选择班型 | ||
| 37 | + </view> | ||
| 38 | + <view style="display: grid;grid-template-columns: repeat(3, 1fr);gap: 20rpx;"> | ||
| 39 | + <view v-for="item in state.selectData.classArr" @click="select2(item)" | ||
| 40 | + :style="state.className === item.text ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''" | ||
| 41 | + :class="item.status === '可选' ? 'select-item' : 'select-item no-select'"> | ||
| 42 | + {{ item.text }} | ||
| 43 | + </view> | ||
| 44 | + </view> | ||
| 45 | + </view> | ||
| 46 | + | ||
| 47 | + <view class="student-box" style="margin-top: 30rpx;display: block;"> | ||
| 48 | + <view class="title" style="margin-bottom: 30rpx;"> | ||
| 49 | + 选择老师 | ||
| 50 | + </view> | ||
| 51 | + <view style="display: grid;grid-template-columns: repeat(3, 1fr);gap: 20rpx;"> | ||
| 52 | + <view v-for="item in state.selectData.teacherArr" @click="select3(item)" | ||
| 53 | + :style="state.teacherName === item.text ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''" | ||
| 54 | + :class="item.status === '可选' ? 'select-item' : 'select-item no-select'"> | ||
| 55 | + {{ item.text }} | ||
| 56 | + </view> | ||
| 57 | + </view> | ||
| 58 | + </view> | ||
| 59 | + | ||
| 60 | + <view class="student-box" style="margin-top: 30rpx;display: block;"> | ||
| 61 | + <view class="title" style="margin-bottom: 30rpx;"> | ||
| 62 | + 选择时段 | ||
| 63 | + </view> | ||
| 64 | + <view> | ||
| 65 | + <!-- body --> | ||
| 66 | + <view class="body-box"> | ||
| 67 | + <view class="body-row"> | ||
| 68 | + <view class="cell" style="background-color: #c4d0fc;height: 70rpx;"> | ||
| 69 | + 日期 | ||
| 70 | + </view> | ||
| 71 | + <view v-for="item in state.selectData?.tableData?.x" class="cell" | ||
| 72 | + style="background-color: #c4d0fc;height: 70rpx;"> | ||
| 73 | + {{ item }} | ||
| 74 | + </view> | ||
| 75 | + </view> | ||
| 76 | + <!-- 行 --> | ||
| 77 | + <view v-for="item in state.selectData?.tableData?.y" class="body-row"> | ||
| 78 | + <!-- 列 --> | ||
| 79 | + <view class="cell"> | ||
| 80 | + {{ item }} | ||
| 81 | + </view> | ||
| 82 | + <view v-for="item1 in state.selectData?.tableData?.x" @click="selectTable(item, item1)" | ||
| 83 | + :class="(!!state.courseDate && !!state.courseTime && state.courseDate === item1 && state.courseTime === item) ? 'cell select-one' : 'cell'"> | ||
| 84 | + {{ filterCell(item, item1) }} | ||
| 85 | + </view> | ||
| 86 | + </view> | ||
| 87 | + </view> | ||
| 88 | + </view> | ||
| 89 | + </view> | ||
| 90 | + | ||
| 91 | + <view @click="resetSelect" style="font-size: 24rpx;color: #7175f0;display: flex;justify-content: center;align-items: center;margin: 40rpx 0;"> | ||
| 92 | + <uv-icon name="reload" color="#7175f0" size="14" style="margin-right: 10rpx;"></uv-icon>重置所有选择 | ||
| 93 | + </view> | ||
| 94 | + | ||
| 95 | + <view @click="signUpHandler" style="background-color: #7175f0;color: #fff;text-align: center;border-radius: 9999rpx;padding: 16rpx 0;margin-bottom: 70rpx;"> | ||
| 96 | + 立即报名 | ||
| 97 | + </view> | ||
| 98 | + | ||
| 99 | + <!-- 选择学员弹窗 --> | ||
| 100 | + <uv-popup ref="studentsRef" safeAreaInsetBottom closeable :round="20"> | ||
| 101 | + <view class="pop-box"> | ||
| 102 | + <view class="content-pop"> | ||
| 103 | + <view v-for="(item, index) in state.students" @click="state.activeIndex = index" | ||
| 104 | + class="pop-inner-item" | ||
| 105 | + :style="state.activeIndex === index ? 'border-color:#7175f0;color:#7175f0;background-color:#f6f7ff;' : ''"> | ||
| 106 | + {{ item.name }}({{ item.grade }}) | ||
| 107 | + </view> | ||
| 108 | + <view @click="addStudents" class="pop-inner-item" | ||
| 109 | + style="display: flex;align-items: center;justify-content: center;"> | ||
| 110 | + <uv-icon name="plus" size="14" style="margin-right: 10rpx;"></uv-icon> 新增学员 | ||
| 111 | + </view> | ||
| 112 | + </view> | ||
| 113 | + </view> | ||
| 114 | + </uv-popup> | ||
| 115 | + </view> | ||
| 116 | +</template> | ||
| 117 | + | ||
| 118 | +<script setup> | ||
| 119 | + import { | ||
| 120 | + onMounted, | ||
| 121 | + reactive, | ||
| 122 | + ref | ||
| 123 | + } from "vue" | ||
| 124 | + import { | ||
| 125 | + myStudentsApi, | ||
| 126 | + getSelectApi, | ||
| 127 | + signUpApi | ||
| 128 | + } from "@/api/index.js" | ||
| 129 | + import { | ||
| 130 | + onLoad | ||
| 131 | + } from '@dcloudio/uni-app' | ||
| 132 | + | ||
| 133 | + const studentsRef = ref(null) | ||
| 134 | + | ||
| 135 | + const state = reactive({ | ||
| 136 | + students: [], | ||
| 137 | + activeIndex: 0, | ||
| 138 | + courseId: null, | ||
| 139 | + selectData: { | ||
| 140 | + classArr: [], | ||
| 141 | + schoolArr: [], | ||
| 142 | + teacherArr: [], | ||
| 143 | + tableData: {} | ||
| 144 | + }, | ||
| 145 | + schoolName: "", | ||
| 146 | + className: "", | ||
| 147 | + teacherName: "", | ||
| 148 | + courseDate: "", // X | ||
| 149 | + courseTime: "" // Y | ||
| 150 | + }) | ||
| 151 | + | ||
| 152 | + onLoad((option) => { | ||
| 153 | + state.courseId = option?.id || null | ||
| 154 | + }) | ||
| 155 | + | ||
| 156 | + onMounted(async () => { | ||
| 157 | + await getMyStudents() | ||
| 158 | + getSelectCourseData() | ||
| 159 | + }) | ||
| 160 | + | ||
| 161 | + const signUpHandler = async () => { | ||
| 162 | + try { | ||
| 163 | + if (!state.students.length) return uni.showToast({ | ||
| 164 | + icon: 'error', | ||
| 165 | + title: '请选择报名学员' | ||
| 166 | + }) | ||
| 167 | + if (!state.schoolName) return uni.showToast({ | ||
| 168 | + icon: 'error', | ||
| 169 | + title: '请选择地区' | ||
| 170 | + }) | ||
| 171 | + if (!state.className) return uni.showToast({ | ||
| 172 | + icon: 'error', | ||
| 173 | + title: '请选择班型' | ||
| 174 | + }) | ||
| 175 | + if (!state.teacherName) return uni.showToast({ | ||
| 176 | + icon: 'error', | ||
| 177 | + title: '请选择老师' | ||
| 178 | + }) | ||
| 179 | + if (!state.courseDate || !state.courseTime) return uni.showToast({ | ||
| 180 | + icon: 'error', | ||
| 181 | + title: '请选择时段' | ||
| 182 | + }) | ||
| 183 | + await signUpApi({ | ||
| 184 | + studentWorkNo: state.students[state.activeIndex]?.workNo, | ||
| 185 | + courseId: state.courseId, | ||
| 186 | + schoolName: state.schoolName, | ||
| 187 | + className: state.className, | ||
| 188 | + teacherName: state.teacherName, | ||
| 189 | + courseDate: state.courseDate, | ||
| 190 | + courseTime: state.courseTime | ||
| 191 | + }) | ||
| 192 | + uni.showToast({ | ||
| 193 | + icon: 'success', | ||
| 194 | + title: '报名成功' | ||
| 195 | + }) | ||
| 196 | + resetSelect() | ||
| 197 | + } catch {} | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + const resetSelect = () => { | ||
| 201 | + state.schoolName = "" | ||
| 202 | + state.className = "" | ||
| 203 | + state.teacherName = "" | ||
| 204 | + state.courseDate = "" | ||
| 205 | + state.courseTime = "" | ||
| 206 | + getSelectCourseData() | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + const select1 = item => { | ||
| 210 | + if (item.status === '不可选') return; | ||
| 211 | + if (state.schoolName === item.text) { | ||
| 212 | + state.schoolName = "" | ||
| 213 | + } else { | ||
| 214 | + state.schoolName = item.text; | ||
| 215 | + } | ||
| 216 | + getSelectCourseData() | ||
| 217 | + } | ||
| 218 | + const select2 = item => { | ||
| 219 | + if (item.status === '不可选') return; | ||
| 220 | + if (state.className === item.text) { | ||
| 221 | + state.className = "" | ||
| 222 | + } else { | ||
| 223 | + state.className = item.text; | ||
| 224 | + } | ||
| 225 | + getSelectCourseData() | ||
| 226 | + } | ||
| 227 | + const select3 = item => { | ||
| 228 | + if (item.status === '不可选') return; | ||
| 229 | + if (state.teacherName === item.text) { | ||
| 230 | + state.teacherName = "" | ||
| 231 | + } else { | ||
| 232 | + state.teacherName = item.text | ||
| 233 | + } | ||
| 234 | + getSelectCourseData() | ||
| 235 | + } | ||
| 236 | + const selectTable = (item, item1) => { | ||
| 237 | + if (state.courseTime === item && state.courseDate === item1) { | ||
| 238 | + state.courseTime = "" | ||
| 239 | + state.courseDate = "" | ||
| 240 | + return | ||
| 241 | + } | ||
| 242 | + const arr = state.selectData?.tableData?.selectable.filter(v => (v.x === item && v.y === item1 && v.status === | ||
| 243 | + "可选")) | ||
| 244 | + if (!arr.length) return false | ||
| 245 | + state.courseTime = item | ||
| 246 | + state.courseDate = item1 | ||
| 247 | + getSelectCourseData() | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + const filterCell = (item, item1) => { | ||
| 251 | + const arr = state.selectData?.tableData?.selectable.filter(v => (v.x === item && v.y === item1 && v.status === | ||
| 252 | + "可选")) | ||
| 253 | + if (arr.length) return "可选" | ||
| 254 | + return "" | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + const getSelectCourseData = async () => { | ||
| 258 | + if (state.courseId === null) return | ||
| 259 | + | ||
| 260 | + const { | ||
| 261 | + data | ||
| 262 | + } = await getSelectApi({ | ||
| 263 | + courseId: state.courseId, | ||
| 264 | + schoolName: state.schoolName, | ||
| 265 | + className: state.className, | ||
| 266 | + teacherName: state.teacherName, | ||
| 267 | + courseDate: state.courseDate, | ||
| 268 | + courseTime: state.courseTime | ||
| 269 | + }) | ||
| 270 | + state.selectData = data | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + const getMyStudents = async () => { | ||
| 274 | + const { | ||
| 275 | + data | ||
| 276 | + } = await myStudentsApi() | ||
| 277 | + state.students = data.students | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + const addStudents = () => { | ||
| 281 | + studentsRef.value.close() | ||
| 282 | + uni.navigateTo({ | ||
| 283 | + url: "/pages/addStudent/addStudent" | ||
| 284 | + }) | ||
| 285 | + } | ||
| 286 | +</script> | ||
| 287 | + | ||
| 288 | +<style lang="scss" scoped> | ||
| 289 | + .container { | ||
| 290 | + background: linear-gradient(135deg, #eaecfb 10%, #f6f7fb 90%); | ||
| 291 | + background-color: red; | ||
| 292 | + height: calc(100vh - var(--tab-bar-height)); | ||
| 293 | + overflow-y: auto; | ||
| 294 | + padding: 0 24rpx; | ||
| 295 | + font-size: 28rpx; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + .title { | ||
| 299 | + padding-left: 12rpx; | ||
| 300 | + position: relative; | ||
| 301 | + | ||
| 302 | + &:before { | ||
| 303 | + content: ""; | ||
| 304 | + width: 6rpx; | ||
| 305 | + height: 70%; | ||
| 306 | + border-radius: 3rpx; | ||
| 307 | + background-color: #f5b426; | ||
| 308 | + position: absolute; | ||
| 309 | + left: 0; | ||
| 310 | + top: 50%; | ||
| 311 | + transform: translateY(-50%); | ||
| 312 | + } | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + .student-box { | ||
| 316 | + display: flex; | ||
| 317 | + align-items: center; | ||
| 318 | + justify-content: space-between; | ||
| 319 | + background-color: #fff; | ||
| 320 | + border-radius: 20rpx; | ||
| 321 | + padding: 30rpx; | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + .pop-box { | ||
| 325 | + padding: 70rpx 20rpx; | ||
| 326 | + padding-bottom: calc(var(--tab-bar-height) + 20rpx); | ||
| 327 | + | ||
| 328 | + .content-pop { | ||
| 329 | + max-height: 40vh; | ||
| 330 | + min-height: 200rpx; | ||
| 331 | + overflow-y: auto; | ||
| 332 | + | ||
| 333 | + scrollbar-width: none; | ||
| 334 | + -ms-overflow-style: none; | ||
| 335 | + | ||
| 336 | + &::-webkit-scrollbar { | ||
| 337 | + display: none; | ||
| 338 | + } | ||
| 339 | + } | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + .pop-inner-item { | ||
| 343 | + font-size: 28rpx; | ||
| 344 | + border: 2rpx solid #ccc; | ||
| 345 | + text-align: center; | ||
| 346 | + padding: 10rpx 0; | ||
| 347 | + border-radius: 9999rpx; | ||
| 348 | + margin-bottom: 40rpx; | ||
| 349 | + } | ||
| 350 | + | ||
| 351 | + .select-item { | ||
| 352 | + text-align: center; | ||
| 353 | + border: 2rpx solid #666; | ||
| 354 | + padding: 8rpx 0; | ||
| 355 | + border-radius: 9999rpx; | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + .no-select { | ||
| 359 | + color: #ccc; | ||
| 360 | + border: 2rpx solid #ccc; | ||
| 361 | + } | ||
| 362 | + | ||
| 363 | + .body-box { | ||
| 364 | + width: 100%; | ||
| 365 | + overflow-x: auto; | ||
| 366 | + box-sizing: border-box; | ||
| 367 | + border-right: 2rpx solid #a0b2f3; | ||
| 368 | + border-bottom: 2rpx solid #a0b2f3; | ||
| 369 | + | ||
| 370 | + scrollbar-width: none; | ||
| 371 | + -ms-overflow-style: none; | ||
| 372 | + | ||
| 373 | + &::-webkit-scrollbar { | ||
| 374 | + display: none; | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + .body-row { | ||
| 379 | + display: flex; | ||
| 380 | + white-space: nowrap; | ||
| 381 | + position: relative; | ||
| 382 | + box-sizing: border-box; | ||
| 383 | + min-width: fit-content; | ||
| 384 | + | ||
| 385 | + .cell { | ||
| 386 | + border: 2rpx solid #a0b2f3; | ||
| 387 | + border-right: none; | ||
| 388 | + border-bottom: none; | ||
| 389 | + flex: 0 0 auto; | ||
| 390 | + text-align: center; | ||
| 391 | + font-size: 24rpx; | ||
| 392 | + min-width: 180rpx; | ||
| 393 | + height: 60rpx; | ||
| 394 | + display: flex; | ||
| 395 | + justify-content: center; | ||
| 396 | + align-items: center; | ||
| 397 | + box-sizing: border-box; | ||
| 398 | + | ||
| 399 | + &:nth-child(1) { | ||
| 400 | + width: 140rpx; | ||
| 401 | + flex-shrink: 0; | ||
| 402 | + background-color: #edf1ff; | ||
| 403 | + position: sticky; | ||
| 404 | + left: 0; | ||
| 405 | + top: 0; | ||
| 406 | + box-shadow: 4rpx 0 4rpx rgba(0, 0, 0, 0.3); | ||
| 407 | + } | ||
| 408 | + } | ||
| 409 | + } | ||
| 410 | + | ||
| 411 | + .select-one { | ||
| 412 | + background-color: #8386ef; | ||
| 413 | + color: #fff; | ||
| 414 | + } | ||
| 415 | +</style> |
static/bottomBg.png
0 → 100644
2.56 KB
static/device/add.png
0 → 100644
3.01 KB
static/device/deviceIcon.png
0 → 100644
1.71 KB
static/device/deviceTitle.png
0 → 100644
1.98 KB
static/device/empty.png
0 → 100644
9.59 KB
static/device/itemBg.png
0 → 100644
8.12 KB
static/index/empty.png
0 → 100644
10.7 KB
static/index/icon1.png
0 → 100644
4.14 KB
static/index/icon2.png
0 → 100644
3.83 KB
static/index/icon3.png
0 → 100644
3.67 KB
static/index/icon4.png
0 → 100644
3.3 KB
static/index/navTitle.png
0 → 100644
3.51 KB
static/index/record1.png
0 → 100644
10.3 KB
static/index/record2.png
0 → 100644
11.7 KB
static/index/record3.png
0 → 100644
13.9 KB
static/index/record4.png
0 → 100644
12.6 KB
static/index/record5.png
0 → 100644
14 KB
static/login/avatar.png
0 → 100644
6.28 KB
static/login/getBtn.png
0 → 100644
4.22 KB
static/login/loginBtn.png
0 → 100644
6.1 KB
static/login/loginTitle.png
0 → 100644
1.35 KB
static/login/unGet.png
0 → 100644
5.25 KB
static/my/avatar.png
0 → 100644
8.3 KB
static/my/information.png
0 → 100644
14.4 KB
static/my/myTitle.png
0 → 100644
1.34 KB
static/my/print.png
0 → 100644
1.54 KB
static/my/student.png
0 → 100644
2.06 KB
static/studentsList/add.png
0 → 100644
3.59 KB
static/studentsList/addBg.png
0 → 100644
6.43 KB
static/studentsList/bind.png
0 → 100644
6.41 KB
static/studentsList/bindSec.png
0 → 100644
2.18 KB
static/studentsList/bindTitle.png
0 → 100644
2.18 KB
static/studentsList/edit.png
0 → 100644
4.11 KB
static/studentsList/empty.png
0 → 100644
3.68 KB
static/studentsList/itemBg.png
0 → 100644
2.16 KB
static/studentsList/unBind.png
0 → 100644
5.32 KB
static/tabBar/device.png
0 → 100644
2.34 KB
static/tabBar/deviceAc.png
0 → 100644
2.13 KB
static/tabBar/home.png
0 → 100644
2.34 KB
static/tabBar/homeAc.png
0 → 100644
2.45 KB
static/tabBar/my.png
0 → 100644
2.4 KB
static/tabBar/myAc.png
0 → 100644
2.3 KB
static/topBg.png
0 → 100644
12.5 KB
uni.promisify.adaptor.js
0 → 100644
| 1 | +uni.addInterceptor({ | ||
| 2 | + returnValue (res) { | ||
| 3 | + if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { | ||
| 4 | + return res; | ||
| 5 | + } | ||
| 6 | + return new Promise((resolve, reject) => { | ||
| 7 | + res.then((res) => { | ||
| 8 | + if (!res) return resolve(res) | ||
| 9 | + return res[0] ? reject(res[0]) : resolve(res[1]) | ||
| 10 | + }); | ||
| 11 | + }); | ||
| 12 | + }, | ||
| 13 | +}); |
uni.scss
0 → 100644
| 1 | +/** | ||
| 2 | + * 这里是uni-app内置的常用样式变量 | ||
| 3 | + * | ||
| 4 | + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 | ||
| 5 | + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App | ||
| 6 | + * | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 | ||
| 11 | + * | ||
| 12 | + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +/* 颜色变量 */ | ||
| 16 | + | ||
| 17 | +/* 行为相关颜色 */ | ||
| 18 | +$uni-color-primary: #007aff; | ||
| 19 | +$uni-color-success: #4cd964; | ||
| 20 | +$uni-color-warning: #f0ad4e; | ||
| 21 | +$uni-color-error: #dd524d; | ||
| 22 | + | ||
| 23 | +/* 文字基本颜色 */ | ||
| 24 | +$uni-text-color:#333;//基本色 | ||
| 25 | +$uni-text-color-inverse:#fff;//反色 | ||
| 26 | +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 | ||
| 27 | +$uni-text-color-placeholder: #808080; | ||
| 28 | +$uni-text-color-disable:#c0c0c0; | ||
| 29 | + | ||
| 30 | +/* 背景颜色 */ | ||
| 31 | +$uni-bg-color:#ffffff; | ||
| 32 | +$uni-bg-color-grey:#f8f8f8; | ||
| 33 | +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 | ||
| 34 | +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 | ||
| 35 | + | ||
| 36 | +/* 边框颜色 */ | ||
| 37 | +$uni-border-color:#c8c7cc; | ||
| 38 | + | ||
| 39 | +/* 尺寸变量 */ | ||
| 40 | + | ||
| 41 | +/* 文字尺寸 */ | ||
| 42 | +$uni-font-size-sm:12px; | ||
| 43 | +$uni-font-size-base:14px; | ||
| 44 | +$uni-font-size-lg:16px; | ||
| 45 | + | ||
| 46 | +/* 图片尺寸 */ | ||
| 47 | +$uni-img-size-sm:20px; | ||
| 48 | +$uni-img-size-base:26px; | ||
| 49 | +$uni-img-size-lg:40px; | ||
| 50 | + | ||
| 51 | +/* Border Radius */ | ||
| 52 | +$uni-border-radius-sm: 2px; | ||
| 53 | +$uni-border-radius-base: 3px; | ||
| 54 | +$uni-border-radius-lg: 6px; | ||
| 55 | +$uni-border-radius-circle: 50%; | ||
| 56 | + | ||
| 57 | +/* 水平间距 */ | ||
| 58 | +$uni-spacing-row-sm: 5px; | ||
| 59 | +$uni-spacing-row-base: 10px; | ||
| 60 | +$uni-spacing-row-lg: 15px; | ||
| 61 | + | ||
| 62 | +/* 垂直间距 */ | ||
| 63 | +$uni-spacing-col-sm: 4px; | ||
| 64 | +$uni-spacing-col-base: 8px; | ||
| 65 | +$uni-spacing-col-lg: 12px; | ||
| 66 | + | ||
| 67 | +/* 透明度 */ | ||
| 68 | +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 | ||
| 69 | + | ||
| 70 | +/* 文章场景相关 */ | ||
| 71 | +$uni-color-title: #2C405A; // 文章标题颜色 | ||
| 72 | +$uni-font-size-title:20px; | ||
| 73 | +$uni-color-subtitle: #555555; // 二级标题颜色 | ||
| 74 | +$uni-font-size-subtitle:26px; | ||
| 75 | +$uni-color-paragraph: #3F536E; // 文章段落颜色 | ||
| 76 | +$uni-font-size-paragraph:15px; | ||
| 77 | + | ||
| 78 | +html, body { | ||
| 79 | + padding: 0; | ||
| 80 | + bottom: 0; | ||
| 81 | + height: 100%; | ||
| 82 | + width: 100%; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +uni-page-body { | ||
| 86 | + height: 100%; | ||
| 87 | +} |
uni_modules/uv-action-sheet/changelog.md
0 → 100644
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 标题,有值则显示,同时会显示关闭按钮 | ||
| 4 | + title: { | ||
| 5 | + type: String, | ||
| 6 | + default: '' | ||
| 7 | + }, | ||
| 8 | + // 选项上方的描述信息 | ||
| 9 | + description: { | ||
| 10 | + type: String, | ||
| 11 | + default: '' | ||
| 12 | + }, | ||
| 13 | + // 数据 | ||
| 14 | + actions: { | ||
| 15 | + type: Array, | ||
| 16 | + default: () => [] | ||
| 17 | + }, | ||
| 18 | + // 取消按钮的文字,不为空时显示按钮 | ||
| 19 | + cancelText: { | ||
| 20 | + type: String, | ||
| 21 | + default: '' | ||
| 22 | + }, | ||
| 23 | + // 点击某个菜单项时是否关闭弹窗 | ||
| 24 | + closeOnClickAction: { | ||
| 25 | + type: Boolean, | ||
| 26 | + default: true | ||
| 27 | + }, | ||
| 28 | + // 处理底部安全区(默认true) | ||
| 29 | + safeAreaInsetBottom: { | ||
| 30 | + type: Boolean, | ||
| 31 | + default: true | ||
| 32 | + }, | ||
| 33 | + // 小程序的打开方式 | ||
| 34 | + openType: { | ||
| 35 | + type: String, | ||
| 36 | + default: '' | ||
| 37 | + }, | ||
| 38 | + // 点击遮罩是否允许关闭 (默认true) | ||
| 39 | + closeOnClickOverlay: { | ||
| 40 | + type: Boolean, | ||
| 41 | + default: true | ||
| 42 | + }, | ||
| 43 | + // 圆角值 | ||
| 44 | + round: { | ||
| 45 | + type: [Boolean, String, Number], | ||
| 46 | + default: 0 | ||
| 47 | + }, | ||
| 48 | + ...uni.$uv?.props?.actionSheet | ||
| 49 | + } | ||
| 50 | +} |
| 1 | + | ||
| 2 | +<template> | ||
| 3 | + <uv-popup | ||
| 4 | + ref="popup" | ||
| 5 | + mode="bottom" | ||
| 6 | + :safeAreaInsetBottom="safeAreaInsetBottom" | ||
| 7 | + :round="round" | ||
| 8 | + :close-on-click-overlay="closeOnClickOverlay" | ||
| 9 | + @change="popupChange" | ||
| 10 | + > | ||
| 11 | + <view class="uv-action-sheet"> | ||
| 12 | + <view | ||
| 13 | + class="uv-action-sheet__header" | ||
| 14 | + v-if="title" | ||
| 15 | + > | ||
| 16 | + <text class="uv-action-sheet__header__title uv-line-1">{{title}}</text> | ||
| 17 | + <view | ||
| 18 | + class="uv-action-sheet__header__icon-wrap" | ||
| 19 | + @tap.stop="cancel" | ||
| 20 | + > | ||
| 21 | + <uv-icon | ||
| 22 | + name="close" | ||
| 23 | + size="17" | ||
| 24 | + color="#c8c9cc" | ||
| 25 | + bold | ||
| 26 | + ></uv-icon> | ||
| 27 | + </view> | ||
| 28 | + </view> | ||
| 29 | + <text | ||
| 30 | + class="uv-action-sheet__description" | ||
| 31 | + :style="[{ | ||
| 32 | + marginTop: `${title && description ? 0 : '18px'}` | ||
| 33 | + }]" | ||
| 34 | + v-if="description" | ||
| 35 | + >{{description}}</text> | ||
| 36 | + <slot> | ||
| 37 | + <uv-line v-if="description"></uv-line> | ||
| 38 | + <view class="uv-action-sheet__item-wrap"> | ||
| 39 | + <view v-for="(item, index) in actions" :key="index"> | ||
| 40 | + <!-- #ifdef MP --> | ||
| 41 | + <button | ||
| 42 | + class="uv-reset-button" | ||
| 43 | + :openType="item.openType" | ||
| 44 | + @getuserinfo="onGetUserInfo" | ||
| 45 | + @contact="onContact" | ||
| 46 | + @getphonenumber="onGetPhoneNumber" | ||
| 47 | + @error="onError" | ||
| 48 | + @launchapp="onLaunchApp" | ||
| 49 | + @opensetting="onOpenSetting" | ||
| 50 | + :lang="lang" | ||
| 51 | + :session-from="sessionFrom" | ||
| 52 | + :send-message-title="sendMessageTitle" | ||
| 53 | + :send-message-path="sendMessagePath" | ||
| 54 | + :send-message-img="sendMessageImg" | ||
| 55 | + :show-message-card="showMessageCard" | ||
| 56 | + :app-parameter="appParameter" | ||
| 57 | + @tap="selectHandler(index)" | ||
| 58 | + :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''" | ||
| 59 | + > | ||
| 60 | + <!-- #endif --> | ||
| 61 | + <view | ||
| 62 | + class="uv-action-sheet__item-wrap__item" | ||
| 63 | + @tap.stop="selectHandler(index)" | ||
| 64 | + :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''" | ||
| 65 | + :hover-stay-time="150" | ||
| 66 | + > | ||
| 67 | + <template v-if="!item.loading"> | ||
| 68 | + <text | ||
| 69 | + class="uv-action-sheet__item-wrap__item__name" | ||
| 70 | + :style="[itemStyle(index)]" | ||
| 71 | + >{{ item.name }}</text> | ||
| 72 | + <text | ||
| 73 | + v-if="item.subname" | ||
| 74 | + class="uv-action-sheet__item-wrap__item__subname" | ||
| 75 | + >{{ item.subname }}</text> | ||
| 76 | + </template> | ||
| 77 | + <uv-loading-icon | ||
| 78 | + v-else | ||
| 79 | + custom-class="van-action-sheet__loading" | ||
| 80 | + size="18" | ||
| 81 | + mode="circle" | ||
| 82 | + /> | ||
| 83 | + </view> | ||
| 84 | + <!-- #ifdef MP --> | ||
| 85 | + </button> | ||
| 86 | + <!-- #endif --> | ||
| 87 | + <uv-line v-if="index !== actions.length - 1"></uv-line> | ||
| 88 | + </view> | ||
| 89 | + </view> | ||
| 90 | + </slot> | ||
| 91 | + <uv-gap | ||
| 92 | + bgColor="#eaeaec" | ||
| 93 | + height="6" | ||
| 94 | + v-if="cancelText" | ||
| 95 | + ></uv-gap> | ||
| 96 | + <view hover-class="uv-action-sheet--hover"> | ||
| 97 | + <text | ||
| 98 | + @touchmove.stop.prevent | ||
| 99 | + :hover-stay-time="150" | ||
| 100 | + v-if="cancelText" | ||
| 101 | + class="uv-action-sheet__cancel-text" | ||
| 102 | + @tap="cancel" | ||
| 103 | + >{{cancelText}}</text> | ||
| 104 | + </view> | ||
| 105 | + </view> | ||
| 106 | + </uv-popup> | ||
| 107 | +</template> | ||
| 108 | + | ||
| 109 | +<script> | ||
| 110 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 111 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 112 | + import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js' | ||
| 113 | + import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js' | ||
| 114 | + import props from './props.js'; | ||
| 115 | + /** | ||
| 116 | + * ActionSheet 操作菜单 | ||
| 117 | + * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。 | ||
| 118 | + * @tutorial https://www.uvui.cn/components/actionSheet.html | ||
| 119 | + * @property {Boolean} show 操作菜单是否展示 (默认 false ) | ||
| 120 | + * @property {String} title 操作菜单标题 | ||
| 121 | + * @property {String} description 选项上方的描述信息 | ||
| 122 | + * @property {Array<Object>} actions 按钮的文字数组,见官方文档示例 | ||
| 123 | + * @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮 | ||
| 124 | + * @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 (默认 true ) | ||
| 125 | + * @property {Boolean} safeAreaInsetBottom 处理底部安全区 (默认 true ) | ||
| 126 | + * @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error ) | ||
| 127 | + * @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true ) | ||
| 128 | + * @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文 | ||
| 129 | + * @property {String} sessionFrom 会话来源,openType="contact"时有效 | ||
| 130 | + * @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效 | ||
| 131 | + * @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效 | ||
| 132 | + * @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效 | ||
| 133 | + * @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false ) | ||
| 134 | + * @property {String} appParameter 打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效 | ||
| 135 | + * | ||
| 136 | + * @event {Function} select 点击ActionSheet列表项时触发 | ||
| 137 | + * @event {Function} close 点击取消按钮时触发 | ||
| 138 | + * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效 | ||
| 139 | + * @event {Function} contact 客服消息回调,openType="contact"时有效 | ||
| 140 | + * @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效 | ||
| 141 | + * @event {Function} error 当使用开放能力时,发生错误的回调,openType="error"时有效 | ||
| 142 | + * @event {Function} launchapp 打开 APP 成功的回调,openType="launchApp"时有效 | ||
| 143 | + * @event {Function} opensetting 在打开授权设置页后回调,openType="openSetting"时有效 | ||
| 144 | + * @example <uv-action-sheet ref="actionSheet" :actions="list" :title="title" ></uv-action-sheet> | ||
| 145 | + */ | ||
| 146 | + export default { | ||
| 147 | + name: "uv-action-sheet", | ||
| 148 | + mixins: [openType, button, mpMixin , mixin, props], | ||
| 149 | + emits: ['close', 'select'], | ||
| 150 | + computed: { | ||
| 151 | + // 操作项目的样式 | ||
| 152 | + itemStyle() { | ||
| 153 | + return (index) => { | ||
| 154 | + let style = {}; | ||
| 155 | + if (this.actions[index].color) style.color = this.actions[index].color | ||
| 156 | + if (this.actions[index].fontSize) style.fontSize = this.$uv.addUnit(this.actions[index].fontSize) | ||
| 157 | + // 选项被禁用的样式 | ||
| 158 | + if (this.actions[index].disabled) style.color = '#c0c4cc' | ||
| 159 | + return style; | ||
| 160 | + } | ||
| 161 | + }, | ||
| 162 | + }, | ||
| 163 | + methods: { | ||
| 164 | + open() { | ||
| 165 | + this.$refs.popup.open(); | ||
| 166 | + }, | ||
| 167 | + close() { | ||
| 168 | + this.$refs.popup.close(); | ||
| 169 | + }, | ||
| 170 | + popupChange(e) { | ||
| 171 | + if(!e.show) this.$emit('close'); | ||
| 172 | + }, | ||
| 173 | + // 点击取消按钮 | ||
| 174 | + cancel() { | ||
| 175 | + this.close(); | ||
| 176 | + }, | ||
| 177 | + selectHandler(index) { | ||
| 178 | + const item = this.actions[index] | ||
| 179 | + if (item && !item.disabled && !item.loading) { | ||
| 180 | + this.$emit('select', item) | ||
| 181 | + if (this.closeOnClickAction) { | ||
| 182 | + this.close(); | ||
| 183 | + } | ||
| 184 | + } | ||
| 185 | + }, | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | +</script> | ||
| 189 | + | ||
| 190 | +<style lang="scss" scoped> | ||
| 191 | + $show-lines: 1; | ||
| 192 | + $show-reset-button: 1; | ||
| 193 | + @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss'; | ||
| 194 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 195 | + @import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 196 | + $uv-action-sheet-reset-button-width:100% !default; | ||
| 197 | + $uv-action-sheet-title-font-size: 16px !default; | ||
| 198 | + $uv-action-sheet-title-padding: 12px 30px !default; | ||
| 199 | + $uv-action-sheet-title-color: $uv-main-color !default; | ||
| 200 | + $uv-action-sheet-header-icon-wrap-right:15px !default; | ||
| 201 | + $uv-action-sheet-header-icon-wrap-top:15px !default; | ||
| 202 | + $uv-action-sheet-description-font-size:13px !default; | ||
| 203 | + $uv-action-sheet-description-color:14px !default; | ||
| 204 | + $uv-action-sheet-description-margin: 18px 15px !default; | ||
| 205 | + $uv-action-sheet-item-wrap-item-padding:15px !default; | ||
| 206 | + $uv-action-sheet-item-wrap-name-font-size:16px !default; | ||
| 207 | + $uv-action-sheet-item-wrap-subname-font-size:13px !default; | ||
| 208 | + $uv-action-sheet-item-wrap-subname-color: #c0c4cc !default; | ||
| 209 | + $uv-action-sheet-item-wrap-subname-margin-top:10px !default; | ||
| 210 | + $uv-action-sheet-cancel-text-font-size:16px !default; | ||
| 211 | + $uv-action-sheet-cancel-text-color:$uv-content-color !default; | ||
| 212 | + $uv-action-sheet-cancel-text-font-size:15px !default; | ||
| 213 | + $uv-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default; | ||
| 214 | + | ||
| 215 | + .uv-reset-button { | ||
| 216 | + width: $uv-action-sheet-reset-button-width; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + .uv-action-sheet { | ||
| 220 | + text-align: center; | ||
| 221 | + &__header { | ||
| 222 | + position: relative; | ||
| 223 | + padding: $uv-action-sheet-title-padding; | ||
| 224 | + &__title { | ||
| 225 | + font-size: $uv-action-sheet-title-font-size; | ||
| 226 | + color: $uv-action-sheet-title-color; | ||
| 227 | + font-weight: bold; | ||
| 228 | + text-align: center; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + &__icon-wrap { | ||
| 232 | + position: absolute; | ||
| 233 | + right: $uv-action-sheet-header-icon-wrap-right; | ||
| 234 | + top: $uv-action-sheet-header-icon-wrap-top; | ||
| 235 | + } | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + &__description { | ||
| 239 | + font-size: $uv-action-sheet-description-font-size; | ||
| 240 | + color: $uv-tips-color; | ||
| 241 | + margin: $uv-action-sheet-description-margin; | ||
| 242 | + text-align: center; | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + &__item-wrap { | ||
| 246 | + | ||
| 247 | + &__item { | ||
| 248 | + padding: $uv-action-sheet-item-wrap-item-padding; | ||
| 249 | + @include flex; | ||
| 250 | + align-items: center; | ||
| 251 | + justify-content: center; | ||
| 252 | + flex-direction: column; | ||
| 253 | + | ||
| 254 | + &__name { | ||
| 255 | + font-size: $uv-action-sheet-item-wrap-name-font-size; | ||
| 256 | + color: $uv-main-color; | ||
| 257 | + text-align: center; | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + &__subname { | ||
| 261 | + font-size: $uv-action-sheet-item-wrap-subname-font-size; | ||
| 262 | + color: $uv-action-sheet-item-wrap-subname-color; | ||
| 263 | + margin-top: $uv-action-sheet-item-wrap-subname-margin-top; | ||
| 264 | + text-align: center; | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + &__cancel-text { | ||
| 270 | + font-size: $uv-action-sheet-cancel-text-font-size; | ||
| 271 | + color: $uv-action-sheet-cancel-text-color; | ||
| 272 | + text-align: center; | ||
| 273 | + padding: $uv-action-sheet-cancel-text-font-size; | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + &--hover { | ||
| 277 | + background-color: $uv-action-sheet-cancel-text-hover-background-color; | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | +</style> |
uni_modules/uv-action-sheet/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-action-sheet", | ||
| 3 | + "displayName": "uv-action-sheet 底部操作菜单 全面兼容小程序、nvue、vue2、vue3等多端", | ||
| 4 | + "version": "1.0.2", | ||
| 5 | + "description": "该组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheet API,配置更加灵活,所有平台都表现一致。", | ||
| 6 | + "keywords": [ | ||
| 7 | + "action-sheet", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "操作菜单", | ||
| 11 | + "菜单选择" | ||
| 12 | +], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools", | ||
| 40 | + "uv-popup", | ||
| 41 | + "uv-icon", | ||
| 42 | + "uv-line", | ||
| 43 | + "uv-loading-icon", | ||
| 44 | + "uv-gap" | ||
| 45 | + ], | ||
| 46 | + "encrypt": [], | ||
| 47 | + "platforms": { | ||
| 48 | + "cloud": { | ||
| 49 | + "tcb": "y", | ||
| 50 | + "aliyun": "y" | ||
| 51 | + }, | ||
| 52 | + "client": { | ||
| 53 | + "Vue": { | ||
| 54 | + "vue2": "y", | ||
| 55 | + "vue3": "y" | ||
| 56 | + }, | ||
| 57 | + "App": { | ||
| 58 | + "app-vue": "y", | ||
| 59 | + "app-nvue": "y" | ||
| 60 | + }, | ||
| 61 | + "H5-mobile": { | ||
| 62 | + "Safari": "y", | ||
| 63 | + "Android Browser": "y", | ||
| 64 | + "微信浏览器(Android)": "y", | ||
| 65 | + "QQ浏览器(Android)": "y" | ||
| 66 | + }, | ||
| 67 | + "H5-pc": { | ||
| 68 | + "Chrome": "y", | ||
| 69 | + "IE": "y", | ||
| 70 | + "Edge": "y", | ||
| 71 | + "Firefox": "y", | ||
| 72 | + "Safari": "y" | ||
| 73 | + }, | ||
| 74 | + "小程序": { | ||
| 75 | + "微信": "y", | ||
| 76 | + "阿里": "y", | ||
| 77 | + "百度": "y", | ||
| 78 | + "字节跳动": "y", | ||
| 79 | + "QQ": "y", | ||
| 80 | + "钉钉": "u", | ||
| 81 | + "快手": "u", | ||
| 82 | + "飞书": "u", | ||
| 83 | + "京东": "u" | ||
| 84 | + }, | ||
| 85 | + "快应用": { | ||
| 86 | + "华为": "u", | ||
| 87 | + "联盟": "u" | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} |
uni_modules/uv-action-sheet/readme.md
0 → 100644
| 1 | +## ActionSheet 操作菜单 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-action-sheet** | ||
| 4 | + | ||
| 5 | +本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。 | ||
| 6 | + | ||
| 7 | +本组件功能类似于uni的uni.showActionSheet API,配置更加灵活,所有平台都表现一致。 | ||
| 8 | + | ||
| 9 | +### <a href="https://www.uvui.cn/components/actionSheet.html" target="_blank">查看文档</a> | ||
| 10 | + | ||
| 11 | +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 12 | + | ||
| 13 | +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-album/changelog.md
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="uv-album"> | ||
| 3 | + <view | ||
| 4 | + class="uv-album__row" | ||
| 5 | + ref="uv-album__row" | ||
| 6 | + v-for="(arr, index) in showUrls" | ||
| 7 | + :forComputedUse="albumWidth" | ||
| 8 | + :key="index" | ||
| 9 | + > | ||
| 10 | + <view | ||
| 11 | + class="uv-album__row__wrapper" | ||
| 12 | + v-for="(item, index1) in arr" | ||
| 13 | + :key="index1" | ||
| 14 | + :style="[imageStyle(index + 1, index1 + 1)]" | ||
| 15 | + @tap.stop="previewFullImage ? onPreviewTap(getSrc(item)) : ''" | ||
| 16 | + > | ||
| 17 | + <image | ||
| 18 | + :src="getSrc(item)" | ||
| 19 | + :mode=" | ||
| 20 | + urls.length === 1 | ||
| 21 | + ? imageHeight > 0 | ||
| 22 | + ? singleMode | ||
| 23 | + : 'widthFix' | ||
| 24 | + : multipleMode | ||
| 25 | + " | ||
| 26 | + :style="[ | ||
| 27 | + { | ||
| 28 | + width: imageWidth, | ||
| 29 | + height: imageHeight | ||
| 30 | + } | ||
| 31 | + ]" | ||
| 32 | + ></image> | ||
| 33 | + <view | ||
| 34 | + v-if=" | ||
| 35 | + showMore && | ||
| 36 | + urls.length > rowCount * showUrls.length && | ||
| 37 | + index === showUrls.length - 1 && | ||
| 38 | + index1 === showUrls[showUrls.length - 1].length - 1 | ||
| 39 | + " | ||
| 40 | + class="uv-album__row__wrapper__text" | ||
| 41 | + > | ||
| 42 | + <uv-text | ||
| 43 | + :text="`+${urls.length - maxCount}`" | ||
| 44 | + color="#fff" | ||
| 45 | + :size="$uv.getPx(multipleSize) * 0.3" | ||
| 46 | + align="center" | ||
| 47 | + customStyle="justify-content: center" | ||
| 48 | + ></uv-text> | ||
| 49 | + </view> | ||
| 50 | + </view> | ||
| 51 | + </view> | ||
| 52 | + </view> | ||
| 53 | +</template> | ||
| 54 | +<script> | ||
| 55 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 56 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 57 | + // #ifdef APP-NVUE | ||
| 58 | + // 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度 | ||
| 59 | + const dom = uni.requireNativePlugin('dom') | ||
| 60 | + // #endif | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * Album 相册 | ||
| 64 | + * @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码 | ||
| 65 | + * @tutorial https://www.uvui.cn/components/album.html | ||
| 66 | + * @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式 | ||
| 67 | + * @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址 | ||
| 68 | + * @property {String | Number} singleSize 单图时,图片长边的长度 (默认 180 ) | ||
| 69 | + * @property {String | Number} multipleSize 多图时,图片边长 (默认 70 ) | ||
| 70 | + * @property {String | Number} space 多图时,图片水平和垂直之间的间隔 (默认 6 ) | ||
| 71 | + * @property {String} singleMode 单图时,图片缩放裁剪的模式 (默认 'scaleToFill' ) | ||
| 72 | + * @property {String} multipleMode 多图时,图片缩放裁剪的模式 (默认 'aspectFill' ) | ||
| 73 | + * @property {String | Number} maxCount 取消按钮的提示文字 (默认 9 ) | ||
| 74 | + * @property {Boolean} previewFullImage 是否可以预览图片 (默认 true ) | ||
| 75 | + * @property {String | Number} rowCount 每行展示图片数量,如设置,singleSize和multipleSize将会无效 (默认 3 ) | ||
| 76 | + * @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true ) | ||
| 77 | + * | ||
| 78 | + * @event {Function} albumWidth 某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送 (回调参数 width ) | ||
| 79 | + * @example <uv-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></uv-album> | ||
| 80 | + */ | ||
| 81 | + export default { | ||
| 82 | + name: 'uv-album', | ||
| 83 | + mixins: [mpMixin, mixin], | ||
| 84 | + emits: ['albumWidth'], | ||
| 85 | + props: { | ||
| 86 | + // 图片地址,Array<String>|Array<Object>形式 | ||
| 87 | + urls: { | ||
| 88 | + type: Array, | ||
| 89 | + default: () => [] | ||
| 90 | + }, | ||
| 91 | + // 指定从数组的对象元素中读取哪个属性作为图片地址 | ||
| 92 | + keyName: { | ||
| 93 | + type: String, | ||
| 94 | + default: '' | ||
| 95 | + }, | ||
| 96 | + // 单图时,图片长边的长度 | ||
| 97 | + singleSize: { | ||
| 98 | + type: [String, Number], | ||
| 99 | + default: 180 | ||
| 100 | + }, | ||
| 101 | + // 多图时,图片边长 | ||
| 102 | + multipleSize: { | ||
| 103 | + type: [String, Number], | ||
| 104 | + default: 70 | ||
| 105 | + }, | ||
| 106 | + // 多图时,图片水平和垂直之间的间隔 | ||
| 107 | + space: { | ||
| 108 | + type: [String, Number], | ||
| 109 | + default: 6 | ||
| 110 | + }, | ||
| 111 | + // 单图时,图片缩放裁剪的模式 | ||
| 112 | + singleMode: { | ||
| 113 | + type: String, | ||
| 114 | + default: 'scaleToFill' | ||
| 115 | + }, | ||
| 116 | + // 多图时,图片缩放裁剪的模式 | ||
| 117 | + multipleMode: { | ||
| 118 | + type: String, | ||
| 119 | + default: 'aspectFill' | ||
| 120 | + }, | ||
| 121 | + // 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量 | ||
| 122 | + maxCount: { | ||
| 123 | + type: [String, Number], | ||
| 124 | + default: 9 | ||
| 125 | + }, | ||
| 126 | + // 是否可以预览图片 | ||
| 127 | + previewFullImage: { | ||
| 128 | + type: Boolean, | ||
| 129 | + default: true | ||
| 130 | + }, | ||
| 131 | + // 每行展示图片数量,如设置,singleSize和multipleSize将会无效 | ||
| 132 | + rowCount: { | ||
| 133 | + type: [String, Number], | ||
| 134 | + default: 3 | ||
| 135 | + }, | ||
| 136 | + // 超出maxCount时是否显示查看更多的提示 | ||
| 137 | + showMore: { | ||
| 138 | + type: Boolean, | ||
| 139 | + default: true | ||
| 140 | + }, | ||
| 141 | + ...uni.$uv?.props?.album | ||
| 142 | + }, | ||
| 143 | + data() { | ||
| 144 | + return { | ||
| 145 | + // 单图的宽度 | ||
| 146 | + singleWidth: 0, | ||
| 147 | + // 单图的高度 | ||
| 148 | + singleHeight: 0, | ||
| 149 | + // 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比 | ||
| 150 | + singlePercent: 0.6 | ||
| 151 | + } | ||
| 152 | + }, | ||
| 153 | + watch: { | ||
| 154 | + urls: { | ||
| 155 | + immediate: true, | ||
| 156 | + handler(newVal) { | ||
| 157 | + if (newVal.length === 1) { | ||
| 158 | + this.getImageRect() | ||
| 159 | + } | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + }, | ||
| 163 | + computed: { | ||
| 164 | + imageStyle() { | ||
| 165 | + return (index1, index2) => { | ||
| 166 | + const { space, rowCount, multipleSize, urls } = this; | ||
| 167 | + const rowLen = this.showUrls.length; | ||
| 168 | + const allLen = this.urls.length; | ||
| 169 | + const style = { | ||
| 170 | + marginRight: this.$uv.addUnit(space), | ||
| 171 | + marginBottom: this.$uv.addUnit(space) | ||
| 172 | + } | ||
| 173 | + // 如果为最后一行,则每个图片都无需下边框 | ||
| 174 | + if (index1 === rowLen) style.marginBottom = 0 | ||
| 175 | + // 每行的最右边一张和总长度的最后一张无需右边框 | ||
| 176 | + if ( | ||
| 177 | + index2 === rowCount || | ||
| 178 | + (index1 === rowLen && | ||
| 179 | + index2 === this.showUrls[index1 - 1].length) | ||
| 180 | + ) | ||
| 181 | + style.marginRight = 0 | ||
| 182 | + return style | ||
| 183 | + } | ||
| 184 | + }, | ||
| 185 | + // 将数组划分为二维数组 | ||
| 186 | + showUrls() { | ||
| 187 | + const arr = [] | ||
| 188 | + this.urls.map((item, index) => { | ||
| 189 | + // 限制最大展示数量 | ||
| 190 | + if (index + 1 <= this.maxCount) { | ||
| 191 | + // 计算该元素为第几个素组内 | ||
| 192 | + const itemIndex = Math.floor(index / this.rowCount) | ||
| 193 | + // 判断对应的索引是否存在 | ||
| 194 | + if (!arr[itemIndex]) { | ||
| 195 | + arr[itemIndex] = [] | ||
| 196 | + } | ||
| 197 | + arr[itemIndex].push(item) | ||
| 198 | + } | ||
| 199 | + }) | ||
| 200 | + return arr | ||
| 201 | + }, | ||
| 202 | + imageWidth() { | ||
| 203 | + return this.$uv.addUnit( | ||
| 204 | + this.urls.length === 1 ? this.singleWidth : this.multipleSize | ||
| 205 | + ) | ||
| 206 | + }, | ||
| 207 | + imageHeight() { | ||
| 208 | + return this.$uv.addUnit( | ||
| 209 | + this.urls.length === 1 ? this.singleHeight : this.multipleSize | ||
| 210 | + ) | ||
| 211 | + }, | ||
| 212 | + // 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度 | ||
| 213 | + // 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送 | ||
| 214 | + albumWidth() { | ||
| 215 | + let width = 0 | ||
| 216 | + if (this.urls.length === 1) { | ||
| 217 | + width = this.singleWidth | ||
| 218 | + } else { | ||
| 219 | + width = | ||
| 220 | + this.showUrls[0].length * this.$uv.getPx(this.multipleSize) + | ||
| 221 | + this.$uv.getPx(this.space) * (this.showUrls[0].length - 1) | ||
| 222 | + } | ||
| 223 | + this.$emit('albumWidth', width) | ||
| 224 | + return width | ||
| 225 | + } | ||
| 226 | + }, | ||
| 227 | + methods: { | ||
| 228 | + // 预览图片 | ||
| 229 | + onPreviewTap(url) { | ||
| 230 | + const urls = this.urls.map((item) => { | ||
| 231 | + return this.getSrc(item) | ||
| 232 | + }) | ||
| 233 | + uni.previewImage({ | ||
| 234 | + current: url, | ||
| 235 | + urls | ||
| 236 | + }) | ||
| 237 | + }, | ||
| 238 | + // 获取图片的路径 | ||
| 239 | + getSrc(item) { | ||
| 240 | + return this.$uv.test.object(item) ? | ||
| 241 | + (this.keyName && item[this.keyName]) || item.src : | ||
| 242 | + item | ||
| 243 | + }, | ||
| 244 | + // 单图时,获取图片的尺寸 | ||
| 245 | + // 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸 | ||
| 246 | + // 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent) | ||
| 247 | + getImageRect() { | ||
| 248 | + const src = this.getSrc(this.urls[0]) | ||
| 249 | + uni.getImageInfo({ | ||
| 250 | + src, | ||
| 251 | + success: (res) => { | ||
| 252 | + // 判断图片横向还是竖向展示方式 | ||
| 253 | + const isHorizotal = res.width >= res.height | ||
| 254 | + this.singleWidth = isHorizotal ? | ||
| 255 | + this.singleSize : | ||
| 256 | + (res.width / res.height) * this.$uv.getPx(this.singleSize) | ||
| 257 | + this.singleHeight = !isHorizotal ? | ||
| 258 | + this.singleSize : | ||
| 259 | + (res.height / res.width) * this.singleWidth | ||
| 260 | + }, | ||
| 261 | + fail: () => { | ||
| 262 | + this.getComponentWidth() | ||
| 263 | + } | ||
| 264 | + }) | ||
| 265 | + }, | ||
| 266 | + // 获取组件的宽度 | ||
| 267 | + async getComponentWidth() { | ||
| 268 | + // 延时一定时间,以获取dom尺寸 | ||
| 269 | + await this.$uv.sleep(30) | ||
| 270 | + // #ifndef APP-NVUE | ||
| 271 | + this.$uGetRect('.uv-album__row').then((size) => { | ||
| 272 | + this.singleWidth = size.width * this.singlePercent | ||
| 273 | + }) | ||
| 274 | + // #endif | ||
| 275 | + | ||
| 276 | + // #ifdef APP-NVUE | ||
| 277 | + // 这里ref="uv-album__row"所在的标签为通过for循环出来,导致this.$refs['uv-album__row']是一个数组 | ||
| 278 | + const ref = this.$refs['uv-album__row'][0] | ||
| 279 | + ref && | ||
| 280 | + dom.getComponentRect(ref, (res) => { | ||
| 281 | + this.singleWidth = res.size.width * this.singlePercent | ||
| 282 | + }) | ||
| 283 | + // #endif | ||
| 284 | + } | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | +</script> | ||
| 288 | + | ||
| 289 | +<style lang="scss" scoped> | ||
| 290 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 291 | + .uv-album { | ||
| 292 | + @include flex(column); | ||
| 293 | + &__row { | ||
| 294 | + @include flex(row); | ||
| 295 | + flex-wrap: wrap; | ||
| 296 | + &__wrapper { | ||
| 297 | + position: relative; | ||
| 298 | + &__text { | ||
| 299 | + position: absolute; | ||
| 300 | + top: 0; | ||
| 301 | + left: 0; | ||
| 302 | + right: 0; | ||
| 303 | + bottom: 0; | ||
| 304 | + background-color: rgba(0, 0, 0, 0.3); | ||
| 305 | + @include flex(row); | ||
| 306 | + justify-content: center; | ||
| 307 | + align-items: center; | ||
| 308 | + } | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | + } | ||
| 312 | +</style> |
uni_modules/uv-album/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-album", | ||
| 3 | + "displayName": "uv-album 相册 全面兼容vue3+2、app、h5、小程序等多端", | ||
| 4 | + "version": "1.0.4", | ||
| 5 | + "description": "本组件提供一个类似相册的功能,让开发者开发起来更加得心应手,功能齐全,灵活配置可以,开箱即用。减少重复的模板代码", | ||
| 6 | + "keywords": [ | ||
| 7 | + "album", | ||
| 8 | + "uv-ui", | ||
| 9 | + "uvui", | ||
| 10 | + "相册", | ||
| 11 | + "图片" | ||
| 12 | +], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools", | ||
| 40 | + "uv-text" | ||
| 41 | + ], | ||
| 42 | + "encrypt": [], | ||
| 43 | + "platforms": { | ||
| 44 | + "cloud": { | ||
| 45 | + "tcb": "y", | ||
| 46 | + "aliyun": "y" | ||
| 47 | + }, | ||
| 48 | + "client": { | ||
| 49 | + "Vue": { | ||
| 50 | + "vue2": "y", | ||
| 51 | + "vue3": "y" | ||
| 52 | + }, | ||
| 53 | + "App": { | ||
| 54 | + "app-vue": "y", | ||
| 55 | + "app-nvue": "y" | ||
| 56 | + }, | ||
| 57 | + "H5-mobile": { | ||
| 58 | + "Safari": "y", | ||
| 59 | + "Android Browser": "y", | ||
| 60 | + "微信浏览器(Android)": "y", | ||
| 61 | + "QQ浏览器(Android)": "y" | ||
| 62 | + }, | ||
| 63 | + "H5-pc": { | ||
| 64 | + "Chrome": "y", | ||
| 65 | + "IE": "y", | ||
| 66 | + "Edge": "y", | ||
| 67 | + "Firefox": "y", | ||
| 68 | + "Safari": "y" | ||
| 69 | + }, | ||
| 70 | + "小程序": { | ||
| 71 | + "微信": "y", | ||
| 72 | + "阿里": "y", | ||
| 73 | + "百度": "y", | ||
| 74 | + "字节跳动": "y", | ||
| 75 | + "QQ": "y", | ||
| 76 | + "钉钉": "u", | ||
| 77 | + "快手": "u", | ||
| 78 | + "飞书": "u", | ||
| 79 | + "京东": "u" | ||
| 80 | + }, | ||
| 81 | + "快应用": { | ||
| 82 | + "华为": "u", | ||
| 83 | + "联盟": "u" | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | +} |
uni_modules/uv-album/readme.md
0 → 100644
| 1 | +# Album 相册 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-album** | ||
| 4 | + | ||
| 5 | +本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。 | ||
| 6 | + | ||
| 7 | +功能齐全,灵活配置可以,开箱即用。减少重复的模板代码。 | ||
| 8 | + | ||
| 9 | +# <a href="https://www.uvui.cn/components/album.html" target="_blank">查看文档</a> | ||
| 10 | + | ||
| 11 | +## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small> | ||
| 12 | + | ||
| 13 | +### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 14 | + | ||
| 15 | +<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank"> | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +</a> | ||
| 20 | + | ||
| 21 | +#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-alert/changelog.md
0 → 100644
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 显示文字 | ||
| 4 | + title: { | ||
| 5 | + type: String, | ||
| 6 | + default: '' | ||
| 7 | + }, | ||
| 8 | + // 主题,success/warning/info/error | ||
| 9 | + type: { | ||
| 10 | + type: String, | ||
| 11 | + default: 'warning' | ||
| 12 | + }, | ||
| 13 | + // 辅助性文字 | ||
| 14 | + description: { | ||
| 15 | + type: String, | ||
| 16 | + default: '' | ||
| 17 | + }, | ||
| 18 | + // 是否可关闭 | ||
| 19 | + closable: { | ||
| 20 | + type: Boolean, | ||
| 21 | + default: false | ||
| 22 | + }, | ||
| 23 | + // 是否显示图标 | ||
| 24 | + showIcon: { | ||
| 25 | + type: Boolean, | ||
| 26 | + default: false | ||
| 27 | + }, | ||
| 28 | + // 浅或深色调,light-浅色,dark-深色 | ||
| 29 | + effect: { | ||
| 30 | + type: String, | ||
| 31 | + default: 'light' | ||
| 32 | + }, | ||
| 33 | + // 文字是否居中 | ||
| 34 | + center: { | ||
| 35 | + type: Boolean, | ||
| 36 | + default: false | ||
| 37 | + }, | ||
| 38 | + // 字体大小 | ||
| 39 | + fontSize: { | ||
| 40 | + type: [String, Number], | ||
| 41 | + default: 14 | ||
| 42 | + }, | ||
| 43 | + ...uni.$uv?.props?.alert | ||
| 44 | + } | ||
| 45 | +} |
| 1 | +<template> | ||
| 2 | + <uv-transition | ||
| 3 | + mode="fade" | ||
| 4 | + :show="show" | ||
| 5 | + > | ||
| 6 | + <view | ||
| 7 | + class="uv-alert" | ||
| 8 | + :class="[`uv-alert--${type}--${effect}`]" | ||
| 9 | + @tap.stop="clickHandler" | ||
| 10 | + :style="[$uv.addStyle(customStyle)]" | ||
| 11 | + > | ||
| 12 | + <view | ||
| 13 | + class="uv-alert__icon" | ||
| 14 | + v-if="showIcon" | ||
| 15 | + > | ||
| 16 | + <uv-icon | ||
| 17 | + :name="iconName" | ||
| 18 | + size="18" | ||
| 19 | + :color="iconColor" | ||
| 20 | + ></uv-icon> | ||
| 21 | + </view> | ||
| 22 | + <view | ||
| 23 | + class="uv-alert__content" | ||
| 24 | + :style="[{ | ||
| 25 | + paddingRight: closable ? '20px' : 0 | ||
| 26 | + }]" | ||
| 27 | + > | ||
| 28 | + <text | ||
| 29 | + class="uv-alert__content__title" | ||
| 30 | + v-if="title" | ||
| 31 | + :style="[{ | ||
| 32 | + fontSize: $uv.addUnit(fontSize), | ||
| 33 | + textAlign: center ? 'center' : 'left' | ||
| 34 | + }]" | ||
| 35 | + :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]" | ||
| 36 | + >{{ title }}</text> | ||
| 37 | + <text | ||
| 38 | + class="uv-alert__content__desc" | ||
| 39 | + v-if="description" | ||
| 40 | + :style="[{ | ||
| 41 | + fontSize: $uv.addUnit(fontSize), | ||
| 42 | + textAlign: center ? 'center' : 'left' | ||
| 43 | + }]" | ||
| 44 | + :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]" | ||
| 45 | + >{{ description }}</text> | ||
| 46 | + </view> | ||
| 47 | + <view | ||
| 48 | + class="uv-alert__close" | ||
| 49 | + v-if="closable" | ||
| 50 | + @tap.stop="closeHandler" | ||
| 51 | + > | ||
| 52 | + <uv-icon | ||
| 53 | + name="close" | ||
| 54 | + :color="iconColor" | ||
| 55 | + size="15" | ||
| 56 | + ></uv-icon> | ||
| 57 | + </view> | ||
| 58 | + </view> | ||
| 59 | + </uv-transition> | ||
| 60 | +</template> | ||
| 61 | + | ||
| 62 | +<script> | ||
| 63 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 64 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 65 | + import props from './props.js'; | ||
| 66 | + /** | ||
| 67 | + * Alert 警告提示 | ||
| 68 | + * @description 警告提示,展现需要关注的信息。 | ||
| 69 | + * @tutorial https://www.uvui.cn/components/alertTips.html | ||
| 70 | + * | ||
| 71 | + * @property {String} title 显示的文字 | ||
| 72 | + * @property {String} type 使用预设的颜色 (默认 'warning' ) | ||
| 73 | + * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选 | ||
| 74 | + * @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false ) | ||
| 75 | + * @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false ) | ||
| 76 | + * @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' ) | ||
| 77 | + * @property {Boolean} center 文字是否居中 (默认 false ) | ||
| 78 | + * @property {String | Number} fontSize 字体大小 (默认 14 ) | ||
| 79 | + * @property {Object} customStyle 定义需要用到的外部样式 | ||
| 80 | + * @event {Function} click 点击组件时触发 | ||
| 81 | + * @example <uv-alert :title="title" type = "warning" :closable="closable" :description = "description"></uv-alert> | ||
| 82 | + */ | ||
| 83 | + export default { | ||
| 84 | + name: 'uv-alert', | ||
| 85 | + mixins: [mpMixin, mixin, props], | ||
| 86 | + emits: ['click'], | ||
| 87 | + data() { | ||
| 88 | + return { | ||
| 89 | + show: true | ||
| 90 | + } | ||
| 91 | + }, | ||
| 92 | + computed: { | ||
| 93 | + iconColor() { | ||
| 94 | + return this.effect === 'light' ? this.type : '#fff' | ||
| 95 | + }, | ||
| 96 | + // 不同主题对应不同的图标 | ||
| 97 | + iconName() { | ||
| 98 | + switch (this.type) { | ||
| 99 | + case 'success': | ||
| 100 | + return 'checkmark-circle-fill'; | ||
| 101 | + break; | ||
| 102 | + case 'error': | ||
| 103 | + return 'close-circle-fill'; | ||
| 104 | + break; | ||
| 105 | + case 'warning': | ||
| 106 | + return 'error-circle-fill'; | ||
| 107 | + break; | ||
| 108 | + case 'info': | ||
| 109 | + return 'info-circle-fill'; | ||
| 110 | + break; | ||
| 111 | + case 'primary': | ||
| 112 | + return 'more-circle-fill'; | ||
| 113 | + break; | ||
| 114 | + default: | ||
| 115 | + return 'error-circle-fill'; | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + }, | ||
| 119 | + methods: { | ||
| 120 | + // 点击内容 | ||
| 121 | + clickHandler() { | ||
| 122 | + this.$emit('click') | ||
| 123 | + }, | ||
| 124 | + // 点击关闭按钮 | ||
| 125 | + closeHandler() { | ||
| 126 | + this.show = false | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | +</script> | ||
| 131 | + | ||
| 132 | +<style lang="scss" scoped> | ||
| 133 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 134 | + @import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 135 | + .uv-alert { | ||
| 136 | + position: relative; | ||
| 137 | + background-color: $uv-primary; | ||
| 138 | + padding: 8px 10px; | ||
| 139 | + @include flex(row); | ||
| 140 | + align-items: center; | ||
| 141 | + border-top-left-radius: 4px; | ||
| 142 | + border-top-right-radius: 4px; | ||
| 143 | + border-bottom-left-radius: 4px; | ||
| 144 | + border-bottom-right-radius: 4px; | ||
| 145 | + | ||
| 146 | + &--primary--dark { | ||
| 147 | + background-color: $uv-primary; | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + &--primary--light { | ||
| 151 | + background-color: #ecf5ff; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + &--error--dark { | ||
| 155 | + background-color: $uv-error; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + &--error--light { | ||
| 159 | + background-color: #FEF0F0; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + &--success--dark { | ||
| 163 | + background-color: $uv-success; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + &--success--light { | ||
| 167 | + background-color: #f5fff0; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + &--warning--dark { | ||
| 171 | + background-color: $uv-warning; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + &--warning--light { | ||
| 175 | + background-color: #FDF6EC; | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + &--info--dark { | ||
| 179 | + background-color: $uv-info; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + &--info--light { | ||
| 183 | + background-color: #f4f4f5; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + &__icon { | ||
| 187 | + margin-right: 5px; | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + &__content { | ||
| 191 | + @include flex(column); | ||
| 192 | + flex: 1; | ||
| 193 | + | ||
| 194 | + &__title { | ||
| 195 | + color: $uv-main-color; | ||
| 196 | + font-size: 14px; | ||
| 197 | + font-weight: bold; | ||
| 198 | + color: #fff; | ||
| 199 | + margin-bottom: 2px; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + &__desc { | ||
| 203 | + color: $uv-main-color; | ||
| 204 | + font-size: 14px; | ||
| 205 | + flex-wrap: wrap; | ||
| 206 | + color: #fff; | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + &__title--dark, | ||
| 211 | + &__desc--dark { | ||
| 212 | + color: #FFFFFF; | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + &__text--primary--light, | ||
| 216 | + &__text--primary--light { | ||
| 217 | + color: $uv-primary; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + &__text--success--light, | ||
| 221 | + &__text--success--light { | ||
| 222 | + color: $uv-success; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + &__text--warning--light, | ||
| 226 | + &__text--warning--light { | ||
| 227 | + color: $uv-warning; | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + &__text--error--light, | ||
| 231 | + &__text--error--light { | ||
| 232 | + color: $uv-error; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + &__text--info--light, | ||
| 236 | + &__text--info--light { | ||
| 237 | + color: $uv-info; | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + &__close { | ||
| 241 | + position: absolute; | ||
| 242 | + top: 11px; | ||
| 243 | + right: 10px; | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | +</style> |
uni_modules/uv-alert/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-alert", | ||
| 3 | + "displayName": "uv-alert 警告提示 全面兼容小程序、nvue、vue2、vue3等多端", | ||
| 4 | + "version": "1.0.2", | ||
| 5 | + "description": "uv-alert 警告提示,展现需要关注的信息。灵活配置,功能齐全,兼容全端", | ||
| 6 | + "keywords": [ | ||
| 7 | + "alert", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "警告提示" | ||
| 11 | + ], | ||
| 12 | + "repository": "", | ||
| 13 | + "engines": { | ||
| 14 | + "HBuilderX": "^3.1.0" | ||
| 15 | + }, | ||
| 16 | + "dcloudext": { | ||
| 17 | + "type": "component-vue", | ||
| 18 | + "sale": { | ||
| 19 | + "regular": { | ||
| 20 | + "price": "0.00" | ||
| 21 | + }, | ||
| 22 | + "sourcecode": { | ||
| 23 | + "price": "0.00" | ||
| 24 | + } | ||
| 25 | + }, | ||
| 26 | + "contact": { | ||
| 27 | + "qq": "" | ||
| 28 | + }, | ||
| 29 | + "declaration": { | ||
| 30 | + "ads": "无", | ||
| 31 | + "data": "插件不采集任何数据", | ||
| 32 | + "permissions": "无" | ||
| 33 | + }, | ||
| 34 | + "npmurl": "" | ||
| 35 | + }, | ||
| 36 | + "uni_modules": { | ||
| 37 | + "dependencies": [ | ||
| 38 | + "uv-ui-tools", | ||
| 39 | + "uv-transition", | ||
| 40 | + "uv-icon" | ||
| 41 | + ], | ||
| 42 | + "encrypt": [], | ||
| 43 | + "platforms": { | ||
| 44 | + "cloud": { | ||
| 45 | + "tcb": "y", | ||
| 46 | + "aliyun": "y" | ||
| 47 | + }, | ||
| 48 | + "client": { | ||
| 49 | + "Vue": { | ||
| 50 | + "vue2": "y", | ||
| 51 | + "vue3": "y" | ||
| 52 | + }, | ||
| 53 | + "App": { | ||
| 54 | + "app-vue": "y", | ||
| 55 | + "app-nvue": "y" | ||
| 56 | + }, | ||
| 57 | + "H5-mobile": { | ||
| 58 | + "Safari": "y", | ||
| 59 | + "Android Browser": "y", | ||
| 60 | + "微信浏览器(Android)": "y", | ||
| 61 | + "QQ浏览器(Android)": "y" | ||
| 62 | + }, | ||
| 63 | + "H5-pc": { | ||
| 64 | + "Chrome": "y", | ||
| 65 | + "IE": "y", | ||
| 66 | + "Edge": "y", | ||
| 67 | + "Firefox": "y", | ||
| 68 | + "Safari": "y" | ||
| 69 | + }, | ||
| 70 | + "小程序": { | ||
| 71 | + "微信": "y", | ||
| 72 | + "阿里": "y", | ||
| 73 | + "百度": "y", | ||
| 74 | + "字节跳动": "y", | ||
| 75 | + "QQ": "y", | ||
| 76 | + "钉钉": "u", | ||
| 77 | + "快手": "u", | ||
| 78 | + "飞书": "u", | ||
| 79 | + "京东": "u" | ||
| 80 | + }, | ||
| 81 | + "快应用": { | ||
| 82 | + "华为": "u", | ||
| 83 | + "联盟": "u" | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | +} |
uni_modules/uv-alert/readme.md
0 → 100644
| 1 | +## Alert 警告提示 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-alert** | ||
| 4 | + | ||
| 5 | +警告提示,展现需要关注的信息。 | ||
| 6 | + | ||
| 7 | +当某个页面需要向用户显示警告的信息时。 | ||
| 8 | + | ||
| 9 | +非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。 | ||
| 10 | + | ||
| 11 | +### <a href="https://www.uvui.cn/components/alert.html" target="_blank">查看文档</a> | ||
| 12 | + | ||
| 13 | +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 14 | + | ||
| 15 | +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-avatar/changelog.md
0 → 100644
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 头像图片组 | ||
| 4 | + urls: { | ||
| 5 | + type: Array, | ||
| 6 | + default: () => [] | ||
| 7 | + }, | ||
| 8 | + // 最多展示的头像数量 | ||
| 9 | + maxCount: { | ||
| 10 | + type: [String, Number], | ||
| 11 | + default: 5 | ||
| 12 | + }, | ||
| 13 | + // 头像形状 | ||
| 14 | + shape: { | ||
| 15 | + type: String, | ||
| 16 | + default: 'circle' | ||
| 17 | + }, | ||
| 18 | + // 图片裁剪模式 | ||
| 19 | + mode: { | ||
| 20 | + type: String, | ||
| 21 | + default: 'scaleToFill' | ||
| 22 | + }, | ||
| 23 | + // 超出maxCount时是否显示查看更多的提示 | ||
| 24 | + showMore: { | ||
| 25 | + type: Boolean, | ||
| 26 | + default: true | ||
| 27 | + }, | ||
| 28 | + // 头像大小 | ||
| 29 | + size: { | ||
| 30 | + type: [String, Number], | ||
| 31 | + default: 40 | ||
| 32 | + }, | ||
| 33 | + // 指定从数组的对象元素中读取哪个属性作为图片地址 | ||
| 34 | + keyName: { | ||
| 35 | + type: String, | ||
| 36 | + default: '' | ||
| 37 | + }, | ||
| 38 | + // 头像之间的遮挡比例 | ||
| 39 | + gap: { | ||
| 40 | + type: [String, Number], | ||
| 41 | + validator(value) { | ||
| 42 | + return value >= 0 && value <= 1 | ||
| 43 | + }, | ||
| 44 | + default: 0.5 | ||
| 45 | + }, | ||
| 46 | + // 需额外显示的值 | ||
| 47 | + extraValue: { | ||
| 48 | + type: [Number, String], | ||
| 49 | + default: 0 | ||
| 50 | + }, | ||
| 51 | + ...uni.$uv?.props?.avatarGroup | ||
| 52 | + } | ||
| 53 | +} |
| 1 | +<template> | ||
| 2 | + <view class="uv-avatar-group"> | ||
| 3 | + <view | ||
| 4 | + class="uv-avatar-group__item" | ||
| 5 | + v-for="(item, index) in showUrl" | ||
| 6 | + :key="index" | ||
| 7 | + :style="{ | ||
| 8 | + marginLeft: index === 0 ? 0 : $uv.addUnit(-size * gap) | ||
| 9 | + }" | ||
| 10 | + > | ||
| 11 | + <uv-avatar | ||
| 12 | + :size="size" | ||
| 13 | + :shape="shape" | ||
| 14 | + :mode="mode" | ||
| 15 | + :src="$uv.test.object(item) ? keyName && item[keyName] || item.url : item" | ||
| 16 | + ></uv-avatar> | ||
| 17 | + <view | ||
| 18 | + class="uv-avatar-group__item__show-more" | ||
| 19 | + v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)" | ||
| 20 | + @tap="clickHandler" | ||
| 21 | + > | ||
| 22 | + <uv-text | ||
| 23 | + color="#ffffff" | ||
| 24 | + :size="size * 0.4" | ||
| 25 | + :text="`+${extraValue || urls.length - showUrl.length}`" | ||
| 26 | + align="center" | ||
| 27 | + customStyle="justify-content: center" | ||
| 28 | + ></uv-text> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + </view> | ||
| 32 | +</template> | ||
| 33 | + | ||
| 34 | +<script> | ||
| 35 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 36 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 37 | + import props from './props.js'; | ||
| 38 | + /** | ||
| 39 | + * AvatarGroup 头像组 | ||
| 40 | + * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 | ||
| 41 | + * @tutorial https://www.uvui.cn/components/avatar.html | ||
| 42 | + * | ||
| 43 | + * @property {Array} urls 头像图片组 (默认 [] ) | ||
| 44 | + * @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 ) | ||
| 45 | + * @property {String} shape 头像形状( 'circle' (默认) | 'square' ) | ||
| 46 | + * @property {String} mode 图片裁剪模式(默认 'scaleToFill' ) | ||
| 47 | + * @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true ) | ||
| 48 | + * @property {String | Number} size 头像大小 (默认 40 ) | ||
| 49 | + * @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址 | ||
| 50 | + * @property {String | Number} gap 头像之间的遮挡比例(0.4代表遮挡40%) (默认 0.5 ) | ||
| 51 | + * @property {String | Number} extraValue 需额外显示的值 | ||
| 52 | + * @event {Function} showMore 头像组更多点击 | ||
| 53 | + * @example <uv-avatar-group:urls="urls" size="35" gap="0.4" ></uv-avatar-group:urls=> | ||
| 54 | + */ | ||
| 55 | + export default { | ||
| 56 | + name: 'uv-avatar-group', | ||
| 57 | + mixins: [mpMixin, mixin, props], | ||
| 58 | + data() { | ||
| 59 | + return { | ||
| 60 | + | ||
| 61 | + } | ||
| 62 | + }, | ||
| 63 | + computed: { | ||
| 64 | + showUrl() { | ||
| 65 | + return this.urls.slice(0, this.maxCount) | ||
| 66 | + } | ||
| 67 | + }, | ||
| 68 | + methods: { | ||
| 69 | + clickHandler() { | ||
| 70 | + this.$emit('showMore') | ||
| 71 | + } | ||
| 72 | + }, | ||
| 73 | + } | ||
| 74 | +</script> | ||
| 75 | + | ||
| 76 | +<style lang="scss" scoped> | ||
| 77 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 78 | + @import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 79 | + | ||
| 80 | + .uv-avatar-group { | ||
| 81 | + @include flex; | ||
| 82 | + | ||
| 83 | + &__item { | ||
| 84 | + margin-left: -10px; | ||
| 85 | + position: relative; | ||
| 86 | + | ||
| 87 | + &--no-indent { | ||
| 88 | + // 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持 | ||
| 89 | + margin-left: 0; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + &__show-more { | ||
| 93 | + position: absolute; | ||
| 94 | + top: 0; | ||
| 95 | + bottom: 0; | ||
| 96 | + left: 0; | ||
| 97 | + right: 0; | ||
| 98 | + background-color: rgba(0, 0, 0, 0.3); | ||
| 99 | + @include flex; | ||
| 100 | + align-items: center; | ||
| 101 | + justify-content: center; | ||
| 102 | + border-radius: 100px; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | +</style> |
| 1 | +import { range } from '@/uni_modules/uv-ui-tools/libs/function/test.js' | ||
| 2 | +export default { | ||
| 3 | + props: { | ||
| 4 | + // 头像图片路径(不能为相对路径) | ||
| 5 | + src: { | ||
| 6 | + type: String, | ||
| 7 | + default: '' | ||
| 8 | + }, | ||
| 9 | + // 头像形状,circle-圆形,square-方形 | ||
| 10 | + shape: { | ||
| 11 | + type: String, | ||
| 12 | + default: 'circle' | ||
| 13 | + }, | ||
| 14 | + // 头像尺寸 | ||
| 15 | + size: { | ||
| 16 | + type: [String, Number], | ||
| 17 | + default: 40 | ||
| 18 | + }, | ||
| 19 | + // 裁剪模式 | ||
| 20 | + mode: { | ||
| 21 | + type: String, | ||
| 22 | + default: 'scaleToFill' | ||
| 23 | + }, | ||
| 24 | + // 显示的文字 | ||
| 25 | + text: { | ||
| 26 | + type: String, | ||
| 27 | + default: '' | ||
| 28 | + }, | ||
| 29 | + // 背景色 | ||
| 30 | + bgColor: { | ||
| 31 | + type: String, | ||
| 32 | + default: '#c0c4cc' | ||
| 33 | + }, | ||
| 34 | + // 文字颜色 | ||
| 35 | + color: { | ||
| 36 | + type: String, | ||
| 37 | + default: '#fff' | ||
| 38 | + }, | ||
| 39 | + // 文字大小 | ||
| 40 | + fontSize: { | ||
| 41 | + type: [String, Number], | ||
| 42 | + default: 18 | ||
| 43 | + }, | ||
| 44 | + // 显示的图标 | ||
| 45 | + icon: { | ||
| 46 | + type: String, | ||
| 47 | + default: '' | ||
| 48 | + }, | ||
| 49 | + // 显示小程序头像,只对百度,微信,QQ小程序有效 | ||
| 50 | + mpAvatar: { | ||
| 51 | + type: Boolean, | ||
| 52 | + default: false | ||
| 53 | + }, | ||
| 54 | + // 是否使用随机背景色 | ||
| 55 | + randomBgColor: { | ||
| 56 | + type: Boolean, | ||
| 57 | + default: false | ||
| 58 | + }, | ||
| 59 | + // 加载失败的默认头像(组件有内置默认图片) | ||
| 60 | + defaultUrl: { | ||
| 61 | + type: String, | ||
| 62 | + default: '' | ||
| 63 | + }, | ||
| 64 | + // 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间 | ||
| 65 | + colorIndex: { | ||
| 66 | + type: [String, Number], | ||
| 67 | + // 校验参数规则,索引在0-19之间 | ||
| 68 | + validator(n) { | ||
| 69 | + return range(n, [0, 19]) || n === '' | ||
| 70 | + }, | ||
| 71 | + default: '' | ||
| 72 | + }, | ||
| 73 | + // 组件标识符 | ||
| 74 | + name: { | ||
| 75 | + type: String, | ||
| 76 | + default: '' | ||
| 77 | + }, | ||
| 78 | + ...uni.$uv?.props?.avatar | ||
| 79 | + } | ||
| 80 | +} |
| 1 | +<template> | ||
| 2 | + <view | ||
| 3 | + class="uv-avatar" | ||
| 4 | + :class="[`uv-avatar--${shape}`]" | ||
| 5 | + :style="[{ | ||
| 6 | + backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $uv.random(0, 19)] : bgColor) : 'transparent', | ||
| 7 | + width: $uv.addUnit(size), | ||
| 8 | + height: $uv.addUnit(size), | ||
| 9 | + }, $uv.addStyle(customStyle)]" | ||
| 10 | + @tap="clickHandler" | ||
| 11 | + > | ||
| 12 | + <slot> | ||
| 13 | + <!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU --> | ||
| 14 | + <open-data | ||
| 15 | + v-if="mpAvatar && allowMp" | ||
| 16 | + type="userAvatarUrl" | ||
| 17 | + :style="[{ | ||
| 18 | + width: $uv.addUnit(size), | ||
| 19 | + height: $uv.addUnit(size) | ||
| 20 | + }]" | ||
| 21 | + /> | ||
| 22 | + <!-- #endif --> | ||
| 23 | + <!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU --> | ||
| 24 | + <template v-if="mpAvatar && allowMp"></template> | ||
| 25 | + <!-- #endif --> | ||
| 26 | + <uv-icon | ||
| 27 | + v-else-if="icon" | ||
| 28 | + :name="icon" | ||
| 29 | + :size="fontSize" | ||
| 30 | + :color="color" | ||
| 31 | + ></uv-icon> | ||
| 32 | + <uv-text | ||
| 33 | + v-else-if="text" | ||
| 34 | + :text="text" | ||
| 35 | + :size="fontSize" | ||
| 36 | + :color="color" | ||
| 37 | + align="center" | ||
| 38 | + customStyle="justify-content: center" | ||
| 39 | + ></uv-text> | ||
| 40 | + <image | ||
| 41 | + class="uv-avatar__image" | ||
| 42 | + v-else | ||
| 43 | + :class="[`uv-avatar__image--${shape}`]" | ||
| 44 | + :src="avatarUrl || defaultUrl" | ||
| 45 | + :mode="mode" | ||
| 46 | + @error="errorHandler" | ||
| 47 | + :style="[{ | ||
| 48 | + width: $uv.addUnit(size), | ||
| 49 | + height: $uv.addUnit(size) | ||
| 50 | + }]" | ||
| 51 | + ></image> | ||
| 52 | + </slot> | ||
| 53 | + </view> | ||
| 54 | +</template> | ||
| 55 | + | ||
| 56 | +<script> | ||
| 57 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 58 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 59 | + import props from './props.js'; | ||
| 60 | + const base64Avatar = | ||
| 61 | + "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z"; | ||
| 62 | + /** | ||
| 63 | + * Avatar 头像 | ||
| 64 | + * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 | ||
| 65 | + * @tutorial https://www.uvui.cn/components/avatar.html | ||
| 66 | + * | ||
| 67 | + * @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径) | ||
| 68 | + * @property {String} shape 头像形状 ( circle (默认) | square) | ||
| 69 | + * @property {String | Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 ) | ||
| 70 | + * @property {String} mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' ) | ||
| 71 | + * @property {String} text 用文字替代图片,级别优先于src | ||
| 72 | + * @property {String} bgColor 背景颜色,一般显示文字时用 (默认 '#c0c4cc' ) | ||
| 73 | + * @property {String} color 文字颜色 (默认 '#ffffff' ) | ||
| 74 | + * @property {String | Number} fontSize 文字大小 (默认 18 ) | ||
| 75 | + * @property {String} icon 显示的图标 | ||
| 76 | + * @property {Boolean} mpAvatar 显示小程序头像,只对百度,微信,QQ小程序有效 (默认 false ) | ||
| 77 | + * @property {Boolean} randomBgColor 是否使用随机背景色 (默认 false ) | ||
| 78 | + * @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片) | ||
| 79 | + * @property {String | Number} colorIndex 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间 | ||
| 80 | + * @property {String} name 组件标识符 (默认 'level' ) | ||
| 81 | + * @property {Object} customStyle 定义需要用到的外部样式 | ||
| 82 | + * | ||
| 83 | + * @event {Function} click 点击组件时触发 index: 用户传递的标识符 | ||
| 84 | + * @example <uv-avatar :src="src" mode="square"></uv-avatar> | ||
| 85 | + */ | ||
| 86 | + export default { | ||
| 87 | + name: 'uv-avatar', | ||
| 88 | + emits: ['click'], | ||
| 89 | + mixins: [mpMixin, mixin, props], | ||
| 90 | + data() { | ||
| 91 | + return { | ||
| 92 | + // 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色 | ||
| 93 | + colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2', | ||
| 94 | + '#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee', | ||
| 95 | + '#73d1f1', | ||
| 96 | + '#80a7dc' | ||
| 97 | + ], | ||
| 98 | + avatarUrl: this.src, | ||
| 99 | + allowMp: false | ||
| 100 | + } | ||
| 101 | + }, | ||
| 102 | + watch: { | ||
| 103 | + // 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值 | ||
| 104 | + // 而组件内部不能直接修改props的值,所以需要一个中间变量 | ||
| 105 | + src: { | ||
| 106 | + immediate: true, | ||
| 107 | + handler(newVal) { | ||
| 108 | + this.avatarUrl = newVal | ||
| 109 | + // 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示 | ||
| 110 | + if(!newVal) { | ||
| 111 | + this.errorHandler() | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + }, | ||
| 116 | + computed: { | ||
| 117 | + imageStyle() { | ||
| 118 | + const style = {} | ||
| 119 | + return style | ||
| 120 | + } | ||
| 121 | + }, | ||
| 122 | + created() { | ||
| 123 | + this.init() | ||
| 124 | + }, | ||
| 125 | + methods: { | ||
| 126 | + init() { | ||
| 127 | + // 目前只有这几个小程序平台具有open-data标签 | ||
| 128 | + // 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑 | ||
| 129 | + // 故目前自动获取小程序头像只支持这几个平台 | ||
| 130 | + // #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU | ||
| 131 | + this.allowMp = true | ||
| 132 | + // #endif | ||
| 133 | + }, | ||
| 134 | + // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式 | ||
| 135 | + isImg() { | ||
| 136 | + return this.src.indexOf('/') !== -1 | ||
| 137 | + }, | ||
| 138 | + // 图片加载时失败时触发 | ||
| 139 | + errorHandler() { | ||
| 140 | + this.avatarUrl = this.defaultUrl || base64Avatar | ||
| 141 | + }, | ||
| 142 | + clickHandler() { | ||
| 143 | + this.$emit('click', this.name) | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | +</script> | ||
| 148 | + | ||
| 149 | +<style lang="scss" scoped> | ||
| 150 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 151 | + | ||
| 152 | + .uv-avatar { | ||
| 153 | + @include flex; | ||
| 154 | + align-items: center; | ||
| 155 | + justify-content: center; | ||
| 156 | + | ||
| 157 | + &--circle { | ||
| 158 | + border-radius: 100px; | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + &--square { | ||
| 162 | + border-radius: 4px; | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + &__image { | ||
| 166 | + &--circle { | ||
| 167 | + border-radius: 100px; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + &--square { | ||
| 171 | + border-radius: 4px; | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + } | ||
| 175 | +</style> |
uni_modules/uv-avatar/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-avatar", | ||
| 3 | + "displayName": "uv-avatar 头像 全面兼容小程序、nvue、vue2、vue3等多端", | ||
| 4 | + "version": "1.0.5", | ||
| 5 | + "description": "uv-avatar 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。", | ||
| 6 | + "keywords": [ | ||
| 7 | + "uv-avatar", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "avatar", | ||
| 11 | + "头像" | ||
| 12 | + ], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools", | ||
| 40 | + "uv-icon", | ||
| 41 | + "uv-text" | ||
| 42 | + ], | ||
| 43 | + "encrypt": [], | ||
| 44 | + "platforms": { | ||
| 45 | + "cloud": { | ||
| 46 | + "tcb": "y", | ||
| 47 | + "aliyun": "y" | ||
| 48 | + }, | ||
| 49 | + "client": { | ||
| 50 | + "Vue": { | ||
| 51 | + "vue2": "y", | ||
| 52 | + "vue3": "y" | ||
| 53 | + }, | ||
| 54 | + "App": { | ||
| 55 | + "app-vue": "y", | ||
| 56 | + "app-nvue": "y" | ||
| 57 | + }, | ||
| 58 | + "H5-mobile": { | ||
| 59 | + "Safari": "y", | ||
| 60 | + "Android Browser": "y", | ||
| 61 | + "微信浏览器(Android)": "y", | ||
| 62 | + "QQ浏览器(Android)": "y" | ||
| 63 | + }, | ||
| 64 | + "H5-pc": { | ||
| 65 | + "Chrome": "y", | ||
| 66 | + "IE": "y", | ||
| 67 | + "Edge": "y", | ||
| 68 | + "Firefox": "y", | ||
| 69 | + "Safari": "y" | ||
| 70 | + }, | ||
| 71 | + "小程序": { | ||
| 72 | + "微信": "y", | ||
| 73 | + "阿里": "y", | ||
| 74 | + "百度": "y", | ||
| 75 | + "字节跳动": "y", | ||
| 76 | + "QQ": "y", | ||
| 77 | + "钉钉": "u", | ||
| 78 | + "快手": "u", | ||
| 79 | + "飞书": "u", | ||
| 80 | + "京东": "u" | ||
| 81 | + }, | ||
| 82 | + "快应用": { | ||
| 83 | + "华为": "u", | ||
| 84 | + "联盟": "u" | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | +} |
uni_modules/uv-avatar/readme.md
0 → 100644
| 1 | +## Avatar 头像 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-avatar** | ||
| 4 | + | ||
| 5 | +本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 | ||
| 6 | + | ||
| 7 | +### <a href="https://www.uvui.cn/components/avatar.html" target="_blank">查看文档</a> | ||
| 8 | + | ||
| 9 | +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 10 | + | ||
| 11 | +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-back-top/changelog.md
0 → 100644
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 返回顶部的形状,circle-圆形,square-方形 | ||
| 4 | + mode: { | ||
| 5 | + type: String, | ||
| 6 | + default: 'circle' | ||
| 7 | + }, | ||
| 8 | + // 自定义图标 | ||
| 9 | + icon: { | ||
| 10 | + type: String, | ||
| 11 | + default: 'arrow-upward' | ||
| 12 | + }, | ||
| 13 | + // 提示文字 | ||
| 14 | + text: { | ||
| 15 | + type: String, | ||
| 16 | + default: '' | ||
| 17 | + }, | ||
| 18 | + // 返回顶部滚动时间 | ||
| 19 | + duration: { | ||
| 20 | + type: [String, Number], | ||
| 21 | + default: 100 | ||
| 22 | + }, | ||
| 23 | + // 滚动距离 | ||
| 24 | + scrollTop: { | ||
| 25 | + type: [String, Number], | ||
| 26 | + default: 0 | ||
| 27 | + }, | ||
| 28 | + // 距离顶部多少距离显示,单位px | ||
| 29 | + top: { | ||
| 30 | + type: [String, Number], | ||
| 31 | + default: 400 | ||
| 32 | + }, | ||
| 33 | + // 返回顶部按钮到底部的距离,单位px | ||
| 34 | + bottom: { | ||
| 35 | + type: [String, Number], | ||
| 36 | + default: 100 | ||
| 37 | + }, | ||
| 38 | + // 返回顶部按钮到右边的距离,单位px | ||
| 39 | + right: { | ||
| 40 | + type: [String, Number], | ||
| 41 | + default: 20 | ||
| 42 | + }, | ||
| 43 | + // 层级 | ||
| 44 | + zIndex: { | ||
| 45 | + type: [String, Number], | ||
| 46 | + default: 9 | ||
| 47 | + }, | ||
| 48 | + // 图标的样式,对象形式 | ||
| 49 | + iconStyle: { | ||
| 50 | + type: Object, | ||
| 51 | + default: () => ({ | ||
| 52 | + color: '#909399', | ||
| 53 | + fontSize: '19px' | ||
| 54 | + }) | ||
| 55 | + }, | ||
| 56 | + ...uni.$uv?.props?.backtop | ||
| 57 | + } | ||
| 58 | +} |
| 1 | +<template> | ||
| 2 | + <uv-transition mode="fade" :customStyle="backTopStyle" :show="show"> | ||
| 3 | + <slot> | ||
| 4 | + <view class="uv-back-top" :style="[contentStyle]" @click="backToTop"> | ||
| 5 | + <uv-icon :name="icon" :custom-style="iconStyle"></uv-icon> | ||
| 6 | + <text v-if="text" class="uv-back-top__text">{{text}}</text> | ||
| 7 | + </view> | ||
| 8 | + </slot> | ||
| 9 | + </uv-transition> | ||
| 10 | +</template> | ||
| 11 | + | ||
| 12 | +<script> | ||
| 13 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 14 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 15 | + import props from './props.js'; | ||
| 16 | + // #ifdef APP-NVUE | ||
| 17 | + const dom = weex.requireModule('dom') | ||
| 18 | + // #endif | ||
| 19 | + /** | ||
| 20 | + * backTop 返回顶部 | ||
| 21 | + * @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。 | ||
| 22 | + * @tutorial https://www.uvui.cn/components/backTop.html | ||
| 23 | + * @property {String} mode 返回顶部的形状,circle-圆形,square-方形 (默认 'circle' ) | ||
| 24 | + * @property {String} icon 自定义图标 (默认 'arrow-upward' ) 见官方文档示例 | ||
| 25 | + * @property {String} text 提示文字 | ||
| 26 | + * @property {String | Number} duration 返回顶部滚动时间 (默认 100) | ||
| 27 | + * @property {String | Number} scrollTop 滚动距离 (默认 0 ) | ||
| 28 | + * @property {String | Number} top 距离顶部多少距离显示,单位px (默认 400 ) | ||
| 29 | + * @property {String | Number} bottom 返回顶部按钮到底部的距离,单位px (默认 100 ) | ||
| 30 | + * @property {String | Number} right 返回顶部按钮到右边的距离,单位px (默认 20 ) | ||
| 31 | + * @property {String | Number} zIndex 层级 (默认 9 ) | ||
| 32 | + * @property {Object<Object>} iconStyle 图标的样式,对象形式 (默认 {color: '#909399',fontSize: '19px'}) | ||
| 33 | + * @property {Object} customStyle 定义需要用到的外部样式 | ||
| 34 | + * | ||
| 35 | + * @example <uv-back-top :scrollTop="scrollTop"></uv-back-top> | ||
| 36 | + */ | ||
| 37 | + export default { | ||
| 38 | + name: 'uv-back-top', | ||
| 39 | + emits: ['click'], | ||
| 40 | + mixins: [mpMixin, mixin, props], | ||
| 41 | + computed: { | ||
| 42 | + backTopStyle() { | ||
| 43 | + // 动画组件样式 | ||
| 44 | + const style = { | ||
| 45 | + bottom: this.$uv.addUnit(this.bottom), | ||
| 46 | + right: this.$uv.addUnit(this.right), | ||
| 47 | + width: '40px', | ||
| 48 | + height: '40px', | ||
| 49 | + position: 'fixed', | ||
| 50 | + zIndex: 10, | ||
| 51 | + } | ||
| 52 | + return style | ||
| 53 | + }, | ||
| 54 | + show() { | ||
| 55 | + return this.$uv.getPx(this.scrollTop) > this.$uv.getPx(this.top) | ||
| 56 | + }, | ||
| 57 | + contentStyle() { | ||
| 58 | + const style = {} | ||
| 59 | + let radius = 0 | ||
| 60 | + // 是否圆形 | ||
| 61 | + if (this.mode === 'circle') { | ||
| 62 | + radius = '100px' | ||
| 63 | + } else { | ||
| 64 | + radius = '4px' | ||
| 65 | + } | ||
| 66 | + // 为了兼容安卓nvue,只能这么分开写 | ||
| 67 | + style.borderTopLeftRadius = radius | ||
| 68 | + style.borderTopRightRadius = radius | ||
| 69 | + style.borderBottomLeftRadius = radius | ||
| 70 | + style.borderBottomRightRadius = radius | ||
| 71 | + return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle)) | ||
| 72 | + } | ||
| 73 | + }, | ||
| 74 | + methods: { | ||
| 75 | + backToTop() { | ||
| 76 | + // #ifdef APP-NVUE | ||
| 77 | + if (!this.$parent.$refs['uv-back-top']) { | ||
| 78 | + this.$uv.error(`nvue页面需要给页面最外层元素设置"ref='uv-back-top'`) | ||
| 79 | + } | ||
| 80 | + dom.scrollToElement(this.$parent.$refs['uv-back-top'], { | ||
| 81 | + offset: 0 | ||
| 82 | + }) | ||
| 83 | + // #endif | ||
| 84 | + | ||
| 85 | + // #ifndef APP-NVUE | ||
| 86 | + uni.pageScrollTo({ | ||
| 87 | + scrollTop: 0, | ||
| 88 | + duration: this.duration | ||
| 89 | + }); | ||
| 90 | + // #endif | ||
| 91 | + this.$emit('click') | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | +</script> | ||
| 96 | + | ||
| 97 | +<style lang="scss" scoped> | ||
| 98 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 99 | + $uv-back-top-flex: 1 !default; | ||
| 100 | + $uv-back-top-height: 100% !default; | ||
| 101 | + $uv-back-top-background-color: #E1E1E1 !default; | ||
| 102 | + $uv-back-top-tips-font-size: 12px !default; | ||
| 103 | + .uv-back-top { | ||
| 104 | + @include flex; | ||
| 105 | + flex-direction: column; | ||
| 106 | + align-items: center; | ||
| 107 | + flex: $uv-back-top-flex; | ||
| 108 | + height: $uv-back-top-height; | ||
| 109 | + justify-content: center; | ||
| 110 | + background-color: $uv-back-top-background-color; | ||
| 111 | + &__tips { | ||
| 112 | + font-size: $uv-back-top-tips-font-size; | ||
| 113 | + transform: scale(0.8); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | +</style> |
uni_modules/uv-back-top/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-back-top", | ||
| 3 | + "displayName": "uv-back-top 返回顶部 全面兼容小程序、nvue、vue2、vue3等多端", | ||
| 4 | + "version": "1.0.2", | ||
| 5 | + "description": "返回顶部 组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。", | ||
| 6 | + "keywords": [ | ||
| 7 | + "uv-back-top", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "avatar", | ||
| 11 | + "返回顶部" | ||
| 12 | + ], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools", | ||
| 40 | + "uv-icon", | ||
| 41 | + "uv-transition" | ||
| 42 | + ], | ||
| 43 | + "encrypt": [], | ||
| 44 | + "platforms": { | ||
| 45 | + "cloud": { | ||
| 46 | + "tcb": "y", | ||
| 47 | + "aliyun": "y" | ||
| 48 | + }, | ||
| 49 | + "client": { | ||
| 50 | + "Vue": { | ||
| 51 | + "vue2": "y", | ||
| 52 | + "vue3": "y" | ||
| 53 | + }, | ||
| 54 | + "App": { | ||
| 55 | + "app-vue": "y", | ||
| 56 | + "app-nvue": "y" | ||
| 57 | + }, | ||
| 58 | + "H5-mobile": { | ||
| 59 | + "Safari": "y", | ||
| 60 | + "Android Browser": "y", | ||
| 61 | + "微信浏览器(Android)": "y", | ||
| 62 | + "QQ浏览器(Android)": "y" | ||
| 63 | + }, | ||
| 64 | + "H5-pc": { | ||
| 65 | + "Chrome": "y", | ||
| 66 | + "IE": "y", | ||
| 67 | + "Edge": "y", | ||
| 68 | + "Firefox": "y", | ||
| 69 | + "Safari": "y" | ||
| 70 | + }, | ||
| 71 | + "小程序": { | ||
| 72 | + "微信": "y", | ||
| 73 | + "阿里": "y", | ||
| 74 | + "百度": "y", | ||
| 75 | + "字节跳动": "y", | ||
| 76 | + "QQ": "y", | ||
| 77 | + "钉钉": "u", | ||
| 78 | + "快手": "u", | ||
| 79 | + "飞书": "u", | ||
| 80 | + "京东": "u" | ||
| 81 | + }, | ||
| 82 | + "快应用": { | ||
| 83 | + "华为": "u", | ||
| 84 | + "联盟": "u" | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | +} |
uni_modules/uv-back-top/readme.md
0 → 100644
| 1 | +## BackTop 返回顶部 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-back-top** | ||
| 4 | + | ||
| 5 | +该组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。 | ||
| 6 | + | ||
| 7 | +### <a href="https://www.uvui.cn/components/backTop.html" target="_blank">查看文档</a> | ||
| 8 | + | ||
| 9 | +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 10 | + | ||
| 11 | +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-badge/changelog.md
0 → 100644
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 是否显示圆点 | ||
| 4 | + isDot: { | ||
| 5 | + type: Boolean, | ||
| 6 | + default: false | ||
| 7 | + }, | ||
| 8 | + // 显示的内容 | ||
| 9 | + value: { | ||
| 10 | + type: [Number, String], | ||
| 11 | + default: '' | ||
| 12 | + }, | ||
| 13 | + // 是否显示 | ||
| 14 | + show: { | ||
| 15 | + type: Boolean, | ||
| 16 | + default: true | ||
| 17 | + }, | ||
| 18 | + // 最大值,超过最大值会显示 '{max}+' | ||
| 19 | + max: { | ||
| 20 | + type: [Number, String], | ||
| 21 | + default: 999 | ||
| 22 | + }, | ||
| 23 | + // 主题类型,error|warning|success|primary | ||
| 24 | + type: { | ||
| 25 | + type: [String,undefined,null], | ||
| 26 | + default: 'error' | ||
| 27 | + }, | ||
| 28 | + // 当数值为 0 时,是否展示 Badge | ||
| 29 | + showZero: { | ||
| 30 | + type: Boolean, | ||
| 31 | + default: false | ||
| 32 | + }, | ||
| 33 | + // 背景颜色,优先级比type高,如设置,type参数会失效 | ||
| 34 | + bgColor: { | ||
| 35 | + type: [String, null], | ||
| 36 | + default: null | ||
| 37 | + }, | ||
| 38 | + // 字体颜色 | ||
| 39 | + color: { | ||
| 40 | + type: [String, null], | ||
| 41 | + default: null | ||
| 42 | + }, | ||
| 43 | + // 徽标形状,circle-四角均为圆角,horn-左下角为直角 | ||
| 44 | + shape: { | ||
| 45 | + type: [String,undefined,null], | ||
| 46 | + default: 'circle' | ||
| 47 | + }, | ||
| 48 | + // 设置数字的显示方式,overflow|ellipsis|limit | ||
| 49 | + // overflow会根据max字段判断,超出显示`${max}+` | ||
| 50 | + // ellipsis会根据max判断,超出显示`${max}...` | ||
| 51 | + // limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数 | ||
| 52 | + numberType: { | ||
| 53 | + type: [String,undefined,null], | ||
| 54 | + default: 'overflow' | ||
| 55 | + }, | ||
| 56 | + // 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效 | ||
| 57 | + offset: { | ||
| 58 | + type: Array, | ||
| 59 | + default: () => [] | ||
| 60 | + }, | ||
| 61 | + // 是否反转背景和字体颜色 | ||
| 62 | + inverted: { | ||
| 63 | + type: Boolean, | ||
| 64 | + default: false | ||
| 65 | + }, | ||
| 66 | + // 是否绝对定位 | ||
| 67 | + absolute: { | ||
| 68 | + type: Boolean, | ||
| 69 | + default: false | ||
| 70 | + }, | ||
| 71 | + ...uni.$uv?.props?.badge | ||
| 72 | + } | ||
| 73 | +} |
| 1 | +<template> | ||
| 2 | + <text | ||
| 3 | + v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)" | ||
| 4 | + :class="[isDot ? 'uv-badge--dot' : 'uv-badge--not-dot', inverted && 'uv-badge--inverted', shape === 'horn' && 'uv-badge--horn', `uv-badge--${propsType}${inverted ? '--inverted' : ''}`]" | ||
| 5 | + :style="[$uv.addStyle(customStyle), badgeStyle]" | ||
| 6 | + class="uv-badge" | ||
| 7 | + >{{ isDot ? '' :showValue }}</text> | ||
| 8 | +</template> | ||
| 9 | + | ||
| 10 | +<script> | ||
| 11 | + import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 12 | + import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 13 | + import props from './props.js'; | ||
| 14 | + /** | ||
| 15 | + * badge 徽标数 | ||
| 16 | + * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。 | ||
| 17 | + * @tutorial https://www.uvui.cn/components/badge.html | ||
| 18 | + * | ||
| 19 | + * @property {Boolean} isDot 是否显示圆点 (默认 false ) | ||
| 20 | + * @property {String | Number} value 显示的内容 | ||
| 21 | + * @property {Boolean} show 是否显示 (默认 true ) | ||
| 22 | + * @property {String | Number} max 最大值,超过最大值会显示 '{max}+' (默认999) | ||
| 23 | + * @property {String} type 主题类型,error|warning|success|primary (默认 'error' ) | ||
| 24 | + * @property {Boolean} showZero 当数值为 0 时,是否展示 Badge (默认 false ) | ||
| 25 | + * @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效 | ||
| 26 | + * @property {String} color 字体颜色 (默认 '#ffffff' ) | ||
| 27 | + * @property {String} shape 徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' ) | ||
| 28 | + * @property {String} numberType 设置数字的显示方式,overflow|ellipsis|limit (默认 'overflow' ) | ||
| 29 | + * @property {Array}} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效 | ||
| 30 | + * @property {Boolean} inverted 是否反转背景和字体颜色(默认 false ) | ||
| 31 | + * @property {Boolean} absolute 是否绝对定位(默认 false ) | ||
| 32 | + * @property {Object} customStyle 定义需要用到的外部样式 | ||
| 33 | + * @example <uv-badge :type="type" :count="count"></uv-badge> | ||
| 34 | + */ | ||
| 35 | + export default { | ||
| 36 | + name: 'uv-badge', | ||
| 37 | + mixins: [mpMixin, mixin, props], | ||
| 38 | + computed: { | ||
| 39 | + // 是否将badge中心与父组件右上角重合 | ||
| 40 | + boxStyle() { | ||
| 41 | + let style = {}; | ||
| 42 | + return style; | ||
| 43 | + }, | ||
| 44 | + // 整个组件的样式 | ||
| 45 | + badgeStyle() { | ||
| 46 | + const style = {} | ||
| 47 | + if(this.color) { | ||
| 48 | + style.color = this.color | ||
| 49 | + } | ||
| 50 | + if (this.bgColor && !this.inverted) { | ||
| 51 | + style.backgroundColor = this.bgColor | ||
| 52 | + } | ||
| 53 | + if (this.absolute) { | ||
| 54 | + style.position = 'absolute' | ||
| 55 | + // 如果有设置offset参数 | ||
| 56 | + if(this.offset.length) { | ||
| 57 | + // top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top | ||
| 58 | + const top = this.offset[0] | ||
| 59 | + const right = this.offset[1] || top | ||
| 60 | + style.top = this.$uv.addUnit(top) | ||
| 61 | + style.right = this.$uv.addUnit(right) | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + return style | ||
| 65 | + }, | ||
| 66 | + showValue() { | ||
| 67 | + switch (this.numberType) { | ||
| 68 | + case "overflow": | ||
| 69 | + return Number(this.value) > Number(this.max) ? this.max + "+" : this.value | ||
| 70 | + break; | ||
| 71 | + case "ellipsis": | ||
| 72 | + return Number(this.value) > Number(this.max) ? "..." : this.value | ||
| 73 | + break; | ||
| 74 | + case "limit": | ||
| 75 | + return Number(this.value) > 999 ? Number(this.value) >= 9999 ? | ||
| 76 | + Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value / | ||
| 77 | + 1e3 * 100) / 100 + "k" : this.value | ||
| 78 | + break; | ||
| 79 | + default: | ||
| 80 | + return Number(this.value) | ||
| 81 | + } | ||
| 82 | + }, | ||
| 83 | + propsType(){ | ||
| 84 | + return this.type || 'error' | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | +</script> | ||
| 89 | + | ||
| 90 | +<style lang="scss" scoped> | ||
| 91 | + @import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 92 | + @import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 93 | + $uv-badge-primary: $uv-primary !default; | ||
| 94 | + $uv-badge-error: $uv-error !default; | ||
| 95 | + $uv-badge-success: $uv-success !default; | ||
| 96 | + $uv-badge-info: $uv-info !default; | ||
| 97 | + $uv-badge-warning: $uv-warning !default; | ||
| 98 | + $uv-badge-dot-radius: 100px !default; | ||
| 99 | + $uv-badge-dot-size: 8px !default; | ||
| 100 | + $uv-badge-dot-right: 4px !default; | ||
| 101 | + $uv-badge-dot-top: 0 !default; | ||
| 102 | + $uv-badge-text-font-size: 11px !default; | ||
| 103 | + $uv-badge-text-right: 10px !default; | ||
| 104 | + $uv-badge-text-padding: 2px 5px !default; | ||
| 105 | + $uv-badge-text-align: center !default; | ||
| 106 | + $uv-badge-text-color: #FFFFFF !default; | ||
| 107 | + | ||
| 108 | + .uv-badge { | ||
| 109 | + border-top-right-radius: $uv-badge-dot-radius; | ||
| 110 | + border-top-left-radius: $uv-badge-dot-radius; | ||
| 111 | + border-bottom-left-radius: $uv-badge-dot-radius; | ||
| 112 | + border-bottom-right-radius: $uv-badge-dot-radius; | ||
| 113 | + @include flex; | ||
| 114 | + line-height: $uv-badge-text-font-size; | ||
| 115 | + text-align: $uv-badge-text-align; | ||
| 116 | + font-size: $uv-badge-text-font-size; | ||
| 117 | + color: $uv-badge-text-color; | ||
| 118 | + | ||
| 119 | + &--dot { | ||
| 120 | + height: $uv-badge-dot-size; | ||
| 121 | + width: $uv-badge-dot-size; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + &--inverted { | ||
| 125 | + font-size: 13px; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + &--not-dot { | ||
| 129 | + padding: $uv-badge-text-padding; | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + &--horn { | ||
| 133 | + border-bottom-left-radius: 0; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + &--primary { | ||
| 137 | + background-color: $uv-badge-primary; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + &--primary--inverted { | ||
| 141 | + color: $uv-badge-primary; | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + &--error { | ||
| 145 | + background-color: $uv-badge-error; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + &--error--inverted { | ||
| 149 | + color: $uv-badge-error; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + &--success { | ||
| 153 | + background-color: $uv-badge-success; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + &--success--inverted { | ||
| 157 | + color: $uv-badge-success; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + &--info { | ||
| 161 | + background-color: $uv-badge-info; | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + &--info--inverted { | ||
| 165 | + color: $uv-badge-info; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + &--warning { | ||
| 169 | + background-color: $uv-badge-warning; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + &--warning--inverted { | ||
| 173 | + color: $uv-badge-warning; | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | +</style> |
uni_modules/uv-badge/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-badge", | ||
| 3 | + "displayName": "uv-badge 徽标数,数字角标 全面兼容小程序、nvue、vue2、vue3等多端", | ||
| 4 | + "version": "1.0.2", | ||
| 5 | + "description": "徽标数一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。", | ||
| 6 | + "keywords": [ | ||
| 7 | + "uv-badge", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "徽标数", | ||
| 11 | + "数字角标" | ||
| 12 | + ], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools" | ||
| 40 | + ], | ||
| 41 | + "encrypt": [], | ||
| 42 | + "platforms": { | ||
| 43 | + "cloud": { | ||
| 44 | + "tcb": "y", | ||
| 45 | + "aliyun": "y" | ||
| 46 | + }, | ||
| 47 | + "client": { | ||
| 48 | + "Vue": { | ||
| 49 | + "vue2": "y", | ||
| 50 | + "vue3": "y" | ||
| 51 | + }, | ||
| 52 | + "App": { | ||
| 53 | + "app-vue": "y", | ||
| 54 | + "app-nvue": "y" | ||
| 55 | + }, | ||
| 56 | + "H5-mobile": { | ||
| 57 | + "Safari": "y", | ||
| 58 | + "Android Browser": "y", | ||
| 59 | + "微信浏览器(Android)": "y", | ||
| 60 | + "QQ浏览器(Android)": "y" | ||
| 61 | + }, | ||
| 62 | + "H5-pc": { | ||
| 63 | + "Chrome": "y", | ||
| 64 | + "IE": "y", | ||
| 65 | + "Edge": "y", | ||
| 66 | + "Firefox": "y", | ||
| 67 | + "Safari": "y" | ||
| 68 | + }, | ||
| 69 | + "小程序": { | ||
| 70 | + "微信": "y", | ||
| 71 | + "阿里": "y", | ||
| 72 | + "百度": "y", | ||
| 73 | + "字节跳动": "y", | ||
| 74 | + "QQ": "y", | ||
| 75 | + "钉钉": "u", | ||
| 76 | + "快手": "u", | ||
| 77 | + "飞书": "u", | ||
| 78 | + "京东": "u" | ||
| 79 | + }, | ||
| 80 | + "快应用": { | ||
| 81 | + "华为": "u", | ||
| 82 | + "联盟": "u" | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | +} |
uni_modules/uv-badge/readme.md
0 → 100644
| 1 | +## Badge 徽标数 | ||
| 2 | + | ||
| 3 | +> **组件名:uv-badge** | ||
| 4 | + | ||
| 5 | +该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。 | ||
| 6 | + | ||
| 7 | +### <a href="https://www.uvui.cn/components/badge.html" target="_blank">查看文档</a> | ||
| 8 | + | ||
| 9 | +### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui) | ||
| 10 | + | ||
| 11 | +#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a> |
uni_modules/uv-button/changelog.md
0 → 100644
| 1 | +## 1.0.15(2023-12-20) | ||
| 2 | +1. 优化 | ||
| 3 | +## 1.0.14(2023-12-06) | ||
| 4 | +1. 优化 | ||
| 5 | +## 1.0.13(2023-12-06) | ||
| 6 | +1. 阻止事件冒泡处理 | ||
| 7 | +## 1.0.12(2023-10-19) | ||
| 8 | +1. 增加后置插槽 | ||
| 9 | +## 1.0.11(2023-09-21) | ||
| 10 | +1. 修复通过customStyle修改按钮宽度,组件中最外层节点不改变的问题 | ||
| 11 | +## 1.0.10(2023-09-15) | ||
| 12 | +1. 按钮支持open-type="agreePrivacyAuthorization" | ||
| 13 | +## 1.0.9(2023-09-11) | ||
| 14 | +1. 增加参数iconSize,用于控制图标的大小 | ||
| 15 | +## 1.0.8(2023-09-10) | ||
| 16 | +1. 修复多个按钮在一行宽度不正常的BUG | ||
| 17 | +## 1.0.7(2023-09-07) | ||
| 18 | +1. 修复warning颜色对应错误的BUG | ||
| 19 | +## 1.0.6(2023-07-25) | ||
| 20 | +1. 增加customTextStyle属性,方便自定义文字样式 | ||
| 21 | +## 1.0.5(2023-07-20) | ||
| 22 | +1. 解决微信小程序动态设置hover-class点击态不消失的BUG | ||
| 23 | +## 1.0.4(2023-06-29) | ||
| 24 | +1. 修改上次更新出现nvue报错异常 | ||
| 25 | +## 1.0.3(2023-06-28) | ||
| 26 | + 修复:设置open-type="chooseAvatar"等值不生效的BUG | ||
| 27 | +## 1.0.2(2023-06-01) | ||
| 28 | +1. 修复按钮点击触发两次的BUG | ||
| 29 | +## 1.0.1(2023-05-16) | ||
| 30 | +1. 优化组件依赖,修改后无需全局引入,组件导入即可使用 | ||
| 31 | +2. 优化部分功能 | ||
| 32 | +## 1.0.0(2023-05-10) | ||
| 33 | +uv-button 按钮 |
| 1 | +$uv-button-active-opacity:0.75 !default; | ||
| 2 | +$uv-button-loading-text-margin-left:4px !default; | ||
| 3 | +$uv-button-text-color: #FFFFFF !default; | ||
| 4 | +$uv-button-text-plain-error-color:$uv-error !default; | ||
| 5 | +$uv-button-text-plain-warning-color:$uv-warning !default; | ||
| 6 | +$uv-button-text-plain-success-color:$uv-success !default; | ||
| 7 | +$uv-button-text-plain-info-color:$uv-info !default; | ||
| 8 | +$uv-button-text-plain-primary-color:$uv-primary !default; | ||
| 9 | +.uv-button { | ||
| 10 | + &--active { | ||
| 11 | + opacity: $uv-button-active-opacity; | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + &--active--plain { | ||
| 15 | + background-color: rgb(217, 217, 217); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + &__loading-text { | ||
| 19 | + margin-left:$uv-button-loading-text-margin-left; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + &__text, | ||
| 23 | + &__loading-text { | ||
| 24 | + color:$uv-button-text-color; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + &__text--plain--error { | ||
| 28 | + color:$uv-button-text-plain-error-color; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + &__text--plain--warning { | ||
| 32 | + color:$uv-button-text-plain-warning-color; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + &__text--plain--success{ | ||
| 36 | + color:$uv-button-text-plain-success-color; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + &__text--plain--info { | ||
| 40 | + color:$uv-button-text-plain-info-color; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + &__text--plain--primary { | ||
| 44 | + color:$uv-button-text-plain-primary-color; | ||
| 45 | + } | ||
| 46 | +} |
| 1 | +export default { | ||
| 2 | + props: { | ||
| 3 | + // 是否细边框 | ||
| 4 | + hairline: { | ||
| 5 | + type: Boolean, | ||
| 6 | + default: true | ||
| 7 | + }, | ||
| 8 | + // 按钮的预置样式,info,primary,error,warning,success | ||
| 9 | + type: { | ||
| 10 | + type: String, | ||
| 11 | + default: 'info' | ||
| 12 | + }, | ||
| 13 | + // 按钮尺寸,large,normal,small,mini | ||
| 14 | + size: { | ||
| 15 | + type: String, | ||
| 16 | + default: 'normal' | ||
| 17 | + }, | ||
| 18 | + // 按钮形状,circle(两边为半圆),square(带圆角) | ||
| 19 | + shape: { | ||
| 20 | + type: String, | ||
| 21 | + default: 'square' | ||
| 22 | + }, | ||
| 23 | + // 按钮是否镂空 | ||
| 24 | + plain: { | ||
| 25 | + type: Boolean, | ||
| 26 | + default: false | ||
| 27 | + }, | ||
| 28 | + // 是否禁止状态 | ||
| 29 | + disabled: { | ||
| 30 | + type: Boolean, | ||
| 31 | + default: false | ||
| 32 | + }, | ||
| 33 | + // 是否加载中 | ||
| 34 | + loading: { | ||
| 35 | + type: Boolean, | ||
| 36 | + default: false | ||
| 37 | + }, | ||
| 38 | + // 加载中提示文字 | ||
| 39 | + loadingText: { | ||
| 40 | + type: [String, Number], | ||
| 41 | + default: '' | ||
| 42 | + }, | ||
| 43 | + // 加载状态图标类型 | ||
| 44 | + loadingMode: { | ||
| 45 | + type: String, | ||
| 46 | + default: 'spinner' | ||
| 47 | + }, | ||
| 48 | + // 加载图标大小 | ||
| 49 | + loadingSize: { | ||
| 50 | + type: [String, Number], | ||
| 51 | + default: 14 | ||
| 52 | + }, | ||
| 53 | + // 开放能力,具体请看uniapp稳定关于button组件部分说明 | ||
| 54 | + // https://uniapp.dcloud.io/component/button | ||
| 55 | + openType: { | ||
| 56 | + type: String, | ||
| 57 | + default: '' | ||
| 58 | + }, | ||
| 59 | + // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件 | ||
| 60 | + // 取值为submit(提交表单),reset(重置表单) | ||
| 61 | + formType: { | ||
| 62 | + type: String, | ||
| 63 | + default: '' | ||
| 64 | + }, | ||
| 65 | + // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 | ||
| 66 | + // 只微信小程序、QQ小程序有效 | ||
| 67 | + appParameter: { | ||
| 68 | + type: String, | ||
| 69 | + default: '' | ||
| 70 | + }, | ||
| 71 | + // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效 | ||
| 72 | + hoverStopPropagation: { | ||
| 73 | + type: Boolean, | ||
| 74 | + default: true | ||
| 75 | + }, | ||
| 76 | + // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效 | ||
| 77 | + lang: { | ||
| 78 | + type: String, | ||
| 79 | + default: 'en' | ||
| 80 | + }, | ||
| 81 | + // 会话来源,open-type="contact"时有效。只微信小程序有效 | ||
| 82 | + sessionFrom: { | ||
| 83 | + type: String, | ||
| 84 | + default: '' | ||
| 85 | + }, | ||
| 86 | + // 会话内消息卡片标题,open-type="contact"时有效 | ||
| 87 | + // 默认当前标题,只微信小程序有效 | ||
| 88 | + sendMessageTitle: { | ||
| 89 | + type: String, | ||
| 90 | + default: '' | ||
| 91 | + }, | ||
| 92 | + // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效 | ||
| 93 | + // 默认当前分享路径,只微信小程序有效 | ||
| 94 | + sendMessagePath: { | ||
| 95 | + type: String, | ||
| 96 | + default: '' | ||
| 97 | + }, | ||
| 98 | + // 会话内消息卡片图片,open-type="contact"时有效 | ||
| 99 | + // 默认当前页面截图,只微信小程序有效 | ||
| 100 | + sendMessageImg: { | ||
| 101 | + type: String, | ||
| 102 | + default: '' | ||
| 103 | + }, | ||
| 104 | + // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示, | ||
| 105 | + // 用户点击后可以快速发送小程序消息,open-type="contact"时有效 | ||
| 106 | + showMessageCard: { | ||
| 107 | + type: Boolean, | ||
| 108 | + default: true | ||
| 109 | + }, | ||
| 110 | + // 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取 | ||
| 111 | + dataName: { | ||
| 112 | + type: String, | ||
| 113 | + default: '' | ||
| 114 | + }, | ||
| 115 | + // 节流,一定时间内只能触发一次 | ||
| 116 | + throttleTime: { | ||
| 117 | + type: [String, Number], | ||
| 118 | + default: 0 | ||
| 119 | + }, | ||
| 120 | + // 按住后多久出现点击态,单位毫秒 | ||
| 121 | + hoverStartTime: { | ||
| 122 | + type: [String, Number], | ||
| 123 | + default: 0 | ||
| 124 | + }, | ||
| 125 | + // 手指松开后点击态保留时间,单位毫秒 | ||
| 126 | + hoverStayTime: { | ||
| 127 | + type: [String, Number], | ||
| 128 | + default: 200 | ||
| 129 | + }, | ||
| 130 | + // 按钮文字,之所以通过props传入,是因为slot传入的话 | ||
| 131 | + // nvue中无法控制文字的样式 | ||
| 132 | + text: { | ||
| 133 | + type: [String, Number], | ||
| 134 | + default: '' | ||
| 135 | + }, | ||
| 136 | + // 按钮图标 | ||
| 137 | + icon: { | ||
| 138 | + type: String, | ||
| 139 | + default: '' | ||
| 140 | + }, | ||
| 141 | + // 按钮图标大小 | ||
| 142 | + iconSize: { | ||
| 143 | + type: [String, Number], | ||
| 144 | + default: '' | ||
| 145 | + }, | ||
| 146 | + // 按钮图标颜色 | ||
| 147 | + iconColor: { | ||
| 148 | + type: String, | ||
| 149 | + default: '#000000' | ||
| 150 | + }, | ||
| 151 | + // 按钮颜色,支持传入linear-gradient渐变色 | ||
| 152 | + color: { | ||
| 153 | + type: String, | ||
| 154 | + default: '' | ||
| 155 | + }, | ||
| 156 | + // 自定义按钮文本样式 | ||
| 157 | + customTextStyle: { | ||
| 158 | + type: [Object,String], | ||
| 159 | + default: '' | ||
| 160 | + }, | ||
| 161 | + ...uni.$uv?.props?.button | ||
| 162 | + } | ||
| 163 | +} |
| 1 | +<template> | ||
| 2 | + <view | ||
| 3 | + class="uv-button-wrapper" | ||
| 4 | + :style="[btnWrapperStyle]" | ||
| 5 | + > | ||
| 6 | + <!-- #ifndef APP-NVUE --> | ||
| 7 | + <!-- #ifdef MP --> | ||
| 8 | + <!-- 为了解决微信小程序动态设置hover-class点击态不消失的BUG --> | ||
| 9 | + <view class="uv-button-wrapper--dis" v-if="disabled || loading"></view> | ||
| 10 | + <button | ||
| 11 | + :hover-start-time="Number(hoverStartTime)" | ||
| 12 | + :hover-stay-time="Number(hoverStayTime)" | ||
| 13 | + :form-type="formType" | ||
| 14 | + :open-type="openType" | ||
| 15 | + :app-parameter="appParameter" | ||
| 16 | + :hover-stop-propagation="hoverStopPropagation" | ||
| 17 | + :send-message-title="sendMessageTitle" | ||
| 18 | + :send-message-path="sendMessagePath" | ||
| 19 | + :lang="lang" | ||
| 20 | + :data-name="dataName" | ||
| 21 | + :session-from="sessionFrom" | ||
| 22 | + :send-message-img="sendMessageImg" | ||
| 23 | + :show-message-card="showMessageCard" | ||
| 24 | + @getphonenumber="onGetPhoneNumber" | ||
| 25 | + @getuserinfo="onGetUserInfo" | ||
| 26 | + @error="onError" | ||
| 27 | + @opensetting="onOpenSetting" | ||
| 28 | + @launchapp="onLaunchApp" | ||
| 29 | + @contact="onContact" | ||
| 30 | + @chooseavatar="onChooseavatar" | ||
| 31 | + @agreeprivacyauthorization="onAgreeprivacyauthorization" | ||
| 32 | + @addgroupapp="onAddgroupapp" | ||
| 33 | + @chooseaddress="onChooseaddress" | ||
| 34 | + @subscribe="onSubscribe" | ||
| 35 | + @login="onLogin" | ||
| 36 | + @im="onIm" | ||
| 37 | + hover-class="uv-button--active" | ||
| 38 | + class="uv-button uv-reset-button" | ||
| 39 | + :style="[baseColor, $uv.addStyle(customStyle)]" | ||
| 40 | + @tap="clickHandler" | ||
| 41 | + :class="bemClass" | ||
| 42 | + > | ||
| 43 | + <!-- #endif --> | ||
| 44 | + <!-- #ifndef MP --> | ||
| 45 | + <button | ||
| 46 | + :hover-start-time="Number(hoverStartTime)" | ||
| 47 | + :hover-stay-time="Number(hoverStayTime)" | ||
| 48 | + :form-type="formType" | ||
| 49 | + :open-type="openType" | ||
| 50 | + :app-parameter="appParameter" | ||
| 51 | + :hover-stop-propagation="hoverStopPropagation" | ||
| 52 | + :send-message-title="sendMessageTitle" | ||
| 53 | + :send-message-path="sendMessagePath" | ||
| 54 | + :lang="lang" | ||
| 55 | + :data-name="dataName" | ||
| 56 | + :session-from="sessionFrom" | ||
| 57 | + :send-message-img="sendMessageImg" | ||
| 58 | + :show-message-card="showMessageCard" | ||
| 59 | + :hover-class="!disabled && !loading ? 'uv-button--active' : ''" | ||
| 60 | + class="uv-button uv-reset-button" | ||
| 61 | + :style="[baseColor, $uv.addStyle(customStyle)]" | ||
| 62 | + @tap="clickHandler" | ||
| 63 | + :class="bemClass" | ||
| 64 | + > | ||
| 65 | + <!-- #endif --> | ||
| 66 | + <template v-if="loading"> | ||
| 67 | + <uv-loading-icon | ||
| 68 | + :mode="loadingMode" | ||
| 69 | + :size="loadingSize * 1.15" | ||
| 70 | + :color="loadingColor" | ||
| 71 | + ></uv-loading-icon> | ||
| 72 | + <text | ||
| 73 | + class="uv-button__loading-text" | ||
| 74 | + :style="[ | ||
| 75 | + { fontSize: textSize + 'px' }, | ||
| 76 | + $uv.addStyle(customTextStyle) | ||
| 77 | + ]" | ||
| 78 | + >{{ loadingText || text }}</text> | ||
| 79 | + </template> | ||
| 80 | + <template v-else> | ||
| 81 | + <uv-icon | ||
| 82 | + v-if="icon" | ||
| 83 | + :name="icon" | ||
| 84 | + :color="iconColorCom" | ||
| 85 | + :size="getIconSize" | ||
| 86 | + :customStyle="{ marginRight: '2px' }" | ||
| 87 | + ></uv-icon> | ||
| 88 | + <slot> | ||
| 89 | + <text | ||
| 90 | + class="uv-button__text" | ||
| 91 | + :style="[ | ||
| 92 | + { fontSize: textSize + 'px' }, | ||
| 93 | + $uv.addStyle(customTextStyle) | ||
| 94 | + ]" | ||
| 95 | + >{{ text }}</text> | ||
| 96 | + </slot> | ||
| 97 | + <slot name="suffix"></slot> | ||
| 98 | + </template> | ||
| 99 | + </button> | ||
| 100 | + <!-- #endif --> | ||
| 101 | + <!-- #ifdef APP-NVUE --> | ||
| 102 | + <view | ||
| 103 | + :hover-start-time="Number(hoverStartTime)" | ||
| 104 | + :hover-stay-time="Number(hoverStayTime)" | ||
| 105 | + class="uv-button" | ||
| 106 | + :hover-class=" | ||
| 107 | + !disabled && !loading && !color && (plain || type === 'info') | ||
| 108 | + ? 'uv-button--active--plain' | ||
| 109 | + : !disabled && !loading && !plain | ||
| 110 | + ? 'uv-button--active' | ||
| 111 | + : '' | ||
| 112 | + " | ||
| 113 | + @tap="clickHandler" | ||
| 114 | + :class="bemClass" | ||
| 115 | + :style="[baseColor, $uv.addStyle(customStyle)]" | ||
| 116 | + > | ||
| 117 | + <template v-if="loading"> | ||
| 118 | + <uv-loading-icon | ||
| 119 | + :mode="loadingMode" | ||
| 120 | + :size="loadingSize * 1.15" | ||
| 121 | + :color="loadingColor" | ||
| 122 | + ></uv-loading-icon> | ||
| 123 | + <text | ||
| 124 | + class="uv-button__loading-text" | ||
| 125 | + :style="[nvueTextStyle,$uv.addStyle(customTextStyle)]" | ||
| 126 | + :class="[plain && `uv-button__text--plain--${type}`]" | ||
| 127 | + >{{ loadingText || text }}</text> | ||
| 128 | + </template> | ||
| 129 | + <template v-else> | ||
| 130 | + <uv-icon | ||
| 131 | + v-if="icon" | ||
| 132 | + :name="icon" | ||
| 133 | + :color="iconColorCom" | ||
| 134 | + :size="getIconSize" | ||
| 135 | + ></uv-icon> | ||
| 136 | + <text | ||
| 137 | + class="uv-button__text" | ||
| 138 | + :style="[ | ||
| 139 | + { | ||
| 140 | + marginLeft: icon ? '2px' : 0, | ||
| 141 | + }, | ||
| 142 | + nvueTextStyle, | ||
| 143 | + $uv.addStyle(customTextStyle) | ||
| 144 | + ]" | ||
| 145 | + :class="[plain && `uv-button__text--plain--${type}`]" | ||
| 146 | + >{{ text }}</text> | ||
| 147 | + <slot name="suffix"></slot> | ||
| 148 | + </template> | ||
| 149 | + </view> | ||
| 150 | + <!-- #endif --> | ||
| 151 | + </view> | ||
| 152 | +</template> | ||
| 153 | + | ||
| 154 | +<script> | ||
| 155 | +import throttle from '@/uni_modules/uv-ui-tools/libs/function/throttle.js'; | ||
| 156 | +import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js' | ||
| 157 | +import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js' | ||
| 158 | +import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js' | ||
| 159 | +import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js' | ||
| 160 | +import props from "./props.js"; | ||
| 161 | +/** | ||
| 162 | + * button 按钮 | ||
| 163 | + * @description Button 按钮 | ||
| 164 | + * @tutorial https://www.uvui.cn/components/button.html | ||
| 165 | + * @property {Boolean} hairline 是否显示按钮的细边框 (默认 true ) | ||
| 166 | + * @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' ) | ||
| 167 | + * @property {String} size 按钮尺寸,large,normal,mini (默认 normal) | ||
| 168 | + * @property {String} shape 按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' ) | ||
| 169 | + * @property {Boolean} plain 按钮是否镂空,背景色透明 (默认 false) | ||
| 170 | + * @property {Boolean} disabled 是否禁用 (默认 false) | ||
| 171 | + * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false) | ||
| 172 | + * @property {String | Number} loadingText 加载中提示文字 | ||
| 173 | + * @property {String} loadingMode 加载状态图标类型 (默认 'spinner' ) | ||
| 174 | + * @property {String | Number} loadingSize 加载图标大小 (默认 15 ) | ||
| 175 | + * @property {String} openType 开放能力,具体请看uniapp稳定关于button组件部分说明 | ||
| 176 | + * @property {String} formType 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件 | ||
| 177 | + * @property {String} appParameter 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效) | ||
| 178 | + * @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true ) | ||
| 179 | + * @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en ) | ||
| 180 | + * @property {String} sessionFrom 会话来源,openType="contact"时有效 | ||
| 181 | + * @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效 | ||
| 182 | + * @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效 | ||
| 183 | + * @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效 | ||
| 184 | + * @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false) | ||
| 185 | + * @property {String} dataName 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取 | ||
| 186 | + * @property {String | Number} throttleTime 节流,一定时间内只能触发一次 (默认 0 ) | ||
| 187 | + * @property {String | Number} hoverStartTime 按住后多久出现点击态,单位毫秒 (默认 0 ) | ||
| 188 | + * @property {String | Number} hoverStayTime 手指松开后点击态保留时间,单位毫秒 (默认 200 ) | ||
| 189 | + * @property {String | Number} text 按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式) | ||
| 190 | + * @property {String} icon 按钮图标 | ||
| 191 | + * @property {String} iconColor 按钮图标颜色 | ||
| 192 | + * @property {String} color 按钮颜色,支持传入linear-gradient渐变色 | ||
| 193 | + * @property {Object} customStyle 定义需要用到的外部样式 | ||
| 194 | + * @event {Function} click 非禁止并且非加载中,才能点击 | ||
| 195 | + * @event {Function} getphonenumber open-type="getPhoneNumber"时有效 | ||
| 196 | + * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo | ||
| 197 | + * @event {Function} error 当使用开放能力时,发生错误的回调 | ||
| 198 | + * @event {Function} opensetting 在打开授权设置页并关闭后回调 | ||
| 199 | + * @event {Function} launchapp 打开 APP 成功的回调 | ||
| 200 | + * @example <uv-button>月落</uv-button> | ||
| 201 | + */ | ||
| 202 | +export default { | ||
| 203 | + name: "uv-button", | ||
| 204 | + // #ifdef MP | ||
| 205 | + mixins: [mpMixin, mixin, button, openType, props], | ||
| 206 | + // #endif | ||
| 207 | + // #ifndef MP | ||
| 208 | + mixins: [mpMixin, mixin, props], | ||
| 209 | + // #endif | ||
| 210 | + emits: ['click'], | ||
| 211 | + data() { | ||
| 212 | + return {}; | ||
| 213 | + }, | ||
| 214 | + computed: { | ||
| 215 | + // 生成bem风格的类名 | ||
| 216 | + bemClass() { | ||
| 217 | + // this.bem为一个computed变量,在mixin中 | ||
| 218 | + if (!this.color) { | ||
| 219 | + return this.bem("button", | ||
| 220 | + ["type", "shape", "size"], | ||
| 221 | + ["disabled", "plain", "hairline"]); | ||
| 222 | + } else { | ||
| 223 | + // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式 | ||
| 224 | + return this.bem("button", | ||
| 225 | + ["shape", "size"], | ||
| 226 | + ["disabled", "plain", "hairline"]); | ||
| 227 | + } | ||
| 228 | + }, | ||
| 229 | + loadingColor() { | ||
| 230 | + if (this.plain) { | ||
| 231 | + // 如果有设置color值,则用color值,否则使用type主题颜色 | ||
| 232 | + return this.color ? this.color : '#3c9cff'; | ||
| 233 | + } | ||
| 234 | + if (this.type === "info") { | ||
| 235 | + return "#c9c9c9"; | ||
| 236 | + } | ||
| 237 | + return "rgb(200, 200, 200)"; | ||
| 238 | + }, | ||
| 239 | + iconColorCom() { | ||
| 240 | + // 如果是镂空状态,设置了color就用color值,否则使用主题颜色, | ||
| 241 | + // uv-icon的color能接受一个主题颜色的值 | ||
| 242 | + if (this.iconColor) return this.iconColor; | ||
| 243 | + if (this.plain) { | ||
| 244 | + return this.color ? this.color : this.type; | ||
| 245 | + } else { | ||
| 246 | + return this.type === "info" ? "#000000" : "#ffffff"; | ||
| 247 | + } | ||
| 248 | + }, | ||
| 249 | + baseColor() { | ||
| 250 | + let style = {}; | ||
| 251 | + if (this.color) { | ||
| 252 | + // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色 | ||
| 253 | + style.color = this.plain ? this.color : "white"; | ||
| 254 | + if (!this.plain) { | ||
| 255 | + // 非镂空,背景色使用自定义的颜色 | ||
| 256 | + style["background-color"] = this.color; | ||
| 257 | + } | ||
| 258 | + if (this.color.indexOf("gradient") !== -1) { | ||
| 259 | + // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色 | ||
| 260 | + // weex文档说明可以写borderWidth的形式,为什么这里需要分开写? | ||
| 261 | + // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效 | ||
| 262 | + style.borderTopWidth = 0; | ||
| 263 | + style.borderRightWidth = 0; | ||
| 264 | + style.borderBottomWidth = 0; | ||
| 265 | + style.borderLeftWidth = 0; | ||
| 266 | + if (!this.plain) { | ||
| 267 | + style.backgroundImage = this.color; | ||
| 268 | + } | ||
| 269 | + } else { | ||
| 270 | + // 非渐变色,则设置边框相关的属性 | ||
| 271 | + style.borderColor = this.color; | ||
| 272 | + style.borderWidth = "1px"; | ||
| 273 | + style.borderStyle = "solid"; | ||
| 274 | + } | ||
| 275 | + } | ||
| 276 | + return style; | ||
| 277 | + }, | ||
| 278 | + // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置 | ||
| 279 | + nvueTextStyle() { | ||
| 280 | + let style = {}; | ||
| 281 | + // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色 | ||
| 282 | + if (this.type === "info") { | ||
| 283 | + style.color = "#323233"; | ||
| 284 | + } | ||
| 285 | + if (this.color) { | ||
| 286 | + style.color = this.plain ? this.color : "white"; | ||
| 287 | + } | ||
| 288 | + style.fontSize = this.textSize + "px"; | ||
| 289 | + return style; | ||
| 290 | + }, | ||
| 291 | + // 字体大小 | ||
| 292 | + textSize() { | ||
| 293 | + let fontSize = 14, | ||
| 294 | + { size } = this; | ||
| 295 | + if (size === "large") fontSize = 16; | ||
| 296 | + if (size === "normal") fontSize = 14; | ||
| 297 | + if (size === "small") fontSize = 12; | ||
| 298 | + if (size === "mini") fontSize = 10; | ||
| 299 | + return fontSize; | ||
| 300 | + }, | ||
| 301 | + // 设置图标大小 | ||
| 302 | + getIconSize() { | ||
| 303 | + const size = this.iconSize ? this.iconSize : this.textSize * 1.35; | ||
| 304 | + return this.$uv.addUnit(size); | ||
| 305 | + }, | ||
| 306 | + // 设置外层盒子的宽度,其他样式不需要 | ||
| 307 | + btnWrapperStyle() { | ||
| 308 | + const style = {}; | ||
| 309 | + const customStyle = this.$uv.addStyle(this.customStyle); | ||
| 310 | + if(customStyle.width) style.width = customStyle.width; | ||
| 311 | + return style; | ||
| 312 | + } | ||
| 313 | + }, | ||
| 314 | + methods: { | ||
| 315 | + clickHandler() { | ||
| 316 | + // 非禁止并且非加载中,才能点击 | ||
| 317 | + if (!this.disabled && !this.loading) { | ||
| 318 | + // 进行节流控制,每this.throttle毫秒内,只在开始处执行 | ||
| 319 | + throttle(() => { | ||
| 320 | + this.$emit("click"); | ||
| 321 | + }, this.throttleTime); | ||
| 322 | + } | ||
| 323 | + } | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | +</script> | ||
| 327 | + | ||
| 328 | +<style lang="scss" scoped> | ||
| 329 | +$show-reset-button: 1; | ||
| 330 | +@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss'; | ||
| 331 | +@import '@/uni_modules/uv-ui-tools/libs/css/components.scss'; | ||
| 332 | +@import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 333 | + | ||
| 334 | +/* #ifndef APP-NVUE */ | ||
| 335 | +@import "./vue.scss"; | ||
| 336 | +/* #endif */ | ||
| 337 | + | ||
| 338 | +/* #ifdef APP-NVUE */ | ||
| 339 | +@import "./nvue.scss"; | ||
| 340 | +/* #endif */ | ||
| 341 | + | ||
| 342 | +$uv-button-uv-button-height: 40px !default; | ||
| 343 | +$uv-button-text-font-size: 15px !default; | ||
| 344 | +$uv-button-loading-text-font-size: 15px !default; | ||
| 345 | +$uv-button-loading-text-margin-left: 4px !default; | ||
| 346 | +$uv-button-large-width: 100% !default; | ||
| 347 | +$uv-button-large-height: 50px !default; | ||
| 348 | +$uv-button-normal-padding: 0 12px !default; | ||
| 349 | +$uv-button-large-padding: 0 15px !default; | ||
| 350 | +$uv-button-normal-font-size: 14px !default; | ||
| 351 | +$uv-button-small-min-width: 60px !default; | ||
| 352 | +$uv-button-small-height: 30px !default; | ||
| 353 | +$uv-button-small-padding: 0px 8px !default; | ||
| 354 | +$uv-button-mini-padding: 0px 8px !default; | ||
| 355 | +$uv-button-small-font-size: 12px !default; | ||
| 356 | +$uv-button-mini-height: 22px !default; | ||
| 357 | +$uv-button-mini-font-size: 10px !default; | ||
| 358 | +$uv-button-mini-min-width: 50px !default; | ||
| 359 | +$uv-button-disabled-opacity: 0.5 !default; | ||
| 360 | +$uv-button-info-color: #323233 !default; | ||
| 361 | +$uv-button-info-background-color: #fff !default; | ||
| 362 | +$uv-button-info-border-color: #ebedf0 !default; | ||
| 363 | +$uv-button-info-border-width: 1px !default; | ||
| 364 | +$uv-button-info-border-style: solid !default; | ||
| 365 | +$uv-button-success-color: #fff !default; | ||
| 366 | +$uv-button-success-background-color: $uv-success !default; | ||
| 367 | +$uv-button-success-border-color: $uv-button-success-background-color !default; | ||
| 368 | +$uv-button-success-border-width: 1px !default; | ||
| 369 | +$uv-button-success-border-style: solid !default; | ||
| 370 | +$uv-button-primary-color: #fff !default; | ||
| 371 | +$uv-button-primary-background-color: $uv-primary !default; | ||
| 372 | +$uv-button-primary-border-color: $uv-button-primary-background-color !default; | ||
| 373 | +$uv-button-primary-border-width: 1px !default; | ||
| 374 | +$uv-button-primary-border-style: solid !default; | ||
| 375 | +$uv-button-error-color: #fff !default; | ||
| 376 | +$uv-button-error-background-color: $uv-error !default; | ||
| 377 | +$uv-button-error-border-color: $uv-button-error-background-color !default; | ||
| 378 | +$uv-button-error-border-width: 1px !default; | ||
| 379 | +$uv-button-error-border-style: solid !default; | ||
| 380 | +$uv-button-warning-color: #fff !default; | ||
| 381 | +$uv-button-warning-background-color: $uv-warning !default; | ||
| 382 | +$uv-button-warning-border-color: $uv-button-warning-background-color !default; | ||
| 383 | +$uv-button-warning-border-width: 1px !default; | ||
| 384 | +$uv-button-warning-border-style: solid !default; | ||
| 385 | +$uv-button-block-width: 100% !default; | ||
| 386 | +$uv-button-circle-border-top-right-radius: 100px !default; | ||
| 387 | +$uv-button-circle-border-top-left-radius: 100px !default; | ||
| 388 | +$uv-button-circle-border-bottom-left-radius: 100px !default; | ||
| 389 | +$uv-button-circle-border-bottom-right-radius: 100px !default; | ||
| 390 | +$uv-button-square-border-top-right-radius: 3px !default; | ||
| 391 | +$uv-button-square-border-top-left-radius: 3px !default; | ||
| 392 | +$uv-button-square-border-bottom-left-radius: 3px !default; | ||
| 393 | +$uv-button-square-border-bottom-right-radius: 3px !default; | ||
| 394 | +$uv-button-icon-min-width: 1em !default; | ||
| 395 | +$uv-button-plain-background-color: #fff !default; | ||
| 396 | +$uv-button-hairline-border-width: 0.5px !default; | ||
| 397 | + | ||
| 398 | +.uv-button { | ||
| 399 | + height: $uv-button-uv-button-height; | ||
| 400 | + position: relative; | ||
| 401 | + align-items: center; | ||
| 402 | + justify-content: center; | ||
| 403 | + @include flex; | ||
| 404 | + /* #ifndef APP-NVUE */ | ||
| 405 | + box-sizing: border-box; | ||
| 406 | + /* #endif */ | ||
| 407 | + flex-direction: row; | ||
| 408 | + | ||
| 409 | + &__text { | ||
| 410 | + font-size: $uv-button-text-font-size; | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + &__loading-text { | ||
| 414 | + font-size: $uv-button-loading-text-font-size; | ||
| 415 | + margin-left: $uv-button-loading-text-margin-left; | ||
| 416 | + } | ||
| 417 | + | ||
| 418 | + &--large { | ||
| 419 | + /* #ifndef APP-NVUE */ | ||
| 420 | + width: $uv-button-large-width; | ||
| 421 | + /* #endif */ | ||
| 422 | + height: $uv-button-large-height; | ||
| 423 | + padding: $uv-button-large-padding; | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + &--normal { | ||
| 427 | + padding: $uv-button-normal-padding; | ||
| 428 | + font-size: $uv-button-normal-font-size; | ||
| 429 | + } | ||
| 430 | + | ||
| 431 | + &--small { | ||
| 432 | + /* #ifndef APP-NVUE */ | ||
| 433 | + min-width: $uv-button-small-min-width; | ||
| 434 | + /* #endif */ | ||
| 435 | + height: $uv-button-small-height; | ||
| 436 | + padding: $uv-button-small-padding; | ||
| 437 | + font-size: $uv-button-small-font-size; | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + &--mini { | ||
| 441 | + height: $uv-button-mini-height; | ||
| 442 | + font-size: $uv-button-mini-font-size; | ||
| 443 | + /* #ifndef APP-NVUE */ | ||
| 444 | + min-width: $uv-button-mini-min-width; | ||
| 445 | + /* #endif */ | ||
| 446 | + padding: $uv-button-mini-padding; | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | + &--disabled { | ||
| 450 | + opacity: $uv-button-disabled-opacity; | ||
| 451 | + } | ||
| 452 | + | ||
| 453 | + &--info { | ||
| 454 | + color: $uv-button-info-color; | ||
| 455 | + background-color: $uv-button-info-background-color; | ||
| 456 | + border-color: $uv-button-info-border-color; | ||
| 457 | + border-width: $uv-button-info-border-width; | ||
| 458 | + border-style: $uv-button-info-border-style; | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + &--success { | ||
| 462 | + color: $uv-button-success-color; | ||
| 463 | + background-color: $uv-button-success-background-color; | ||
| 464 | + border-color: $uv-button-success-border-color; | ||
| 465 | + border-width: $uv-button-success-border-width; | ||
| 466 | + border-style: $uv-button-success-border-style; | ||
| 467 | + } | ||
| 468 | + | ||
| 469 | + &--primary { | ||
| 470 | + color: $uv-button-primary-color; | ||
| 471 | + background-color: $uv-button-primary-background-color; | ||
| 472 | + border-color: $uv-button-primary-border-color; | ||
| 473 | + border-width: $uv-button-primary-border-width; | ||
| 474 | + border-style: $uv-button-primary-border-style; | ||
| 475 | + } | ||
| 476 | + | ||
| 477 | + &--error { | ||
| 478 | + color: $uv-button-error-color; | ||
| 479 | + background-color: $uv-button-error-background-color; | ||
| 480 | + border-color: $uv-button-error-border-color; | ||
| 481 | + border-width: $uv-button-error-border-width; | ||
| 482 | + border-style: $uv-button-error-border-style; | ||
| 483 | + } | ||
| 484 | + | ||
| 485 | + &--warning { | ||
| 486 | + color: $uv-button-warning-color; | ||
| 487 | + background-color: $uv-button-warning-background-color; | ||
| 488 | + border-color: $uv-button-warning-border-color; | ||
| 489 | + border-width: $uv-button-warning-border-width; | ||
| 490 | + border-style: $uv-button-warning-border-style; | ||
| 491 | + } | ||
| 492 | + | ||
| 493 | + &--block { | ||
| 494 | + @include flex; | ||
| 495 | + width: $uv-button-block-width; | ||
| 496 | + } | ||
| 497 | + | ||
| 498 | + &--circle { | ||
| 499 | + border-top-right-radius: $uv-button-circle-border-top-right-radius; | ||
| 500 | + border-top-left-radius: $uv-button-circle-border-top-left-radius; | ||
| 501 | + border-bottom-left-radius: $uv-button-circle-border-bottom-left-radius; | ||
| 502 | + border-bottom-right-radius: $uv-button-circle-border-bottom-right-radius; | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + &--square { | ||
| 506 | + border-bottom-left-radius: $uv-button-square-border-top-right-radius; | ||
| 507 | + border-bottom-right-radius: $uv-button-square-border-top-left-radius; | ||
| 508 | + border-top-left-radius: $uv-button-square-border-bottom-left-radius; | ||
| 509 | + border-top-right-radius: $uv-button-square-border-bottom-right-radius; | ||
| 510 | + } | ||
| 511 | + | ||
| 512 | + &__icon { | ||
| 513 | + /* #ifndef APP-NVUE */ | ||
| 514 | + min-width: $uv-button-icon-min-width; | ||
| 515 | + line-height: inherit !important; | ||
| 516 | + vertical-align: top; | ||
| 517 | + /* #endif */ | ||
| 518 | + } | ||
| 519 | + | ||
| 520 | + &--plain { | ||
| 521 | + background-color: $uv-button-plain-background-color; | ||
| 522 | + } | ||
| 523 | + | ||
| 524 | + &--hairline { | ||
| 525 | + border-width: $uv-button-hairline-border-width !important; | ||
| 526 | + } | ||
| 527 | +} | ||
| 528 | +</style> |
| 1 | +@import '@/uni_modules/uv-ui-tools/libs/css/color.scss'; | ||
| 2 | +// nvue下hover-class无效 | ||
| 3 | +$uv-button-before-top:50% !default; | ||
| 4 | +$uv-button-before-left:50% !default; | ||
| 5 | +$uv-button-before-width:100% !default; | ||
| 6 | +$uv-button-before-height:100% !default; | ||
| 7 | +$uv-button-before-transform:translate(-50%, -50%) !default; | ||
| 8 | +$uv-button-before-opacity:0 !default; | ||
| 9 | +$uv-button-before-background-color:#000 !default; | ||
| 10 | +$uv-button-before-border-color:#000 !default; | ||
| 11 | +$uv-button-active-before-opacity:.15 !default; | ||
| 12 | +$uv-button-icon-margin-left:4px !default; | ||
| 13 | +$uv-button-plain-uv-button-info-color:$uv-info; | ||
| 14 | +$uv-button-plain-uv-button-success-color:$uv-success; | ||
| 15 | +$uv-button-plain-uv-button-error-color:$uv-error; | ||
| 16 | +$uv-button-plain-uv-button-warning-color:$uv-warning; | ||
| 17 | + | ||
| 18 | +.uv-button-wrapper { | ||
| 19 | + position: relative; | ||
| 20 | + &--dis { | ||
| 21 | + position: absolute; | ||
| 22 | + left: 0; | ||
| 23 | + top: 0; | ||
| 24 | + right: 0; | ||
| 25 | + bottom: 0; | ||
| 26 | + z-index: 9; | ||
| 27 | + } | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +.uv-button { | ||
| 31 | + width: 100%; | ||
| 32 | + | ||
| 33 | + &__text { | ||
| 34 | + white-space: nowrap; | ||
| 35 | + line-height: 1; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + &:before { | ||
| 39 | + position: absolute; | ||
| 40 | + top:$uv-button-before-top; | ||
| 41 | + left:$uv-button-before-left; | ||
| 42 | + width:$uv-button-before-width; | ||
| 43 | + height:$uv-button-before-height; | ||
| 44 | + border: inherit; | ||
| 45 | + border-radius: inherit; | ||
| 46 | + transform:$uv-button-before-transform; | ||
| 47 | + opacity:$uv-button-before-opacity; | ||
| 48 | + content: " "; | ||
| 49 | + background-color:$uv-button-before-background-color; | ||
| 50 | + border-color:$uv-button-before-border-color; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + &--active { | ||
| 54 | + &:before { | ||
| 55 | + opacity: .15 | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + &__icon+&__text:not(:empty), | ||
| 60 | + &__loading-text { | ||
| 61 | + margin-left:$uv-button-icon-margin-left; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + &--plain { | ||
| 65 | + &.uv-button--primary { | ||
| 66 | + color: $uv-primary; | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + &--plain { | ||
| 71 | + &.uv-button--info { | ||
| 72 | + color:$uv-button-plain-uv-button-info-color; | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + &--plain { | ||
| 77 | + &.uv-button--success { | ||
| 78 | + color:$uv-button-plain-uv-button-success-color; | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + &--plain { | ||
| 83 | + &.uv-button--error { | ||
| 84 | + color:$uv-button-plain-uv-button-error-color; | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + &--plain { | ||
| 89 | + &.uv-button--warning { | ||
| 90 | + color:$uv-button-plain-uv-button-warning-color; | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | +} |
uni_modules/uv-button/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "id": "uv-button", | ||
| 3 | + "displayName": "uv-button 按钮 全面兼容vue3+2、app、h5、小程序等多端", | ||
| 4 | + "version": "1.0.15", | ||
| 5 | + "description": "按钮组件内部实现以uni-app的button组件为基础,进行二次封装,灵活配置,功能齐全,兼容全端。", | ||
| 6 | + "keywords": [ | ||
| 7 | + "uv-button", | ||
| 8 | + "uvui", | ||
| 9 | + "uv-ui", | ||
| 10 | + "button", | ||
| 11 | + "按钮" | ||
| 12 | + ], | ||
| 13 | + "repository": "", | ||
| 14 | + "engines": { | ||
| 15 | + "HBuilderX": "^3.1.0" | ||
| 16 | + }, | ||
| 17 | + "dcloudext": { | ||
| 18 | + "type": "component-vue", | ||
| 19 | + "sale": { | ||
| 20 | + "regular": { | ||
| 21 | + "price": "0.00" | ||
| 22 | + }, | ||
| 23 | + "sourcecode": { | ||
| 24 | + "price": "0.00" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "contact": { | ||
| 28 | + "qq": "" | ||
| 29 | + }, | ||
| 30 | + "declaration": { | ||
| 31 | + "ads": "无", | ||
| 32 | + "data": "插件不采集任何数据", | ||
| 33 | + "permissions": "无" | ||
| 34 | + }, | ||
| 35 | + "npmurl": "" | ||
| 36 | + }, | ||
| 37 | + "uni_modules": { | ||
| 38 | + "dependencies": [ | ||
| 39 | + "uv-ui-tools", | ||
| 40 | + "uv-loading-icon", | ||
| 41 | + "uv-icon" | ||
| 42 | + ], | ||
| 43 | + "encrypt": [], | ||
| 44 | + "platforms": { | ||
| 45 | + "cloud": { | ||
| 46 | + "tcb": "y", | ||
| 47 | + "aliyun": "y" | ||
| 48 | + }, | ||
| 49 | + "client": { | ||
| 50 | + "Vue": { | ||
| 51 | + "vue2": "y", | ||
| 52 | + "vue3": "y" | ||
| 53 | + }, | ||
| 54 | + "App": { | ||
| 55 | + "app-vue": "y", | ||
| 56 | + "app-nvue": "y" | ||
| 57 | + }, | ||
| 58 | + "H5-mobile": { | ||
| 59 | + "Safari": "y", | ||
| 60 | + "Android Browser": "y", | ||
| 61 | + "微信浏览器(Android)": "y", | ||
| 62 | + "QQ浏览器(Android)": "y" | ||
| 63 | + }, | ||
| 64 | + "H5-pc": { | ||
| 65 | + "Chrome": "y", | ||
| 66 | + "IE": "y", | ||
| 67 | + "Edge": "y", | ||
| 68 | + "Firefox": "y", | ||
| 69 | + "Safari": "y" | ||
| 70 | + }, | ||
| 71 | + "小程序": { | ||
| 72 | + "微信": "y", | ||
| 73 | + "阿里": "y", | ||
| 74 | + "百度": "y", | ||
| 75 | + "字节跳动": "y", | ||
| 76 | + "QQ": "y", | ||
| 77 | + "钉钉": "u", | ||
| 78 | + "快手": "u", | ||
| 79 | + "飞书": "u", | ||
| 80 | + "京东": "u" | ||
| 81 | + }, | ||
| 82 | + "快应用": { | ||
| 83 | + "华为": "u", | ||
| 84 | + "联盟": "u" | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | +} |
-
Please register or login to post a comment