提交 792f9cbe 作者: 宇宙超人

1

上级 0b765bbb
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "vscode.typescript-language-features"
}, },
"[typescriptreact]": { "[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -54,7 +54,8 @@ ...@@ -54,7 +54,8 @@
}) })
</script> </script>
<style lang="less"> <style lang="scss">
@import '@/uni_modules/uview-plus/index.scss';
/* common css */ /* common css */
/* #ifndef APP-PLUS-NVUE */ /* #ifndef APP-PLUS-NVUE */
/* uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */ /* uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */
......
...@@ -7,8 +7,57 @@ enum Api { ...@@ -7,8 +7,57 @@ enum Api {
agricultureModelsList = '/online/cgform/api/getData/7b2983df6ddf416aba68db8b0ab234ab', // 农业模型数据 agricultureModelsList = '/online/cgform/api/getData/7b2983df6ddf416aba68db8b0ab234ab', // 农业模型数据
baseManagementList = '/online/cgform/api/getData/e4e4e6c901254b60b1e7a005097999ec', // 基地管理数据 baseManagementList = '/online/cgform/api/getData/e4e4e6c901254b60b1e7a005097999ec', // 基地管理数据
commonToolsList = '/online/cgform/api/getData/3a7fbb877f304b7d83935caa454859c4', // 常用工具数据 commonToolsList = '/online/cgform/api/getData/3a7fbb877f304b7d83935caa454859c4', // 常用工具数据
getFarmBaseList = '/farmbase/getFarmBaseList',
}
/**
* 删除基地
* @param id
* @returns
*/
export function delFarmbase(id) {
return otherHttp.delete({
url: '/farmbase/delete?id='+id,
})
}
/**
* 添加基地
* @param params
* @returns
*/
export function addFarmbase(params = {}) {
return otherHttp.post({
url: '/farmbase/add',
params,
})
}
/**
* 基地列表
* @param {any} params
* @return
*/
export function getFarmbaseList(params: any = {}) {
return otherHttp.get({
url: '/farmbase/list',
params,
})
}
export function AllFarms(params = {}) {
return otherHttp.get({
url: '/farms/getAllFarms',
params,
})
}
/**
* 获取基地数量
* @param params
* @return
*/
export function getFarmBaseList(params = {}) {
return otherHttp.get({
url: Api.getFarmBaseList,
params,
})
} }
/** /**
* @param params 请求参数 * @param params 请求参数
* @description: 金刚区菜单数据 * @description: 金刚区菜单数据
......
...@@ -416,7 +416,7 @@ ...@@ -416,7 +416,7 @@
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
.fui-form__msg-bg { .fui-form__msg-bg {
background: var(--fui-color-danger, #FF2B2B) !important; background: var(--fui-color-minor, #FF2B2B) !important;
} }
/* #endif */ /* #endif */
......
...@@ -29,6 +29,7 @@ export const APP_UUID_KEY = 'APP__UUID__KEY__' ...@@ -29,6 +29,7 @@ export const APP_UUID_KEY = 'APP__UUID__KEY__'
*/ */
export const USER_ID_KEY = 'USER__ID__KEY__' export const USER_ID_KEY = 'USER__ID__KEY__'
export const FARM_ID_KEY = 'FARM__ID__KEY__'
export enum CacheTypeEnum { export enum CacheTypeEnum {
SESSION, SESSION,
LOCAL, LOCAL,
......
declare module '@/uni_modules/uview-plus';
import { createSSRApp } from 'vue' import { createSSRApp } from 'vue'
import * as Pinia from 'pinia' import * as Pinia from 'pinia'
import uviewPlus from '@/uni_modules/uview-plus'
import 'virtual:uno.css' import 'virtual:uno.css'
import App from './App.vue' import App from './App.vue'
...@@ -23,7 +23,7 @@ export function createApp() { ...@@ -23,7 +23,7 @@ export function createApp() {
// 配置 i18n // 配置 i18n
setupI18n(app) setupI18n(app)
app.use(uviewPlus)
return { return {
app, app,
Pinia, Pinia,
......
{ {
"easycom": {
"autoscan": true,
"custom": {
"^u--(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue"
}
},
"pages": [ "pages": [
{ {
"path": "pages/login/login", "path": "pages/login/login",
...@@ -272,11 +280,10 @@ ...@@ -272,11 +280,10 @@
"titleSize": "20", "titleSize": "20",
"buttons": [ "buttons": [
{ {
"text": "\ue560", "text": "+ 添加基地",
"fontSrc": "/static/uni.ttf", "fontSrc": "/static/uni.ttf",
"color": "#fff", "color": "#fff",
"fontSize": "22px", "fontSize": "28rpx"
"width": "40px"
} }
] ]
} }
...@@ -358,7 +365,13 @@ ...@@ -358,7 +365,13 @@
}, },
"disableScroll": true "disableScroll": true
} }
} },
{
"path": "pages/jidiguanli/add",
"style": {
"navigationBarTitleText": "添加基地"
}
}
], ],
"easycom": { "easycom": {
"autoscan": true, "autoscan": true,
......
...@@ -66,26 +66,17 @@ ...@@ -66,26 +66,17 @@
close, close,
}) })
</script> </script>
<template> <template>
<fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable> <fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable>
<view class="title flex justify-center"> <view class="title flex justify-center">
<view class="flex-1">立即报价</view> <view class="flex-1">立即报价</view>
<fui-icon class="close flex-basis" name="close" size="46" color="#999999" @click="close"></fui-icon> <fui-icon class="close flex-basis" name="close" size="46" color="#999999" @click="close" />
</view> </view>
<view class="text-left"> <view class="text-left">
<fui-form ref="formRef"> <fui-form ref="formRef" top="180" color="#000">
<fui-input <fui-input marginTop="30" size="28" placeholder="请填写联系人姓名" v-model="pageData.form.supplyName" />
marginTop="30" <fui-input marginTop="30" size="28" placeholder="请填写联系电话" v-model="pageData.form.phone" />
size="28"
placeholder="请填写联系人姓名"
v-model="pageData.form.supplyName"
></fui-input>
<fui-input
marginTop="30"
size="28"
placeholder="请填写联系电话"
v-model="pageData.form.phone"
></fui-input>
<fui-input marginTop="30" size="28" placeholder="请填写价格" v-model="pageData.form.supplyPrice"> <fui-input marginTop="30" size="28" placeholder="请填写价格" v-model="pageData.form.supplyPrice">
<view class="flex"> <view class="flex">
<view class="mr-3" style="color: #ccc">|</view> <view class="mr-3" style="color: #ccc">|</view>
...@@ -98,14 +89,15 @@ ...@@ -98,14 +89,15 @@
height="80rpx" height="80rpx"
placeholder="请输入报价备注" placeholder="请输入报价备注"
v-model="pageData.form.remark" v-model="pageData.form.remark"
></fui-textarea> />
<view style="margin-top: 30rpx"> <view style="margin-top: 30rpx">
<fui-button text="确定" bold radius="96rpx" @click="submit"></fui-button> <fui-button text="确定" bold radius="96rpx" @click="submit" />
</view> </view>
</fui-form> </fui-form>
</view> </view>
</fui-dialog> </fui-dialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.fui-dialog__body) { :deep(.fui-dialog__body) {
background: linear-gradient(0deg, rgba(93, 182, 111, 0) 0%, rgba(93, 182, 111, 0.25) 100%); background: linear-gradient(0deg, rgba(93, 182, 111, 0) 0%, rgba(93, 182, 111, 0.25) 100%);
......
<script setup lang="ts"> <script setup lang="ts">
import { reactive } from 'vue' import { reactive } from 'vue'
import { onPullDownRefresh, onLoad, onShow } from '@dcloudio/uni-app' import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import * as WodeAPI from '@/api/model/wode' import * as WodeAPI from '@/api/model/wode'
import * as NongchangAPI from '@/api/model/nongchang' import * as NongchangAPI from '@/api/model/nongchang'
...@@ -29,13 +29,14 @@ ...@@ -29,13 +29,14 @@
}, },
farmDescription: '华北绿色农业示范基地', farmDescription: '华北绿色农业示范基地',
settingsIcon: '/static/images/codefun/1458747d012f7cb820f99627876e8fa6.png', settingsIcon: '/static/images/codefun/1458747d012f7cb820f99627876e8fa6.png',
ncId: 0,
}, },
// 统计数据 // 统计数据
statistics: [ statistics: [
{ id: 1, value: '44', label: '我的基地' }, { id: 1, value: '0', label: '我的基地', url: '/pages/jidiguanli/jidiguanli' },
{ id: 2, value: '¥3266', label: '累计收益' }, { id: 2, value: '¥3266', label: '累计收益', url: '' },
{ id: 3, value: '8', label: '服务订单' }, { id: 3, value: '8', label: '服务订单', url: '' },
], ],
// 消息中心 // 消息中心
...@@ -175,7 +176,11 @@ ...@@ -175,7 +176,11 @@
pageData.commonResources.resources = records pageData.commonResources.resources = records
}) })
} }
function getFarmBaseList(id) {
NongchangAPI.getFarmBaseList({ id }).then((res) => {
pageData.statistics[0].value = res.length
})
}
function getFarmsList() { function getFarmsList() {
NongchangAPI.farmsList({ NongchangAPI.farmsList({
pageNo: 1, pageNo: 1,
...@@ -189,7 +194,9 @@ ...@@ -189,7 +194,9 @@
: '/static/images/codefun/b6079649e1f0ba231d158cb10bea118f.png' : '/static/images/codefun/b6079649e1f0ba231d158cb10bea118f.png'
pageData.userInfo.certification.text = records[0]?.certificationStatus_dictText pageData.userInfo.certification.text = records[0]?.certificationStatus_dictText
pageData.userInfo.farmDescription = records[0]?.description pageData.userInfo.farmDescription = records[0]?.description
pageData.statistics[0].value = total pageData.userInfo.ncId = records[0]?.id
getFarmBaseList(pageData.userInfo.ncId)
}) })
} }
...@@ -296,7 +303,7 @@ ...@@ -296,7 +303,7 @@
}) })
} else { } else {
uni.hideLoading() uni.hideLoading()
Message.toast('下载失败,状态码: ' + res.statusCode) Message.toast(`下载失败,状态码: ${res.statusCode}`)
} }
}, },
fail: (err) => { fail: (err) => {
...@@ -372,15 +379,18 @@ ...@@ -372,15 +379,18 @@
</view> </view>
<view class="codefun-flex-col codefun-justify-start section_3"> <view class="codefun-flex-col codefun-justify-start section_3">
<view class="codefun-flex-row"> <view class="codefun-flex-row">
<view <navigator
v-for="stat in pageData.statistics" v-for="stat in pageData.statistics"
:url="stat.url"
:key="stat.id" :key="stat.id"
class="codefun-flex-col codefun-items-center group_6 equal-division-item" class="codefun-flex-col codefun-items-center group_6 equal-division-item"
hover-class="none"
:render-link="false"
:class="{ 'codefun-ml-32': stat.id > 1 }" :class="{ 'codefun-ml-32': stat.id > 1 }"
> >
<text class="font_4">{{ stat.value }}</text> <text class="font_4">{{ stat.value }}</text>
<text class="font_5 codefun-mt-16">{{ stat.label }}</text> <text class="font_5 codefun-mt-16">{{ stat.label }}</text>
</view> </navigator>
</view> </view>
</view> </view>
</view> </view>
......
import { defineStore } from 'pinia'
import { store } from '/@/store'
import { Storage } from '@/utils/storage'
import { FARM_ID_KEY } from '@/enums/cacheEnum'
export interface Farm {
id: string
farmName: string
farmType: string
farmTypeText: string
}
interface FarmState {
info: Nullable<Farm>
}
export const useFarmStore = defineStore({
id: 'farm',
state: (): FarmState => ({
info: null,
}),
getters: {
getFarm(): Nullable<Farm> {
if (this.info) {
return this.info
}
const storedInfo = Storage.get(FARM_ID_KEY)
if (storedInfo) {
const parsedInfo = JSON.parse(storedInfo) as Farm
this.info = parsedInfo
return parsedInfo
}
return null
},
},
actions: {
setFarmInfo(info: Farm) {
console.log('setFarmInfo', info)
this.info = info
if (!info) {
Storage.remove(FARM_ID_KEY)
} else {
Storage.set(FARM_ID_KEY, info ? JSON.stringify(info) : null)
}
},
},
})
// Need to be used outside the setup
export function useFarmStoreWithOut() {
return useFarmStore(store)
}
\ No newline at end of file
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/ */
@import '@/uni_modules/uview-plus/theme.scss';
/* 颜色变量 */ /* 颜色变量 */
/* 行为相关颜色 */ /* 行为相关颜色 */
......
MIT License
Copyright (c) 2024 https://uiadmin.net/uview-plus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
<p align="center">
<img alt="logo" src="https://uiadmin.net/uview-plus/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uview-plus 3.0</h3>
<h3 align="center">多平台快速开发的UI框架</h3>
[![stars](https://img.shields.io/github/stars/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus)
[![forks](https://img.shields.io/github/forks/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus)
[![issues](https://img.shields.io/github/issues/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus/issues)
[![release](https://img.shields.io/github/v/release/ijry/uview-plus?style=flat-square)](https://gitee.com/jry/uview-plus/releases)
[![license](https://img.shields.io/github/license/ijry/uview-plus?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
## 说明
uview-plus,是uni-app全面兼容vue3/nvue/鸿蒙/uni-app-x(即将发布)的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。
## 可视化设计
uview-plus现已推出免费可视化设计,可以方便的进行页面可视化设计,导出源码即可使用。极大提高前端页面开发效率;如产品经理设计师直接使用更可作为高保真高可用原型制作工具,让设计稿即代码,无需传统的设计稿开发还原步骤。
<img src="https://s3.bmp.ovh/imgs/2024/11/24/fd58d00071e6e5df.png" width="900" height="auto" >
<img src="https://s3.bmp.ovh/imgs/2024/11/24/8e85a519fe627fb1.png" width="900" height="auto" >
## 文档
[官方文档:https://uview-plus.jiangruyi.com](https://uview-plus.jiangruyi.com)
[备用文档:https://uiadmin.net/uview-plus](https://uiadmin.net/uview-plus)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uview-plus.jiangruyi.com/common/h5_qrcode.png" width="220" height="220" >
## 链接
- [官方文档](https://uview-plus.jiangruyi.com)
- [更新日志](https://uview-plus.jiangruyi.com/components/changelog.html)
- [升级指南](https://uview-plus.jiangruyi.com/components/changeGuide.html)
- [关于我们](https://uview-plus.jiangruyi.com/cooperation/about.html)
## 交流反馈
欢迎加入我们的QQ群交流反馈:[点此跳转](https://uview-plus.jiangruyi.com/components/addQQGroup.html)
## 关于PR
> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uview-plus是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢!
## 安装
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?name=uview-plus](https://ext.dcloud.net.cn/plugin?name=uview-plus)
请通过[官网安装文档](https://uview-plus.jiangruyi.com/components/install.html)了解更详细的内容
## 快速上手
请通过[快速上手](https://uview-plus.jiangruyi.com/components/quickstart.html)了解更详细的内容
## 使用方法
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
```html
<template>
<u-button text="按钮"></u-button>
</template>
```
## 版权信息
uview-plus遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uview-plus应用到您的产品中。
<template>
<view class="u-action-sheet-data">
<view class="u-action-sheet-data__trigger">
<slot name="trigger"></slot>
<up-input
v-if="!$slots['trigger']"
:modelValue="current"
disabled
disabledColor="#ffffff"
:placeholder="title"
border="none"
></up-input>
<view @click="show = true"
class="u-action-sheet-data__trigger__cover"></view>
</view>
<up-action-sheet
:show="show"
:actions="options"
:title="title"
safeAreaInsetBottom
:description="description"
@close="show = false"
@select="select"
>
</up-action-sheet>
</view>
</template>
<script>
export default {
props: {
modelValue: {
type: [String, Number],
default: ''
},
title: {
type: String,
default: ''
},
description: {
type: String,
default: ''
},
options: {
type: Array,
default: () => {
return []
}
},
valueKey: {
type: String,
default: 'value'
},
labelKey: {
type: String,
default: 'name'
}
},
data() {
return {
show: false,
current: '',
}
},
created() {
if (this.modelValue) {
this.options.forEach((ele) => {
if (ele[this.valueKey] == this.modelValue) {
this.current = ele[this.labelKey]
}
})
}
},
emits: ['update:modelValue'],
watch: {
modelValue() {
this.options.forEach((ele) => {
if (ele[this.valueKey] == this.modelValue) {
this.current = ele[this.labelKey]
}
})
}
},
methods: {
hideKeyboard() {
uni.hideKeyboard()
},
select(e) {
this.$emit('update:modelValue', e[this.valueKey])
this.current = e[this.labelKey]
},
}
}
</script>
<style lang="scss" scoped>
.u-action-sheet-data {
&__trigger {
position: relative;
&__cover {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
}
</style>
\ No newline at end of file
/*
* @Author : LQ
* @Description :
* @version : 3.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : jry
* @lastTime : 2025-08-16 10:52:35
* @FilePath : /uview-plus/libs/config/props/actionSheet.js
*/
export default {
// action-sheet组件
actionSheet: {
show: false,
title: '',
description: '',
actions: [],
index: '',
cancelText: '',
closeOnClickAction: true,
safeAreaInsetBottom: true,
openType: '',
closeOnClickOverlay: true,
round: 0,
wrapMaxHeight: '600px'
}
}
/*
* @Author : LQ
* @Description :
* @version : 3.0
* @LastAuthor : jry
* @lastTime : 2025-08-16 10:52:35
* @FilePath : /uview-plus/libs/config/props/props.js
*/
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 操作菜单是否展示 (默认false)
show: {
type: Boolean,
default: () => defProps.actionSheet.show
},
// 标题
title: {
type: String,
default: () => defProps.actionSheet.title
},
// 选项上方的描述信息
description: {
type: String,
default: () => defProps.actionSheet.description
},
// 数据
actions: {
type: Array,
default: () => defProps.actionSheet.actions
},
// 取消按钮的文字,不为空时显示按钮
cancelText: {
type: String,
default: () => defProps.actionSheet.cancelText
},
// 点击某个菜单项时是否关闭弹窗
closeOnClickAction: {
type: Boolean,
default: () => defProps.actionSheet.closeOnClickAction
},
// 处理底部安全区(默认true)
safeAreaInsetBottom: {
type: Boolean,
default: () => defProps.actionSheet.safeAreaInsetBottom
},
// 小程序的打开方式
openType: {
type: String,
default: () => defProps.actionSheet.openType
},
// 点击遮罩是否允许关闭 (默认true)
closeOnClickOverlay: {
type: Boolean,
default: () => defProps.actionSheet.closeOnClickOverlay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: () => defProps.actionSheet.round
},
// 选项区域最大高度
wrapMaxHeight: {
type: [String],
default: () => defProps.actionSheet.wrapMaxHeight
},
}
})
<style scoped lang="scss">
.agreement-content {
width: 100%;;
display: inline-block;
flex-direction: column;
.agreement-url {
display: inline-block;
color: blue;
// #ifdef H5
cursor: pointer;
// #endif
}
}
</style>
<template>
<view class="up-agreement">
<up-modal v-model:show="show" showCancelButton @confirm="confirm" @cancel="close" confirmText="阅读并同意">
<view class="agreement-content">
<slot>
我们非常重视您的个人信息和隐私保护。为了更好地保障您的个人权益,在您使用我们的产品前,
请务必审慎阅读《<text class="agreement-url" @click="urlClick('urlProtocol')">用户协议</text>
和《<text class="agreement-url" @click="urlClick('urlPrivacy')">隐私政策</text>》内的所有条款,
尤其是:1.我们对您的个人信息的收集/保存/使用/对外提供/保护等规则条款,以及您的用户权利等条款;2. 约定我们的限制责任、免责
条款;3.其他以颜色或加粗进行标识的重要条款。如您对以上协议有任何疑问,请先不要同意,您点击“同意并继续”的行为即表示您已阅读
完毕并同意以上协议的全部内容。
</slot>
</view>
</up-modal>
</view>
</template>
<script>
export default {
name: 'up-agreement',
props: {
urlProtocol: {
type: String,
default: '/pages/user_agreement/agreement/info?title=用户协议'
},
urlPrivacy: {
type: String,
default: '/pages/user_agreement/agreement/info?title=隐私政策'
},
},
emits: ['confirm'],
data() {
return {
show: false
}
},
methods: {
close() {
// #ifdef H5
window.opener = null;
window.close();
// #endif
// #ifdef APP-PLUS
plus.runtime.quit();
// #endif
},
confirm() {
this.show = false;
this.$emit('confirm', 1);
},
showModal() {
this.show = true;
},
urlClick(type) {
uni.navigateTo({
url: this[type]
});
}
}
}
</script>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : jry
* @lastTime : 2025-08-16 16:32:24
* @FilePath : /uview-plus/libs/config/props/album.js
*/
export default {
// album 组件
album: {
urls: [],
keyName: '',
singleSize: 180,
multipleSize: 70,
space: 6,
singleMode: 'scaleToFill',
multipleMode: 'aspectFill',
maxCount: 9,
previewFullImage: true,
rowCount: 3,
showMore: true,
autoWrap: false,
unit: 'px',
stop: true,
}
}
/*
* @Author : jry
* @Description :
* @version : 3.0
* @LastAuthor : jry
* @lastTime : 2025-08-16 16:35:24
* @FilePath : /uview-plus/components/u-album/props.js
*/
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 图片地址,Array<String>|Array<Object>形式
urls: {
type: Array,
default: () => defProps.album.urls
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: () => defProps.album.keyName
},
// 单图时,图片长边的长度
singleSize: {
type: [String, Number],
default: () => defProps.album.singleSize
},
// 多图时,图片边长
multipleSize: {
type: [String, Number],
default: () => defProps.album.multipleSize
},
// 多图时,图片水平和垂直之间的间隔
space: {
type: [String, Number],
default: () => defProps.album.space
},
// 单图时,图片缩放裁剪的模式
singleMode: {
type: String,
default: () => defProps.album.singleMode
},
// 多图时,图片缩放裁剪的模式
multipleMode: {
type: String,
default: () => defProps.album.multipleMode
},
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
maxCount: {
type: [String, Number],
default: () => defProps.album.maxCount
},
// 是否可以预览图片
previewFullImage: {
type: Boolean,
default: () => defProps.album.previewFullImage
},
// 每行展示图片数量,如设置,singleSize和multipleSize将会无效
rowCount: {
type: [String, Number],
default: () => defProps.album.rowCount
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: () => defProps.album.showMore
},
// 图片形状,circle-圆形,square-方形
shape: {
type: String,
default: () => defProps.image.shape
},
// 圆角,单位任意
radius: {
type: [String, Number],
default: () => defProps.image.radius
},
// 自适应换行
autoWrap: {
type: Boolean,
default: () => defProps.album.autoWrap
},
// 单位
unit: {
type: [String],
default: () => defProps.album.unit
},
// 阻止点击冒泡
stop: {
type: Boolean,
default: () => defProps.album.stop
}
}
})
/*
* @Author : LQ
* @Description :
* @version : 3.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : jry
* @lastTime : 2025-08-17 17:23:53
* @FilePath : /uview-plus/libs/config/props/alert.js
*/
export default {
// alert警告组件
alert: {
title: '',
type: 'warning',
description: '',
closable: false,
showIcon: false,
effect: 'light',
center: false,
fontSize: 14,
transitionMode: 'fade',
duration: 0,
icon: '',
value: true
}
}
/*
* @Author : jry
* @Description :
* @version : 3.0
* @LastAuthor : jry
* @lastTime : 2025-08-17 17:23:53
* @FilePath : /uview-plus/libs/config/props/props.js
*/
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 显示文字
title: {
type: String,
default: () => defProps.alert.title
},
// 主题,success/warning/info/error
type: {
type: String,
default: () => defProps.alert.type
},
// 辅助性文字
description: {
type: String,
default: () => defProps.alert.description
},
// 是否可关闭
closable: {
type: Boolean,
default: () => defProps.alert.closable
},
// 是否显示图标
showIcon: {
type: Boolean,
default: () => defProps.alert.showIcon
},
// 浅或深色调,light-浅色,dark-深色
effect: {
type: String,
default: () => defProps.alert.effect
},
// 文字是否居中
center: {
type: Boolean,
default: () => defProps.alert.center
},
// 字体大小
fontSize: {
type: [String, Number],
default: () => defProps.alert.fontSize
},
// 动画类型
transitionMode: {
type: [String],
default: () => defProps.alert.transitionMode
},
// 自动定时关闭毫秒
duration: {
type: [Number],
default: () => defProps.alert.duration
},
// 自定义图标
icon: {
type: [String],
default: () => defProps.alert.icon
},
// 是否显示
modelValue: {
type: [Boolean],
default: () => defProps.alert.value
}
}
})
<template>
<up-transition
:mode="transitionMode"
:show="show"
>
<view
class="u-alert"
:class="[`u-alert--${type}--${effect}`]"
@tap.stop="clickHandler"
:style="[addStyle(customStyle)]"
>
<!-- 左侧图标 -->
<view
class="u-alert__icon"
v-if="showIcon"
>
<up-icon
:name="iconName"
size="18"
:color="iconColor"
></up-icon>
</view>
<!-- 内容区域 -->
<view
class="u-alert__content"
:style="[{
paddingRight: closable ? '20px' : 0
}]"
>
<!-- 标题 -->
<text
class="u-alert__content__title"
v-if="title"
:style="[{
fontSize: addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ title }}</text>
<!-- 描述信息 -->
<text
class="u-alert__content__desc"
v-if="description"
:style="[{
fontSize: addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ description }}</text>
</view>
<!-- 关闭按钮 -->
<view
class="u-alert__close"
v-if="closable"
@tap.stop="closeHandler"
>
<slot name="close">
<up-icon
name="close"
:color="iconColor"
size="15"
></up-icon>
</slot>
</view>
</view>
</up-transition>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addUnit, addStyle } from '../../libs/function/index';
/**
* Alert 警告提示
* @description 警告提示,展现需要关注的信息。
* @tutorial https://ijry.github.io/uview-plus/components/alertTips.html
*
* @property {String} title 显示的文字
* @property {String} type 使用预设的颜色 (默认 'warning' )
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )
* @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )
* @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' )
* @property {Boolean} center 文字是否居中 (默认 false )
* @property {String | Number} fontSize 字体大小 (默认 14 )
* @property {Object} customStyle 定义需要用到的外部样式
* @property {String} transitionMode 过渡动画模式 (默认 'fade' )
* @property {String | Number} duration 自动关闭延时(毫秒),设置为0或负数则不自动关闭 (默认 0 )
* @property {String} icon 自定义图标名称,优先级高于type默认图标
* @property {Boolean} modelValue/v-model 绑定值,控制是否显示 (默认 true )
* @event {Function} click 点击组件时触发
* @event {Function} close 点击关闭按钮时触发
* @event {Function} closed 关闭动画结束时触发
* @example <up-alert :title="title" type = "warning" :closable="closable" :description = "description"></up-alert>
*/
export default {
name: 'u-alert',
mixins: [mpMixin, mixin, props],
data() {
return {
// 控制组件显示隐藏
show: true
}
},
computed: {
// 根据不同的主题类型返回对应的图标颜色
iconColor() {
return this.effect === 'light' ? this.type : '#fff'
},
// 不同主题对应不同的图标
iconName() {
// 如果用户自定义了图标,则优先使用自定义图标
if (this.icon) return this.icon;
switch (this.type) {
case 'success':
return 'checkmark-circle-fill';
break;
case 'error':
return 'close-circle-fill';
break;
case 'warning':
return 'error-circle-fill';
break;
case 'info':
return 'info-circle-fill';
break;
case 'primary':
return 'more-circle-fill';
break;
default:
return 'error-circle-fill';
}
}
},
emits: ["click","close", "closed", "update:modelValue"],
watch: {
modelValue: {
handler(newVal) {
this.show = newVal;
},
immediate: true
},
show: {
handler(newVal) {
this.$emit('update:modelValue', newVal);
// 如果是从显示到隐藏,且启用了自动关闭功能
if (!newVal && this.duration > 0) {
this.$emit('closed');
}
}
}
},
mounted() {
// 如果设置了自动关闭时间,则在指定时间后自动关闭
if (this.duration > 0) {
setTimeout(() => {
this.closeHandler();
}, this.duration);
}
},
methods: {
addUnit,
addStyle,
// 点击内容区域触发click事件
clickHandler() {
this.$emit('click')
},
// 点击关闭按钮触发close事件并隐藏组件
closeHandler() {
this.show = false
this.$emit('close');
}
}
}
</script>
<style lang="scss" scoped>
.u-alert {
position: relative;
background-color: $u-primary;
padding: 8px 10px;
@include flex(row);
align-items: center;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
&--primary--dark {
background-color: $u-primary;
}
&--primary--light {
background-color: #ecf5ff;
}
&--error--dark {
background-color: $u-error;
}
&--error--light {
background-color: #FEF0F0;
}
&--success--dark {
background-color: $u-success;
}
&--success--light {
background-color: #f5fff0;
}
&--warning--dark {
background-color: $u-warning;
}
&--warning--light {
background-color: #FDF6EC;
}
&--info--dark {
background-color: $u-info;
}
&--info--light {
background-color: #f4f4f5;
}
&__icon {
margin-right: 5px;
}
&__content {
@include flex(column);
flex: 1;
&__title {
color: $u-main-color;
font-size: 14px;
font-weight: bold;
color: #fff;
margin-bottom: 2px;
}
&__desc {
color: $u-main-color;
font-size: 14px;
flex-wrap: wrap;
color: #fff;
}
}
&__title--dark,
&__desc--dark {
color: #FFFFFF;
}
&__text--primary--light,
&__text--primary--light {
color: $u-primary;
}
&__text--success--light,
&__text--success--light {
color: $u-success;
}
&__text--warning--light,
&__text--warning--light {
color: $u-warning;
}
&__text--error--light,
&__text--error--light {
color: $u-error;
}
&__text--info--light,
&__text--info--light {
color: $u-info;
}
&__close {
position: absolute;
top: 11px;
right: 10px;
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:49:55
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatarGroup.js
*/
export default {
// avatarGroup 组件
avatarGroup: {
urls: [],
maxCount: 5,
shape: 'circle',
mode: 'scaleToFill',
showMore: true,
size: 40,
keyName: '',
gap: 0.5,
extraValue: 0
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 头像图片组
urls: {
type: Array,
default: () => defProps.avatarGroup.urls
},
// 最多展示的头像数量
maxCount: {
type: [String, Number],
default: () => defProps.avatarGroup.maxCount
},
// 头像形状
shape: {
type: String,
default: () => defProps.avatarGroup.shape
},
// 图片裁剪模式
mode: {
type: String,
default: () => defProps.avatarGroup.mode
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: () => defProps.avatarGroup.showMore
},
// 头像大小
size: {
type: [String, Number],
default: () => defProps.avatarGroup.size
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: () => defProps.avatarGroup.keyName
},
// 头像之间的遮挡比例
gap: {
type: [String, Number],
validator(value) {
return value >= 0 && value <= 1
},
default: () => defProps.avatarGroup.gap
},
// 需额外显示的值
extraValue: {
type: [Number, String],
default: () => defProps.avatarGroup.extraValue
}
}
})
<template>
<view class="u-avatar-group">
<view
class="u-avatar-group__item"
v-for="(item, index) in showUrl"
:key="index"
:style="{
marginLeft: index === 0 ? 0 : addUnit(-size * gap)
}"
>
<u-avatar
:size="size"
:shape="shape"
:mode="mode"
:src="testObject(item) ? keyName && item[keyName] || item.url : item"
></u-avatar>
<view
class="u-avatar-group__item__show-more"
v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
@tap="clickHandler"
>
<up-text
color="#ffffff"
:size="size * 0.4"
:text="`+${extraValue || urls.length - showUrl.length}`"
align="center"
customStyle="justify-content: center"
></up-text>
</view>
</view>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addUnit } from '../../libs/function/index';
import test from '../../libs/function/test';
/**
* AvatarGroup 头像组
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html
*
* @property {Array} urls 头像图片组 (默认 [] )
* @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
* @property {String} shape 头像形状( 'circle' (默认) | 'square' )
* @property {String} mode 图片裁剪模式(默认 'scaleToFill' )
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
* @property {String | Number} size 头像大小 (默认 40 )
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} gap 头像之间的遮挡比例(0.4代表遮挡40%) (默认 0.5 )
* @property {String | Number} extraValue 需额外显示的值
* @event {Function} showMore 头像组更多点击
* @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
*/
export default {
name: 'u-avatar-group',
mixins: [mpMixin, mixin, props],
data() {
return {
}
},
computed: {
showUrl() {
return this.urls.slice(0, this.maxCount)
}
},
emits: ["showMore"],
methods: {
addUnit,
testObject: test.object,
clickHandler() {
this.$emit('showMore')
}
},
}
</script>
<style lang="scss" scoped>
.u-avatar-group {
@include flex;
&__item {
margin-left: -10px;
position: relative;
&--no-indent {
// 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持
margin-left: 0;
}
&__show-more {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex;
align-items: center;
justify-content: center;
border-radius: 100px;
}
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:49:22
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatar.js
*/
export default {
// avatar 组件
avatar: {
src: '',
shape: 'circle',
size: 40,
mode: 'scaleToFill',
text: '',
bgColor: '#c0c4cc',
color: '#ffffff',
fontSize: 18,
icon: '',
mpAvatar: false,
randomBgColor: false,
defaultUrl: '',
colorIndex: '',
name: ''
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
import test from '../../libs/function/test';
export const props = defineMixin({
props: {
// 头像图片路径(不能为相对路径)
src: {
type: String,
default: () => defProps.avatar.src
},
// 头像形状,circle-圆形,square-方形
shape: {
type: String,
default: () => defProps.avatar.shape
},
// 头像尺寸
size: {
type: [String, Number],
default: () => defProps.avatar.size
},
// 裁剪模式
mode: {
type: String,
default: () => defProps.avatar.mode
},
// 显示的文字
text: {
type: String,
default: () => defProps.avatar.text
},
// 背景色
bgColor: {
type: String,
default: () => defProps.avatar.bgColor
},
// 文字颜色
color: {
type: String,
default: () => defProps.avatar.color
},
// 文字大小
fontSize: {
type: [String, Number],
default: () => defProps.avatar.fontSize
},
// 显示的图标
icon: {
type: String,
default: () => defProps.avatar.icon
},
// 显示小程序头像,只对百度,微信,QQ小程序有效
mpAvatar: {
type: Boolean,
default: () => defProps.avatar.mpAvatar
},
// 是否使用随机背景色
randomBgColor: {
type: Boolean,
default: () => defProps.avatar.randomBgColor
},
// 加载失败的默认头像(组件有内置默认图片)
defaultUrl: {
type: String,
default: () => defProps.avatar.defaultUrl
},
// 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
colorIndex: {
type: [String, Number],
// 校验参数规则,索引在0-19之间
validator(n) {
return test.range(n, [0, 19]) || n === ''
},
default: () => defProps.avatar.colorIndex
},
// 组件标识符
name: {
type: String,
default: () => defProps.avatar.name
}
}
})
<template>
<view
class="u-avatar"
:class="[`u-avatar--${shape}`]"
:style="[{
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : random(0, 19)] : bgColor) : 'transparent',
width: addUnit(size),
height: addUnit(size),
}, addStyle(customStyle)]"
@tap="clickHandler"
>
<slot>
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
<open-data
v-if="mpAvatar && allowMp"
type="userAvatarUrl"
:style="[{
width: addUnit(size),
height: addUnit(size)
}]"
/>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
<template v-if="mpAvatar && allowMp"></template>
<!-- #endif -->
<up-icon
v-else-if="icon"
:name="icon"
:size="fontSize"
:color="color"
></up-icon>
<up-text
v-else-if="text"
:text="text"
:size="fontSize"
:color="color"
align="center"
customStyle="justify-content: center"
></up-text>
<image
class="u-avatar__image"
v-else
:class="[`u-avatar__image--${shape}`]"
:src="avatarUrl || defaultUrl"
:mode="mode"
@error="errorHandler"
:style="[{
width: addUnit(size),
height: addUnit(size)
}]"
></image>
</slot>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle, addUnit, random } from '../../libs/function/index';
const base64Avatar =
"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";
/**
* Avatar 头像
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html
*
* @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径)
* @property {String} shape 头像形状 ( circle (默认) | square)
* @property {String | Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 )
* @property {String} mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' )
* @property {String} text 用文字替代图片,级别优先于src
* @property {String} bgColor 背景颜色,一般显示文字时用 (默认 '#c0c4cc' )
* @property {String} color 文字颜色 (默认 '#ffffff' )
* @property {String | Number} fontSize 文字大小 (默认 18 )
* @property {String} icon 显示的图标
* @property {Boolean} mpAvatar 显示小程序头像,只对百度,微信,QQ小程序有效 (默认 false )
* @property {Boolean} randomBgColor 是否使用随机背景色 (默认 false )
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
* @property {String | Number} colorIndex 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
* @property {String} name 组件标识符 (默认 'level' )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击组件时触发 index: 用户传递的标识符
* @example <u-avatar :src="src" mode="square"></u-avatar>
*/
export default {
name: 'u-avatar',
mixins: [mpMixin, mixin, props],
data() {
return {
// 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
'#73d1f1',
'#80a7dc'
],
avatarUrl: this.src,
allowMp: false
}
},
watch: {
// 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值
// 而组件内部不能直接修改props的值,所以需要一个中间变量
src: {
immediate: true,
handler(newVal) {
this.avatarUrl = newVal
// 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示
if(!newVal) {
this.errorHandler()
}
}
}
},
computed: {
imageStyle() {
const style = {}
return style
}
},
created() {
this.init()
},
emits: ["click"],
methods: {
addStyle,
addUnit,
random,
init() {
// 目前只有这几个小程序平台具有open-data标签
// 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑
// 故目前自动获取小程序头像只支持这几个平台
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
this.allowMp = true
// #endif
},
// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
isImg() {
return this.src.indexOf('/') !== -1
},
// 图片加载时失败时触发
errorHandler() {
this.avatarUrl = this.defaultUrl || base64Avatar
},
clickHandler(e) {
this.$emit('click', this.name, e)
}
}
}
</script>
<style lang="scss" scoped>
.u-avatar {
@include flex;
align-items: center;
justify-content: center;
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
&__image {
&--circle {
border-radius: 100px;
overflow: hidden;
}
&--square {
border-radius: 4px;
}
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:50:18
* @FilePath : /u-view2.0/uview-ui/libs/config/props/backtop.js
*/
export default {
// backtop组件
backtop: {
mode: 'circle',
icon: 'arrow-upward',
text: '',
duration: 100,
scrollTop: 0,
top: 400,
bottom: 100,
right: 20,
zIndex: 9,
iconStyle: {
color: '#909399',
fontSize: '19px'
}
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 返回顶部的形状,circle-圆形,square-方形
mode: {
type: String,
default: () => defProps.backtop.mode
},
// 自定义图标
icon: {
type: String,
default: () => defProps.backtop.icon
},
// 提示文字
text: {
type: String,
default: () => defProps.backtop.text
},
// 返回顶部滚动时间
duration: {
type: [String, Number],
default: () => defProps.backtop.duration
},
// 滚动距离
scrollTop: {
type: [String, Number],
default: () => defProps.backtop.scrollTop
},
// 距离顶部多少距离显示,单位px
top: {
type: [String, Number],
default: () => defProps.backtop.top
},
// 返回顶部按钮到底部的距离,单位px
bottom: {
type: [String, Number],
default: () => defProps.backtop.bottom
},
// 返回顶部按钮到右边的距离,单位px
right: {
type: [String, Number],
default: () => defProps.backtop.right
},
// 层级
zIndex: {
type: [String, Number],
default: () => defProps.backtop.zIndex
},
// 图标的样式,对象形式
iconStyle: {
type: Object,
default: () => defProps.backtop.iconStyle
}
}
})
<template>
<u-transition
mode="fade"
:customStyle="backTopStyle"
:show="show"
>
<view
class="u-back-top"
:style="[contentStyle]"
v-if="!$slots.default && !$slots.$default"
@click="backToTop"
>
<up-icon
:name="icon"
:custom-style="iconStyle"
></up-icon>
<text
v-if="text"
class="u-back-top__text"
>{{text}}</text>
</view>
<slot v-else />
</u-transition>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addUnit, addStyle, getPx, deepMerge, error } from '../../libs/function/index';
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* backTop 返回顶部
* @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
* @tutorial https://uview-plus.jiangruyi.com/components/backTop.html
*
* @property {String} mode 返回顶部的形状,circle-圆形,square-方形 (默认 'circle' )
* @property {String} icon 自定义图标 (默认 'arrow-upward' ) 见官方文档示例
* @property {String} text 提示文字
* @property {String | Number} duration 返回顶部滚动时间 (默认 100)
* @property {String | Number} scrollTop 滚动距离 (默认 0 )
* @property {String | Number} top 距离顶部多少距离显示,单位px (默认 400 )
* @property {String | Number} bottom 返回顶部按钮到底部的距离,单位px (默认 100 )
* @property {String | Number} right 返回顶部按钮到右边的距离,单位px (默认 20 )
* @property {String | Number} zIndex 层级 (默认 9 )
* @property {Object<Object>} iconStyle 图标的样式,对象形式 (默认 {color: '#909399',fontSize: '19px'})
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <u-back-top :scrollTop="scrollTop"></u-back-top>
*/
export default {
name: 'u-back-top',
mixins: [mpMixin, mixin, props],
computed: {
backTopStyle() {
// 动画组件样式
const style = {
bottom: addUnit(this.bottom),
right: addUnit(this.right),
width: '40px',
height: '40px',
position: 'fixed',
zIndex: 10,
}
return style
},
show() {
return getPx(this.scrollTop) > getPx(this.top)
},
contentStyle() {
const style = {}
let radius = 0
// 是否圆形
if(this.mode === 'circle') {
radius = '100px'
} else {
radius = '4px'
}
// 为了兼容安卓nvue,只能这么分开写
style.borderTopLeftRadius = radius
style.borderTopRightRadius = radius
style.borderBottomLeftRadius = radius
style.borderBottomRightRadius = radius
return deepMerge(style, addStyle(this.customStyle))
}
},
emits: ["click"],
methods: {
backToTop() {
// #ifdef APP-NVUE
if (!this.$parent.$refs['u-back-top']) {
error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
}
dom.scrollToElement(this.$parent.$refs['u-back-top'], {
offset: 0
})
// #endif
// #ifndef APP-NVUE
uni.pageScrollTo({
scrollTop: 0,
duration: this.duration
});
// #endif
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
$u-back-top-flex:1 !default;
$u-back-top-height:100% !default;
$u-back-top-background-color:#E1E1E1 !default;
$u-back-top-tips-font-size:12px !default;
.u-back-top {
@include flex;
flex-direction: column;
align-items: center;
flex:$u-back-top-flex;
height: $u-back-top-height;
justify-content: center;
background-color: $u-back-top-background-color;
&__tips {
font-size:$u-back-top-tips-font-size;
transform: scale(0.8);
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-23 19:51:50
* @FilePath : /u-view2.0/uview-ui/libs/config/props/badge.js
*/
export default {
// 徽标数组件
badge: {
isDot: false,
value: '',
show: true,
max: 999,
type: 'error',
showZero: false,
bgColor: null,
color: null,
shape: 'circle',
numberType: 'overflow',
offset: [],
inverted: false,
absolute: false
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 是否显示圆点
isDot: {
type: Boolean,
default: () => defProps.badge.isDot
},
// 显示的内容
value: {
type: [Number, String],
default: () => defProps.badge.value
},
// 显示的内容
modelValue: {
type: [Number, String],
default: () => defProps.badge.modelValue
},
// 是否显示
show: {
type: Boolean,
default: () => defProps.badge.show
},
// 最大值,超过最大值会显示 '{max}+'
max: {
type: [Number, String],
default: () => defProps.badge.max
},
// 主题类型,error|warning|success|primary
type: {
type: String,
default: () => defProps.badge.type
},
// 当数值为 0 时,是否展示 Badge
showZero: {
type: Boolean,
default: () => defProps.badge.showZero
},
// 背景颜色,优先级比type高,如设置,type参数会失效
bgColor: {
type: [String, null],
default: () => defProps.badge.bgColor
},
// 字体颜色
color: {
type: [String, null],
default: () => defProps.badge.color
},
// 徽标形状,circle-四角均为圆角,horn-左下角为直角
shape: {
type: String,
default: () => defProps.badge.shape
},
// 设置数字的显示方式,overflow|ellipsis|limit
// overflow会根据max字段判断,超出显示`${max}+`
// ellipsis会根据max判断,超出显示`${max}...`
// limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
numberType: {
type: String,
default: () => defProps.badge.numberType
},
// 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
offset: {
type: Array,
default: () => defProps.badge.offset
},
// 是否反转背景和字体颜色
inverted: {
type: Boolean,
default: () => defProps.badge.inverted
},
// 是否绝对定位
absolute: {
type: Boolean,
default: () => defProps.badge.absolute
}
}
})
<template>
<text
v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
:style="[addStyle(customStyle), badgeStyle]"
class="u-badge"
>{{ isDot ? '' :showValue }}</text>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle, addUnit } from '../../libs/function/index';
/**
* badge 徽标数
* @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
* @tutorial https://uview-plus.jiangruyi.com/components/badge.html
*
* @property {Boolean} isDot 是否显示圆点 (默认 false )
* @property {String | Number} value 显示的内容
* @property {Boolean} show 是否显示 (默认 true )
* @property {String | Number} max 最大值,超过最大值会显示 '{max}+' (默认999)
* @property {String} type 主题类型,error|warning|success|primary (默认 'error' )
* @property {Boolean} showZero 当数值为 0 时,是否展示 Badge (默认 false )
* @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
* @property {String} color 字体颜色 (默认 '#ffffff' )
* @property {String} shape 徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' )
* @property {String} numberType 设置数字的显示方式,overflow|ellipsis|limit (默认 'overflow' )
* @property {Array}} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
* @property {Boolean} inverted 是否反转背景和字体颜色(默认 false )
* @property {Boolean} absolute 是否绝对定位(默认 false )
* @property {Object} customStyle 定义需要用到的外部样式
* @example <u-badge :type="type" :count="count"></u-badge>
*/
export default {
name: 'u-badge',
mixins: [mpMixin, props, mixin],
computed: {
// 是否将badge中心与父组件右上角重合
boxStyle() {
let style = {};
return style;
},
// 整个组件的样式
badgeStyle() {
const style = {}
if(this.color) {
style.color = this.color
}
if (this.bgColor && !this.inverted) {
style.backgroundColor = this.bgColor
}
if (this.absolute) {
style.position = 'absolute'
// 如果有设置offset参数
if(this.offset.length) {
// top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top
const top = this.offset[0]
const right = this.offset[1] || top
style.top = addUnit(top)
style.right = addUnit(right)
}
}
return style
},
showValue() {
switch (this.numberType) {
case "overflow":
return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
break;
case "ellipsis":
return Number(this.value) > Number(this.max) ? "..." : this.value
break;
case "limit":
return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
1e3 * 100) / 100 + "k" : this.value
break;
default:
return Number(this.value)
}
},
},
methods: {
addStyle
}
}
</script>
<style lang="scss" scoped>
$u-badge-primary: $u-primary !default;
$u-badge-error: $u-error !default;
$u-badge-success: $u-success !default;
$u-badge-info: $u-info !default;
$u-badge-warning: $u-warning !default;
$u-badge-dot-radius: 100px !default;
$u-badge-dot-size: 8px !default;
$u-badge-dot-right: 4px !default;
$u-badge-dot-top: 0 !default;
$u-badge-text-font-size: 11px !default;
$u-badge-text-right: 10px !default;
$u-badge-text-padding: 2px 5px !default;
$u-badge-text-align: center !default;
$u-badge-text-color: #FFFFFF !default;
.u-badge {
border-top-right-radius: $u-badge-dot-radius;
border-top-left-radius: $u-badge-dot-radius;
border-bottom-left-radius: $u-badge-dot-radius;
border-bottom-right-radius: $u-badge-dot-radius;
@include flex;
line-height: $u-badge-text-font-size;
text-align: $u-badge-text-align;
font-size: $u-badge-text-font-size;
color: $u-badge-text-color;
&--dot {
height: $u-badge-dot-size;
width: $u-badge-dot-size;
}
&--inverted {
font-size: 13px;
}
&--not-dot {
padding: $u-badge-text-padding;
}
&--horn {
border-bottom-left-radius: 0;
}
&--primary {
background-color: $u-badge-primary;
}
&--primary--inverted {
color: $u-badge-primary;
}
&--error {
background-color: $u-badge-error;
}
&--error--inverted {
color: $u-badge-error;
}
&--success {
background-color: $u-badge-success;
}
&--success--inverted {
color: $u-badge-success;
}
&--info {
background-color: $u-badge-info;
}
&--info--inverted {
color: $u-badge-info;
}
&--warning {
background-color: $u-badge-warning;
}
&--warning--inverted {
color: $u-badge-warning;
}
}
</style>
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const propsBox = defineMixin({
props: {
// 背景色
bgColors: {
type: [Array],
default: ['#EEFCFF', '#FCF8FF', '#FDF8F2']
},
// 高度
height: {
type: [String],
default: "160px"
},
// 圆角
borderRadius: {
type: [String],
default: "6px"
},
// 间隔
gap: {
type: [String],
default: "15px"
},
}
})
<template>
<view class="u-box" :style="[{height: height}, addStyle(customStyle)]">
<view class="u-box__left" :style="{borderRadius: borderRadius, backgroundColor: bgColors[0]}">
<slot name="left"></slot>
</view>
<view class="u-box__gap" :style="{width: gap, height: height}"></view>
<view class="u-box__right">
<view class="u-box__right-top" :style="{borderRadius: borderRadius, backgroundColor: bgColors[1]}">
<slot name="rightTop">右上</slot>
</view>
<view class="u-box__right-gap" :style="{height: gap}"></view>
<view class="u-box__right-bottom" :style="{borderRadius: borderRadius, backgroundColor: bgColors[2]}">
<slot name="rightBottom">右下</slot>
</view>
</view>
</view>
</template>
<script>
import { propsBox } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle } from '../../libs/function/index';
import test from '../../libs/function/test';
/**
* box 盒子
* @description box盒子一般为左边一个盒子,右侧两个等高的半盒组成,常用于App首页座位重点突出。
* @tutorial https://uview-plus.jiangruyi.com/components/box.html
* @property {Array} bgColors 背景色
* @property {String} height 高度
* @property {String} borderRadius 圆角
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击cell列表时触发
* @example <up-box colors=['blue', 'red', 'yellow'] height="200px"></up-box>
*/
export default {
name: 'up-box',
data() {
return {
}
},
mixins: [mpMixin, mixin, propsBox],
computed: {
},
emits: [],
methods: {
addStyle,
}
}
</script>
<style lang="scss" scoped>
.u-box {
/* #ifndef APP-NVUE */
/* #endif */
@include flex();
flex: 1;
&__left {
@include flex();
justify-content: center;
align-items: center;
flex: 1;
}
&__gap {
@include flex();
flex-direction: column;
}
&__right {
@include flex();
flex-direction: column;
flex: 1;
}
&__right-top {
@include flex();
flex: 1;
justify-content: center;
align-items: center;
}
&__right-bottom {
@include flex();
flex: 1;
justify-content: center;
align-items: center;
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:51:27
* @FilePath : /u-view2.0/uview-ui/libs/config/props/button.js
*/
export default {
// button组件
button: {
hairline: false,
type: 'info',
size: 'normal',
shape: 'square',
plain: false,
disabled: false,
loading: false,
loadingText: '',
loadingMode: 'spinner',
loadingSize: 15,
openType: '',
formType: '',
appParameter: '',
hoverStopPropagation: true,
lang: 'en',
sessionFrom: '',
sendMessageTitle: '',
sendMessagePath: '',
sendMessageImg: '',
showMessageCard: false,
dataName: '',
throttleTime: 0,
hoverStartTime: 0,
hoverStayTime: 200,
text: '',
icon: '',
iconColor: '',
color: '',
stop: true,
}
}
$u-button-active-opacity:0.75 !default;
$u-button-loading-text-margin-left:4px !default;
$u-button-text-color: #FFFFFF !default;
$u-button-text-plain-error-color:$u-error !default;
$u-button-text-plain-warning-color:$u-warning !default;
$u-button-text-plain-success-color:$u-success !default;
$u-button-text-plain-info-color:$u-info !default;
$u-button-text-plain-primary-color:$u-primary !default;
.u-button {
&--active {
opacity: $u-button-active-opacity;
}
&--active--plain {
background-color: rgb(217, 217, 217);
}
&__loading-text {
margin-left:$u-button-loading-text-margin-left;
}
&__text,
&__loading-text {
color:$u-button-text-color;
}
&__text--plain--error {
color:$u-button-text-plain-error-color;
}
&__text--plain--warning {
color:$u-button-text-plain-warning-color;
}
&__text--plain--success{
color:$u-button-text-plain-success-color;
}
&__text--plain--info {
color:$u-button-text-plain-info-color;
}
&__text--plain--primary {
color:$u-button-text-plain-primary-color;
}
}
\ No newline at end of file
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 是否细边框
hairline: {
type: Boolean,
default: () => defProps.button.hairline
},
// 按钮的预置样式,info,primary,error,warning,success
type: {
type: String,
default: () => defProps.button.type
},
// 按钮尺寸,large,normal,small,mini
size: {
type: String,
default: () => defProps.button.size
},
// 按钮形状,circle(两边为半圆),square(带圆角)
shape: {
type: String,
default: () => defProps.button.shape
},
// 按钮是否镂空
plain: {
type: Boolean,
default: () => defProps.button.plain
},
// 是否禁止状态
disabled: {
type: Boolean,
default: () => defProps.button.disabled
},
// 是否加载中
loading: {
type: Boolean,
default: () => defProps.button.loading
},
// 加载中提示文字
loadingText: {
type: [String, Number],
default: () => defProps.button.loadingText
},
// 加载状态图标类型
loadingMode: {
type: String,
default: () => defProps.button.loadingMode
},
// 加载图标大小
loadingSize: {
type: [String, Number],
default: () => defProps.button.loadingSize
},
// 开放能力,具体请看uniapp稳定关于button组件部分说明
// https://uniapp.dcloud.io/component/button
openType: {
type: String,
default: () => defProps.button.openType
},
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
// 取值为submit(提交表单),reset(重置表单)
formType: {
type: String,
default: () => defProps.button.formType
},
// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
// 只微信小程序、QQ小程序有效
appParameter: {
type: String,
default: () => defProps.button.appParameter
},
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
hoverStopPropagation: {
type: Boolean,
default: () => defProps.button.hoverStopPropagation
},
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
lang: {
type: String,
default: () => defProps.button.lang
},
// 会话来源,open-type="contact"时有效。只微信小程序有效
sessionFrom: {
type: String,
default: () => defProps.button.sessionFrom
},
// 会话内消息卡片标题,open-type="contact"时有效
// 默认当前标题,只微信小程序有效
sendMessageTitle: {
type: String,
default: () => defProps.button.sendMessageTitle
},
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
// 默认当前分享路径,只微信小程序有效
sendMessagePath: {
type: String,
default: () => defProps.button.sendMessagePath
},
// 会话内消息卡片图片,open-type="contact"时有效
// 默认当前页面截图,只微信小程序有效
sendMessageImg: {
type: String,
default: () => defProps.button.sendMessageImg
},
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
showMessageCard: {
type: Boolean,
default: () => defProps.button.showMessageCard
},
// 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
dataName: {
type: String,
default: () => defProps.button.dataName
},
// 节流,一定时间内只能触发一次
throttleTime: {
type: [String, Number],
default: () => defProps.button.throttleTime
},
// 按住后多久出现点击态,单位毫秒
hoverStartTime: {
type: [String, Number],
default: () => defProps.button.hoverStartTime
},
// 手指松开后点击态保留时间,单位毫秒
hoverStayTime: {
type: [String, Number],
default: () => defProps.button.hoverStayTime
},
// 按钮文字,之所以通过props传入,是因为slot传入的话
// nvue中无法控制文字的样式
text: {
type: [String, Number],
default: () => defProps.button.text
},
// 按钮图标
icon: {
type: String,
default: () => defProps.button.icon
},
// 按钮图标
iconColor: {
type: String,
default: () => defProps.button.icon
},
// 按钮颜色,支持传入linear-gradient渐变色
color: {
type: String,
default: () => defProps.button.color
},
// 停止冒泡
stop: {
type: Boolean,
default: () => defProps.button.stop
},
}
})
// nvue下hover-class无效
$u-button-before-top:50% !default;
$u-button-before-left:50% !default;
$u-button-before-width:100% !default;
$u-button-before-height:100% !default;
$u-button-before-transform:translate(-50%, -50%) !default;
$u-button-before-opacity:0 !default;
$u-button-before-background-color:#000 !default;
$u-button-before-border-color:#000 !default;
$u-button-active-before-opacity:.15 !default;
$u-button-icon-margin-left:4px !default;
$u-button-plain-u-button-info-color:$u-info;
$u-button-plain-u-button-success-color:$u-success;
$u-button-plain-u-button-error-color:$u-error;
$u-button-plain-u-button-warning-color:$u-warning;
.u-button {
width: 100%;
white-space: nowrap;
&__text {
white-space: nowrap;
line-height: 1;
}
&:before {
position: absolute;
top:$u-button-before-top;
left:$u-button-before-left;
width:$u-button-before-width;
height:$u-button-before-height;
border: inherit;
border-radius: inherit;
transform:$u-button-before-transform;
opacity:$u-button-before-opacity;
content: " ";
background-color:$u-button-before-background-color;
border-color:$u-button-before-border-color;
}
&--active {
&:before {
opacity: .15
}
}
&__icon+&__text:not(:empty),
&__loading-text {
margin-left:$u-button-icon-margin-left;
}
&--plain {
&.u-button--primary {
color: $u-primary;
}
}
&--plain {
&.u-button--info {
color:$u-button-plain-u-button-info-color;
}
}
&--plain {
&.u-button--success {
color:$u-button-plain-u-button-success-color;
}
}
&--plain {
&.u-button--error {
color:$u-button-plain-u-button-error-color;
}
}
&--plain {
&.u-button--warning {
color:$u-button-plain-u-button-warning-color;
}
}
}
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:52:43
* @FilePath : /u-view2.0/uview-ui/libs/config/props/calendar.js
*/
import { t } from '../../libs/i18n'
export default {
// calendar 组件
calendar: {
title: t("up.calendar.chooseDates"),
showTitle: true,
showSubtitle: true,
mode: 'single',
startText: t("up.common.start"),
endText: t("up.common.end"),
customList: [],
color: '#3c9cff',
minDate: 0,
maxDate: 0,
defaultDate: null,
maxCount: Number.MAX_SAFE_INTEGER, // Infinity
rowHeight: 56,
formatter: null,
showLunar: false,
showMark: true,
confirmText: t("up.common.confirm"),
confirmDisabledText: t("up.common.confirm"),
show: false,
closeOnClickOverlay: false,
readonly: false,
showConfirm: true,
maxRange: Number.MAX_SAFE_INTEGER, // Infinity
rangePrompt: '',
showRangePrompt: true,
allowSameDay: false,
round: 0,
monthNum: 3,
weekText: [t("up.week.one"), t("up.week.two"), t("up.week.three"), t("up.week.four"), t("up.week.five"), t("up.week.six"), t("up.week.seven")],
forbidDays: [],
forbidDaysToast: t("up.calendar.disabled"),
monthFormat: '',
pageInline: false
}
}
<template>
<view class="u-calendar-header u-border-bottom">
<text
class="u-calendar-header__title"
v-if="showTitle"
>{{ title }}</text>
<text
class="u-calendar-header__subtitle"
v-if="showSubtitle"
>{{ subtitle }}</text>
<view class="u-calendar-header__weekdays">
<text class="u-calendar-header__weekdays__weekday">{{ weekText[0] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[1] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[2] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[3] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[4] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[5] }}</text>
<text class="u-calendar-header__weekdays__weekday">{{ weekText[6] }}</text>
</view>
</view>
</template>
<script>
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
export default {
name: 'u-calendar-header',
mixins: [mpMixin, mixin],
props: {
// 标题
title: {
type: String,
default: ''
},
// 副标题
subtitle: {
type: String,
default: ''
},
// 是否显示标题
showTitle: {
type: Boolean,
default: true
},
// 是否显示副标题
showSubtitle: {
type: Boolean,
default: true
},
// 星期文本
weekText: {
type: Array,
default: () => {
return []
}
},
},
data() {
return {
}
},
methods: {
name() {
}
},
}
</script>
<style lang="scss" scoped>
.u-calendar-header {
display: flex;
flex-direction: column;
padding-bottom: 4px;
&__title {
font-size: 16px;
color: $u-main-color;
text-align: center;
height: 42px;
line-height: 42px;
font-weight: bold;
}
&__subtitle {
font-size: 14px;
color: $u-main-color;
height: 40px;
text-align: center;
line-height: 40px;
font-weight: bold;
}
&__weekdays {
@include flex;
justify-content: space-between;
&__weekday {
font-size: 13px;
color: $u-main-color;
line-height: 30px;
flex: 1;
text-align: center;
}
}
}
</style>
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 日历顶部标题
title: {
type: String,
default: () => defProps.calendar.title
},
// 是否显示标题
showTitle: {
type: Boolean,
default: () => defProps.calendar.showTitle
},
// 是否显示副标题
showSubtitle: {
type: Boolean,
default: () => defProps.calendar.showSubtitle
},
// 日期类型选择,single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围
mode: {
type: String,
default: () => defProps.calendar.mode
},
// mode=range时,第一个日期底部的提示文字
startText: {
type: String,
default: () => defProps.calendar.startText
},
// mode=range时,最后一个日期底部的提示文字
endText: {
type: String,
default: () => defProps.calendar.endText
},
// 自定义列表
customList: {
type: Array,
default: () => defProps.calendar.customList
},
// 主题色,对底部按钮和选中日期有效
color: {
type: String,
default: () => defProps.calendar.color
},
// 最小的可选日期
minDate: {
type: [String, Number],
default: () => defProps.calendar.minDate
},
// 最大可选日期
maxDate: {
type: [String, Number],
default: () => defProps.calendar.maxDate
},
// 默认选中的日期,mode为multiple或range是必须为数组格式
defaultDate: {
type: [Array, String, Date, null],
default: () => defProps.calendar.defaultDate
},
// mode=multiple时,最多可选多少个日期
maxCount: {
type: [String, Number],
default: () => defProps.calendar.maxCount
},
// 日期行高
rowHeight: {
type: [String, Number],
default: () => defProps.calendar.rowHeight
},
// 日期格式化函数
formatter: {
type: [Function, null],
default: () => defProps.calendar.formatter
},
// 是否显示农历
showLunar: {
type: Boolean,
default: () => defProps.calendar.showLunar
},
// 是否显示月份背景色
showMark: {
type: Boolean,
default: () => defProps.calendar.showMark
},
// 确定按钮的文字
confirmText: {
type: String,
default: () => defProps.calendar.confirmText
},
// 确认按钮处于禁用状态时的文字
confirmDisabledText: {
type: String,
default: () => defProps.calendar.confirmDisabledText
},
// 是否显示日历弹窗
show: {
type: Boolean,
default: () => defProps.calendar.show
},
// 是否允许点击遮罩关闭日历
closeOnClickOverlay: {
type: Boolean,
default: () => defProps.calendar.closeOnClickOverlay
},
// 是否为只读状态,只读状态下禁止选择日期
readonly: {
type: Boolean,
default: () => defProps.calendar.readonly
},
// 是否展示确认按钮
showConfirm: {
type: Boolean,
default: () => defProps.calendar.showConfirm
},
// 日期区间最多可选天数,默认无限制,mode = range时有效
maxRange: {
type: [Number, String],
default: () => defProps.calendar.maxRange
},
// 范围选择超过最多可选天数时的提示文案,mode = range时有效
rangePrompt: {
type: String,
default: () => defProps.calendar.rangePrompt
},
// 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
showRangePrompt: {
type: Boolean,
default: () => defProps.calendar.showRangePrompt
},
// 是否允许日期范围的起止时间为同一天,mode = range时有效
allowSameDay: {
type: Boolean,
default: () => defProps.calendar.allowSameDay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: () => defProps.calendar.round
},
// 最多展示月份数量
monthNum: {
type: [Number, String],
default: 3
},
// 星期文案
weekText: {
type: Array,
default: defProps.calendar.weekText
},
forbidDays: {
type: Array,
default: defProps.calendar.forbidDays
},
forbidDaysToast:{
type: String,
default: defProps.calendar.forbidDaysToast
},
monthFormat:{
type: String,
default: defProps.calendar.monthFormat
},
// 是否页面内展示
pageInline:{
type: Boolean,
default: defProps.calendar.pageInline
}
}
})
import dayjs from '../u-datetime-picker/dayjs.esm.min.js';
export default {
methods: {
// 设置月份数据
setMonth() {
// 月初是周几
const day = dayjs(this.date).date(1).day()
const start = day == 0 ? 6 : day - 1
// 本月天数
const days = dayjs(this.date).endOf('month').format('D')
// 上个月天数
const prevDays = dayjs(this.date).endOf('month').subtract(1, 'month').format('D')
// 日期数据
const arr = []
// 清空表格
this.month = []
// 添加上月数据
arr.push(
...new Array(start).fill(1).map((e, i) => {
const day = prevDays - start + i + 1
return {
value: day,
disabled: true,
date: dayjs(this.date).subtract(1, 'month').date(day).format('YYYY-MM-DD')
}
})
)
// 添加本月数据
arr.push(
...new Array(days - 0).fill(1).map((e, i) => {
const day = i + 1
return {
value: day,
date: dayjs(this.date).date(day).format('YYYY-MM-DD')
}
})
)
// 添加下个月
arr.push(
...new Array(42 - days - start).fill(1).map((e, i) => {
const day = i + 1
return {
value: day,
disabled: true,
date: dayjs(this.date).add(1, 'month').date(day).format('YYYY-MM-DD')
}
})
)
// 分割数组
for (let n = 0; n < arr.length; n += 7) {
this.month.push(
arr.slice(n, n + 7).map((e, i) => {
e.index = i + n
// 自定义信息
const custom = this.customList.find((c) => c.date == e.date)
// 农历
if (this.lunar) {
const {
IDayCn,
IMonthCn
} = this.getLunar(e.date)
e.lunar = IDayCn == '初一' ? IMonthCn : IDayCn
}
return {
...e,
...custom
}
})
)
}
}
}
}
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:53:20
* @FilePath : /u-view2.0/uview-ui/libs/config/props/carKeyboard.js
*/
export default {
// 车牌号键盘
carKeyboard: {
random: false
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 是否打乱键盘按键的顺序
random: {
type: Boolean,
default: false
},
// 输入一个中文后,是否自动切换到英文
autoChange: {
type: Boolean,
default: false
}
}
})
<template>
<view
class="u-keyboard"
@touchmove.stop.prevent="noop"
>
<view
v-for="(group, i) in abc ? engKeyBoardList : areaList"
:key="i"
class="u-keyboard__button"
:index="i"
:class="[i + 1 === 4 && 'u-keyboard__button--center']"
>
<view
v-if="i === 3"
class="u-keyboard__button__inner-wrapper"
>
<view
class="u-keyboard__button__inner-wrapper__left"
hover-class="u-hover-class"
:hover-stay-time="200"
@tap="changeCarInputMode"
>
<text
class="u-keyboard__button__inner-wrapper__left__lang"
:class="[!abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
></text>
<text class="u-keyboard__button__inner-wrapper__left__line">/</text>
<text
class="u-keyboard__button__inner-wrapper__left__lang"
:class="[abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
></text>
</view>
</view>
<view
class="u-keyboard__button__inner-wrapper"
v-for="(item, j) in group"
:key="j"
>
<view
class="u-keyboard__button__inner-wrapper__inner"
:hover-stay-time="200"
@tap="carInputClick(i, j)"
hover-class="u-hover-class"
>
<text class="u-keyboard__button__inner-wrapper__inner__text">{{ item }}</text>
</view>
</view>
<view
v-if="i === 3"
@touchstart="backspaceClick"
@touchend="clearTimer"
class="u-keyboard__button__inner-wrapper"
>
<view
class="u-keyboard__button__inner-wrapper__right"
hover-class="u-hover-class"
:hover-stay-time="200"
>
<up-icon
size="28"
name="backspace"
color="#303133"
></up-icon>
</view>
</view>
</view>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { randomArray, sleep } from '../../libs/function/index';
/**
* keyboard 键盘组件
* @description 此为uview-plus自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。
* @tutorial https://uview-plus.jiangruyi.com/components/keyboard.html
* @property {Boolean} random 是否打乱键盘的顺序
* @event {Function} change 点击键盘触发
* @event {Function} backspace 点击退格键触发
* @example <u-keyboard ref="uKeyboard" mode="car" v-model="show"></u-keyboard>
*/
export default {
name: "u-car-keyboard",
mixins: [mpMixin, mixin, props],
data() {
return {
// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
abc: false
};
},
computed: {
areaList() {
let data = [
'京',
'沪',
'粤',
'津',
'冀',
'豫',
'云',
'辽',
'黑',
'湘',
'皖',
'鲁',
'苏',
'浙',
'赣',
'鄂',
'桂',
'甘',
'晋',
'陕',
'蒙',
'吉',
'闽',
'贵',
'渝',
'川',
'青',
'琼',
'宁',
'挂',
'藏',
'港',
'澳',
'新',
'使',
'学'
];
let tmp = [];
// 打乱顺序
if (this.random) data = randomArray(data);
// 切割成二维数组
tmp[0] = data.slice(0, 10);
tmp[1] = data.slice(10, 20);
tmp[2] = data.slice(20, 30);
tmp[3] = data.slice(30, 36);
return tmp;
},
engKeyBoardList() {
let data = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
0,
'Q',
'W',
'E',
'R',
'T',
'Y',
'U',
'I',
'O',
'P',
'A',
'S',
'D',
'F',
'G',
'H',
'J',
'K',
'L',
'Z',
'X',
'C',
'V',
'B',
'N',
'M'
];
let tmp = [];
if (this.random) data = randomArray(data);
tmp[0] = data.slice(0, 10);
tmp[1] = data.slice(10, 20);
tmp[2] = data.slice(20, 30);
tmp[3] = data.slice(30, 36);
return tmp;
}
},
emits: ["change", "backspace"],
methods: {
// 点击键盘按钮
carInputClick(i, j) {
let value = '';
// 不同模式,获取不同数组的值
if (this.abc) value = this.engKeyBoardList[i][j];
else value = this.areaList[i][j];
// 如果允许自动切换,则将中文状态切换为英文
if (!this.abc && this.autoChange) sleep(200).then(() => this.abc = true)
this.$emit('change', value);
},
// 修改汽车牌键盘的输入模式,中文|英文
changeCarInputMode() {
this.abc = !this.abc;
},
// 点击退格键
backspaceClick() {
this.$emit('backspace');
clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
this.timer = null;
this.timer = setInterval(() => {
this.$emit('backspace');
}, 250);
},
clearTimer() {
clearInterval(this.timer);
this.timer = null;
},
}
};
</script>
<style lang="scss" scoped>
$u-car-keyboard-background-color: rgb(224, 228, 230) !default;
$u-car-keyboard-padding:6px 0 6px !default;
$u-car-keyboard-button-inner-width:64rpx !default;
$u-car-keyboard-button-inner-background-color:#FFFFFF !default;
$u-car-keyboard-button-height:80rpx !default;
$u-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default;
$u-car-keyboard-button-border-radius:4px !default;
$u-car-keyboard-button-inner-margin:8rpx 5rpx !default;
$u-car-keyboard-button-text-font-size:16px !default;
$u-car-keyboard-button-text-color:$u-main-color !default;
$u-car-keyboard-center-inner-margin: 0 4rpx !default;
$u-car-keyboard-special-button-width:134rpx !default;
$u-car-keyboard-lang-font-size:16px !default;
$u-car-keyboard-lang-color:$u-main-color !default;
$u-car-keyboard-active-color:$u-primary !default;
$u-car-keyboard-line-font-size:15px !default;
$u-car-keyboard-line-color:$u-main-color !default;
$u-car-keyboard-line-margin:0 1px !default;
$u-car-keyboard-u-hover-class-background-color:#BBBCC6 !default;
.u-keyboard {
@include flex(column);
justify-content: space-around;
background-color: $u-car-keyboard-background-color;
align-items: stretch;
padding: $u-car-keyboard-padding;
&__button {
@include flex;
justify-content: center;
flex: 1;
/* #ifndef APP-NVUE */
/* #endif */
&__inner-wrapper {
box-shadow: $u-car-keyboard-button-inner-box-shadow;
margin: $u-car-keyboard-button-inner-margin;
border-radius: $u-car-keyboard-button-border-radius;
&__inner {
@include flex;
justify-content: center;
align-items: center;
width: $u-car-keyboard-button-inner-width;
background-color: $u-car-keyboard-button-inner-background-color;
height: $u-car-keyboard-button-height;
border-radius: $u-car-keyboard-button-border-radius;
&__text {
font-size: $u-car-keyboard-button-text-font-size;
color: $u-car-keyboard-button-text-color;
}
}
&__left,
&__right {
border-radius: $u-car-keyboard-button-border-radius;
width: $u-car-keyboard-special-button-width;
height: $u-car-keyboard-button-height;
background-color: $u-car-keyboard-u-hover-class-background-color;
@include flex;
justify-content: center;
align-items: center;
box-shadow: $u-car-keyboard-button-inner-box-shadow;
}
&__left {
&__line {
font-size: $u-car-keyboard-line-font-size;
color: $u-car-keyboard-line-color;
margin: $u-car-keyboard-line-margin;
}
&__lang {
font-size: $u-car-keyboard-lang-font-size;
color: $u-car-keyboard-lang-color;
&--active {
color: $u-car-keyboard-active-color;
}
}
}
}
}
}
.u-hover-class {
background-color: $u-car-keyboard-u-hover-class-background-color;
}
</style>
/*
* @Author : jry
* @Description :
* @version : 3.0
* @Date : 2025-04-26 16:37:21
* @LastAuthor : jry
* @lastTime : 2025-04-26 16:37:21
* @FilePath : /uview-plus/libs/config/props/card.js
*/
export default {
// card组件的props
card: {
full: false,
title: '',
titleColor: '#303133',
titleSize: '15px',
subTitle: '',
subTitleColor: '#909399',
subTitleSize: '13px',
border: true,
index: '',
margin: '15px',
borderRadius: '8px',
headStyle: {},
bodyStyle: {},
footStyle: {},
headBorderBottom: true,
footBorderTop: true,
thumb: '',
thumbWidth: '30px',
thumbCircle: false,
padding: '15px',
paddingHead: '',
paddingBody: '',
paddingFoot: '',
showHead: true,
showFoot: true,
boxShadow: 'none'
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const propsCard = defineMixin({
props: {
// 与屏幕两侧是否留空隙
full: {
type: Boolean,
default: () => defProps.card.full
},
// 标题
title: {
type: String,
default: () => defProps.card.title
},
// 标题颜色
titleColor: {
type: String,
default: () => defProps.card.titleColor
},
// 标题字体大小
titleSize: {
type: [Number, String],
default: () => defProps.card.titleSize
},
// 副标题
subTitle: {
type: String,
default: () => defProps.card.subTitle
},
// 副标题颜色
subTitleColor: {
type: String,
default: () => defProps.card.subTitleColor
},
// 副标题字体大小
subTitleSize: {
type: [Number, String],
default: () => defProps.card.subTitleSize
},
// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
border: {
type: Boolean,
default: () => defProps.card.border
},
// 用于标识点击了第几个
index: {
type: [Number, String, Object],
default: () => defProps.card.index
},
// 用于隔开上下左右的边距,带单位的写法,如:"30px 30px","20px 20px 30px 30px"
margin: {
type: String,
default: () => defProps.card.margin
},
// card卡片的圆角
borderRadius: {
type: [Number, String],
default: () => defProps.card.borderRadius
},
// 头部自定义样式,对象形式
headStyle: {
type: Object,
default: () => defProps.card.headStyle
},
// 主体自定义样式,对象形式
bodyStyle: {
type: Object,
default: () => defProps.card.bodyStyle
},
// 底部自定义样式,对象形式
footStyle: {
type: Object,
default: () => defProps.card.footStyle
},
// 头部是否下边框
headBorderBottom: {
type: Boolean,
default: () => defProps.card.headBorderBottom
},
// 底部是否有上边框
footBorderTop: {
type: Boolean,
default: () => defProps.card.footBorderTop
},
// 标题左边的缩略图
thumb: {
type: String,
default: () => defProps.card.thumb
},
// 缩略图宽高
thumbWidth: {
type: [String, Number],
default: () => defProps.card.thumbWidth
},
// 缩略图是否为圆形
thumbCircle: {
type: Boolean,
default: () => defProps.card.thumbCircle
},
// 给head,body,foot的内边距
padding: {
type: [String, Number],
default: () => defProps.card.padding
},
paddingHead: {
type: [String, Number],
default: () => defProps.card.paddingHead
},
paddingBody: {
type: [String, Number],
default: () => defProps.card.paddingBody
},
paddingFoot: {
type: [String, Number],
default: () => defProps.card.paddingFoot
},
// 是否显示头部
showHead: {
type: Boolean,
default: () => defProps.card.showHead
},
// 是否显示尾部
showFoot: {
type: Boolean,
default: () => defProps.card.showFoot
},
// 卡片外围阴影,字符串形式
boxShadow: {
type: String,
default: () => defProps.card.boxShadow
}
}
})
<template>
<view
class="u-card"
@tap.stop="click"
:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': getPx(borderRadius) > 0 }"
:style="{
borderRadius: addUnit(borderRadius),
margin: margin,
boxShadow: boxShadow
}"
>
<view
v-if="showHead"
class="u-card__head"
:style="[{padding: addUnit(paddingHead || padding)}, headStyle]"
:class="{
'u-border-bottom': headBorderBottom
}"
@tap="headClick"
>
<view v-if="!$slots.head" class="u-flex u-flex-between">
<view class="u-card__head--left u-flex u-line-1" v-if="title">
<image
:src="thumb"
class="u-card__head--left__thumb"
mode="aspectFill"
v-if="thumb"
:style="{
height: addUnit(thumbWidth),
width: addUnit(thumbWidth),
borderRadius: thumbCircle ? '50px' : '4px'
}"
></image>
<text
class="u-card__head--left__title u-line-1"
:style="{
fontSize: addUnit(titleSize),
color: titleColor
}"
>
{{ title }}
</text>
</view>
<view class="u-card__head--right u-line-1" v-if="subTitle">
<text
class="u-card__head__title__text"
:style="{
fontSize: addUnit(subTitleSize),
color: subTitleColor
}"
>
{{ subTitle }}
</text>
</view>
</view>
<slot name="head" v-else />
</view>
<view @tap="bodyClick" class="u-card__body"
:style="[{padding: addUnit(paddingBody || padding)}, bodyStyle]"><slot name="body" /></view>
<view
v-if="showFoot"
class="u-card__foot"
@tap="footClick"
:style="[{padding: $slots.foot ? addUnit(paddingFoot || padding) : 0}, footStyle]"
:class="{
'u-border-top': footBorderTop
}"
>
<slot name="foot" />
</view>
</view>
</template>
<script>
import { propsCard } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle, addUnit, getPx } from '../../libs/function/index';
/**
* card 卡片
* @description 卡片组件一般用于多个列表条目,且风格统一的场景
* @tutorial https://uview-plus.jiangruyi.com/components/card.html
* @property {Boolean} full 卡片与屏幕两侧是否留空隙(默认false)
* @property {String} title 头部左边的标题
* @property {String} title-color 标题颜色(默认#303133)
* @property {String | Number} title-size 标题字体大小,单位rpx(默认15px)
* @property {String} sub-title 头部右边的副标题
* @property {String} sub-title-color 副标题颜色(默认#909399)
* @property {String | Number} sub-title-size 副标题字体大小(默认13px
* @property {Boolean} border 是否显示边框(默认true)
* @property {String | Number} index 用于标识点击了第几个卡片
* @property {String} box-shadow 卡片外围阴影,字符串形式(默认none)
* @property {String} margin 卡片与屏幕两边和上下元素的间距,需带单位,如"30px 20px"(默认15px)
* @property {String | Number} border-radius 卡片整体的圆角值,单位rpx(默认8px)
* @property {Object} head-style 头部自定义样式,对象形式
* @property {Object} body-style 中部自定义样式,对象形式
* @property {Object} foot-style 底部自定义样式,对象形式
* @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
* @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
* @property {Boolean} show-head 是否显示头部(默认true)
* @property {Boolean} show-foot 是否显示尾部(默认true)
* @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
* @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位px(默认30px)
* @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
* @event {Function} click 整个卡片任意位置被点击时触发
* @event {Function} head-click 卡片头部被点击时触发
* @event {Function} body-click 卡片主体部分被点击时触发
* @event {Function} foot-click 卡片底部部分被点击时触发
* @example <u-card paddingFoot="2px 15px" title="card"></u-card>
*/
export default {
name: 'up-card',
data() {
return {};
},
mixins: [mpMixin, mixin, propsCard],
emits: ['click', 'head-click', 'body-click', 'foot-click'],
methods: {
addStyle,
addUnit,
getPx,
click() {
this.$emit('click', this.index);
},
headClick() {
this.$emit('head-click', this.index);
},
bodyClick() {
this.$emit('body-click', this.index);
},
footClick() {
this.$emit('foot-click', this.index);
}
}
};
</script>
<style lang="scss" scoped>
.u-card {
position: relative;
overflow: hidden;
font-size: 28rpx;
background-color: #ffffff;
box-sizing: border-box;
&-full {
// 如果是与屏幕之间不留空隙,应该设置左右边距为0
margin-left: 0 !important;
margin-right: 0 !important;
width: 100%;
}
&--border:after {
border-radius: 16rpx;
}
&__head {
&--left {
color: $u-main-color;
&__thumb {
margin-right: 16rpx;
}
&__title {
max-width: 400rpx;
}
}
&--right {
color: $u-tips-color;
margin-left: 6rpx;
}
}
&__body {
color: $u-content-color;
}
&__foot {
color: $u-tips-color;
}
}
</style>
<template>
<up-popup :show="popupShow" mode="bottom" :popup="false"
:mask="true" :closeable="true" :safe-area-inset-bottom="true"
close-icon-color="#ffffff" :z-index="uZIndex"
:maskCloseAble="maskCloseAble" @close="close">
<view class="up-p-t-30 up-p-l-20 up-m-b-10" v-if="headerDirection =='column'">
<up-steps v-if="popupShow" dot direction="column" v-model:current="tabsIndex">
<up-steps-item v-for="(item, index) in genTabsList"
@click="tabsIndex = index" :title="item.name"></up-steps-item>
</up-steps>
</view>
<view class="up-p-t-20 up-m-b-10" v-else>
<up-tabs v-if="popupShow" :list="genTabsList"
:scrollable="true" v-model:current="tabsIndex" @change="tabsChange" ref="tabs"></up-tabs>
</view>
<view class="area-box">
<view class="u-flex" :class="{ 'change':isChange }"
:style="{transform: optionsCols == 2 && isChange ? 'translateX(-33.3333333%)' : ''}">
<template v-for="(levelData, levelIndex) in levelList" :key="levelIndex">
<view v-if="optionsCols == 2 || levelIndex == tabsIndex" class="area-item"
:style="{ width: optionsCols == 2 ? '33.33333%' : '750rpx'}">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true" style="height: 100%">
<up-cell-group v-if="levelIndex === 0 || selectedValueIndexs[levelIndex - 1] !== undefined">
<up-cell v-for="(item,index) in levelData"
:title="item[labelKey]" :arrow="false"
:index="index" :key="index"
@click="levelChange(levelIndex, index)">
<template v-slot:right-icon>
<up-icon v-if="selectedValueIndexs[levelIndex] === index"
size="17" name="checkbox-mark"></up-icon>
</template>
</up-cell>
</up-cell-group>
</scroll-view>
</view>
</view>
</template>
</view>
</view>
<!-- 添加按钮区域 -->
<view class="u-cascader-action up-flex up-flex-between">
<view class="u-padding-20 up-flex-fill">
<up-button @click="handleCancel" type="default">{{ t("up.common.cancel") }}</up-button>
</view>
<view class="u-padding-20 up-flex-fill">
<up-button @click="handleConfirm" type="primary">{{ t("up.common.confirm") }}</up-button>
</view>
</view>
</up-popup>
</template>
<script>
/**
* u-cascader 通用无限级联选择器
* @property {String Number} z-index 弹出时的z-index值(默认1075)
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
* @property {Array} data 级联数据
* @property {Array} default-value 默认选中的值
* @property {String} valueKey 指定选项的值为选项对象中的哪个属性值
* @property {String} labelKey 指定选项标签为选项对象中的哪个属性值
* @property {String} childrenKey 指定选项的子选项为选项对象中的哪个属性值
* @property {Boolean} autoClose 是否在选择最后一级时自动关闭并触发confirm(默认false)
*/
import { t } from '../../libs/i18n'
export default {
name: 'up-cascader',
props: {
// 通过双向绑定控制组件的弹出与收起
show: {
type: Boolean,
default: false
},
// 级联数据
data: {
type: Array,
default() {
return [];
}
},
// 默认选中的值
modelValue: {
type: Array,
default() {
return [];
}
},
// 指定选项的值为选项对象中的哪个属性值
valueKey: {
type: String,
default: 'value'
},
// 指定选项标签为选项对象中的哪个属性值
labelKey: {
type: String,
default: 'label'
},
// 指定选项的子选项为选项对象中的哪个属性值
childrenKey: {
type: String,
default: 'children'
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 0
},
// 是否在选择最后一级时自动关闭并触发confirm
autoClose: {
type: Boolean,
default: false
},
// 选中项目的展示方向direction垂直方向适合文字长度过长
headerDirection: {
type: String,
default: 'row'
},
// 选项区域列数,支持1列和2列,默认为2列
optionsCols: {
type: [Number],
default: 2
}
},
data() {
return {
// 存储每一级的数据
levelList: [],
// 存储每一级选中的索引
selectedValueIndexs: [],
tabsIndex: 0,
popupShow: false,
// 新增confirmValues用于存储确认的值
confirmValues: []
}
},
watch: {
data: {
handler() {
this.initLevelList();
},
immediate: true
},
show() {
this.popupShow = this.show;
},
modelValue: {
handler() {
this.init();
},
immediate: true
}
},
computed: {
isChange() {
return this.tabsIndex > 1;
},
genTabsList() {
let tabsList = [{
name: "请选择"
}];
// 根据选中的值动态生成tabs
for (let i = 0; i < this.selectedValueIndexs.length; i++) {
if (this.selectedValueIndexs[i] !== undefined && this.levelList[i]) {
const selectedItem = this.levelList[i][this.selectedValueIndexs[i]];
if (selectedItem) {
tabsList[i] = {
name: selectedItem[this.labelKey]
};
// 如果还有下一级,则添加"请选择"
if (i === this.selectedValueIndexs.length - 1 &&
selectedItem[this.childrenKey] &&
selectedItem[this.childrenKey].length > 0) {
tabsList.push({
name: "请选择"
});
}
}
}
}
return tabsList;
},
uZIndex() {
// 如果用户有传递z-index值,优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
}
},
// 新增confirm事件
emits: ['update:modelValue', 'change', 'confirm'],
methods: {
t,
init() {
// 初始化选中值
if (this.modelValue && this.modelValue.length > 0) {
this.setDefaultValue();
}
},
initLevelList() {
// 初始化第一级数据
if (this.data && this.data.length > 0) {
this.levelList = [this.data];
this.selectedValueIndexs = [];
}
},
setDefaultValue() {
// 根据默认值设置选中项
// 根据modelValue获取indexs给selectedValueIndexs
this.selectedValueIndexs = [];
let currentLevelData = this.data;
for (let i = 0; i < this.modelValue.length; i++) {
const value = this.modelValue[i];
const index = currentLevelData.findIndex(item => item[this.valueKey] === value);
if (index !== -1) {
this.selectedValueIndexs.push(index);
// 更新下一级的数据
if (currentLevelData[index][this.childrenKey]) {
currentLevelData = currentLevelData[index][this.childrenKey];
} else {
// 如果没有子级数据,则停止处理
break;
}
} else {
// 如果找不到匹配项,则停止处理
break;
}
}
},
close() {
this.$emit('update:show', false);
},
tabsChange(item) {
},
levelChange(levelIndex, index) {
// 设置当前级的选中值
this.$set(this.selectedValueIndexs, levelIndex, index);
// 清除后续级别的选中值
for (let i = levelIndex + 1; i < this.selectedValueIndexs.length; i++) {
this.$set(this.selectedValueIndexs, i, undefined);
}
// 获取当前选中项
const currentItem = this.levelList[levelIndex][index];
// 如果有子级数据,则初始化下一级
if (currentItem && currentItem[this.childrenKey] && currentItem[this.childrenKey].length > 0) {
// 确保levelList数组足够长
if (this.levelList.length <= levelIndex + 1) {
this.levelList.push(currentItem[this.childrenKey]);
} else {
this.$set(this.levelList, levelIndex + 1, currentItem[this.childrenKey]);
}
// 切换到下一级tab
this.tabsIndex = levelIndex + 1;
} else {
// 没有子级数据,说明是最后一级
if (this.autoClose) {
// 如果启用自动关闭,则触发change事件并关闭
this.emitChange();
} else {
// 否则只触发change事件,不关闭
this.emitChange(false);
}
}
},
// 修改emitChange方法,增加closePopup参数
emitChange(closePopup = true) {
// 构造选中结果
const result = [];
for (let i = 0; i < this.selectedValueIndexs.length; i++) {
if (this.selectedValueIndexs[i] !== undefined && this.levelList[i]) {
result.push(this.levelList[i][this.selectedValueIndexs[i]][this.valueKey]);
}
}
// 更新confirmValues
this.confirmValues = [...result];
// 触发change事件,返回value数组
this.$emit('change', this.confirmValues);
// 根据参数决定是否关闭弹窗
if (closePopup) {
this.close();
}
},
handleCancel() {
this.close();
},
handleConfirm() {
// 确认时触发confirm事件
this.$emit('update:modelValue', this.confirmValues);
this.$emit('confirm', this.confirmValues);
this.close();
}
}
}
</script>
<style lang="scss">
.area-box {
width: 100%;
overflow: hidden;
height: 800rpx;
>view {
width: 150%;
transition: transform 0.3s ease-in-out 0s;
transform: translateX(0);
&.change {
// transform: translateX(-33.3333333%);
}
}
.area-item {
// width: 750rpx;
height: 800rpx;
}
}
// 添加按钮区域样式
.u-cascader-action {
border-top: 1px solid #eee;
}
</style>
\ No newline at end of file
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:54:16
* @FilePath : /u-view2.0/uview-ui/libs/config/props/cellGroup.js
*/
export default {
// cell-group组件的props
cellGroup: {
title: '',
border: true,
customStyle: {}
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 分组标题
title: {
type: String,
default: () => defProps.cellGroup.title
},
// 是否显示外边框
border: {
type: Boolean,
default: () => defProps.cellGroup.border
}
}
})
<template>
<view :style="[addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">
<view v-if="title" class="u-cell-group__title">
<slot name="title">
<text class="u-cell-group__title__text">{{ title }}</text>
</slot>
</view>
<view class="u-cell-group__wrapper">
<u-line v-if="border"></u-line>
<slot />
</view>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle } from '../../libs/function/index';
/**
* cellGroup 单元格
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
* @tutorial https://uview-plus.jiangruyi.com/components/cell.html
*
* @property {String} title 分组标题
* @property {Boolean} border 是否显示外边框 (默认 true )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击cell列表时触发
* @example <u-cell-group title="设置喜好">
*/
export default {
name: 'u-cell-group',
mixins: [mpMixin, mixin, props],
methods: {
addStyle
}
}
</script>
<style lang="scss" scoped>
$u-cell-group-title-padding: 16px 16px 8px !default;
$u-cell-group-title-font-size: 15px !default;
$u-cell-group-title-line-height: 16px !default;
$u-cell-group-title-color: $u-main-color !default;
.u-cell-group {
flex: 1;
&__title {
padding: $u-cell-group-title-padding;
&__text {
font-size: $u-cell-group-title-font-size;
line-height: $u-cell-group-title-line-height;
color: $u-cell-group-title-color;
}
}
&__wrapper {
position: relative;
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-23 20:53:09
* @FilePath : /u-view2.0/uview-ui/libs/config/props/cell.js
*/
export default {
// cell组件的props
cell: {
customClass: '',
title: '',
label: '',
value: '',
icon: '',
disabled: false,
border: true,
center: false,
url: '',
linkType: 'navigateTo',
clickable: false,
isLink: false,
required: false,
arrowDirection: '',
iconStyle: {},
rightIconStyle: {},
rightIcon: 'arrow-right',
titleStyle: {},
size: '',
stop: true,
name: ''
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 标题
title: {
type: [String, Number],
default: () => defProps.cell.title
},
// 标题下方的描述信息
label: {
type: [String, Number],
default: () => defProps.cell.label
},
// 右侧的内容
value: {
type: [String, Number],
default: () => defProps.cell.value
},
// 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
icon: {
type: String,
default: () => defProps.cell.icon
},
// 是否禁用cell
disabled: {
type: Boolean,
default: () => defProps.cell.disabled
},
// 是否显示下边框
border: {
type: Boolean,
default: () => defProps.cell.border
},
// 内容是否垂直居中(主要是针对右侧的value部分)
center: {
type: Boolean,
default: () => defProps.cell.center
},
// 点击后跳转的URL地址
url: {
type: String,
default: () => defProps.cell.url
},
// 链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作
linkType: {
type: String,
default: () => defProps.cell.linkType
},
// 是否开启点击反馈(表现为点击时加上灰色背景)
clickable: {
type: Boolean,
default: () => defProps.cell.clickable
},
// 是否展示右侧箭头并开启点击反馈
isLink: {
type: Boolean,
default: () => defProps.cell.isLink
},
// 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
required: {
type: Boolean,
default: () => defProps.cell.required
},
// 右侧的图标箭头
rightIcon: {
type: String,
default: () => defProps.cell.rightIcon
},
// 右侧箭头的方向,可选值为:left,up,down
arrowDirection: {
type: String,
default: () => defProps.cell.arrowDirection
},
// 左侧图标样式
iconStyle: {
type: [Object, String],
default: () => {
return defProps.cell.iconStyle
}
},
// 右侧箭头图标的样式
rightIconStyle: {
type: [Object, String],
default: () => {
return defProps.cell.rightIconStyle
}
},
// 标题的样式
titleStyle: {
type: [Object, String],
default: () => {
return defProps.cell.titleStyle
}
},
// 单位元的大小,可选值为large
size: {
type: String,
default: () => defProps.cell.size
},
// 点击cell是否阻止事件传播
stop: {
type: Boolean,
default: () => defProps.cell.stop
},
// 标识符,cell被点击时返回
name: {
type: [Number, String],
default: () => defProps.cell.name
}
}
})
<template>
<view class="u-cell" :class="[customClass]" :style="[addStyle(customStyle)]"
:hover-class="(!disabled && (clickable || isLink)) ? 'u-cell--clickable' : ''" :hover-stay-time="250"
@tap="clickHandler">
<view class="u-cell__body" :class="[ center && 'u-cell--center', size === 'large' && 'u-cell__body--large']">
<view class="u-cell__body__content">
<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon">
<slot name="icon" v-if="$slots.icon">
</slot>
<up-icon v-else :name="icon"
:custom-style="iconStyle"
:size="size === 'large' ? 22 : 18"></up-icon>
</view>
<view class="u-cell__title">
<!-- 将slot与默认内容用if/else分开主要是因为微信小程序不支持slot嵌套传递,这样才能解决collapse组件的slot不失效问题,label暂时未用到。 -->
<slot name="title" v-if="$slots.title || !title">
</slot>
<text v-else class="u-cell__title-text" :style="[titleTextStyle]"
:class="[required && 'u-cell--required', disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
<slot name="label">
<text class="u-cell__label" v-if="label"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text>
</slot>
</view>
</view>
<slot name="value">
<text class="u-cell__value"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']"
v-if="!testEmpty(value)">{{ value }}</text>
</slot>
<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink"
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
<up-icon v-if="rightIcon && !$slots['right-icon']" :name="rightIcon"
:custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
:size="size === 'large' ? 18 : 16"></up-icon>
<slot v-else name="right-icon">
</slot>
</view>
<view class="u-cell__right-icon-wrap" v-if="$slots['righticon']"
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
<slot name="righticon">
</slot>
</view>
</view>
<u-line v-if="border"></u-line>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
import { addStyle } from '../../libs/function/index';
import test from '../../libs/function/test';
/**
* cell 单元格
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
* @tutorial https://uview-plus.jiangruyi.com/components/cell.html
* @property {String | Number} title 标题
* @property {String | Number} label 标题下方的描述信息
* @property {String | Number} value 右侧的内容
* @property {String} icon 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
* @property {Boolean} disabled 是否禁用cell
* @property {Boolean} border 是否显示下边框 (默认 true )
* @property {Boolean} center 内容是否垂直居中(主要是针对右侧的value部分) (默认 false )
* @property {String} url 点击后跳转的URL地址
* @property {String} linkType 链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作 (默认 'navigateTo' )
* @property {Boolean} clickable 是否开启点击反馈(表现为点击时加上灰色背景) (默认 false )
* @property {Boolean} isLink 是否展示右侧箭头并开启点击反馈 (默认 false )
* @property {Boolean} required 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) (默认 false )
* @property {String} rightIcon 右侧的图标箭头 (默认 'arrow-right')
* @property {String} arrowDirection 右侧箭头的方向,可选值为:left,up,down
* @property {Object | String} rightIconStyle 右侧箭头图标的样式
* @property {Object | String} titleStyle 标题的样式
* @property {Object | String} iconStyle 左侧图标样式
* @property {String} size 单位元的大小,可选值为 large,normal,mini
* @property {Boolean} stop 点击cell是否阻止事件传播 (默认 true )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击cell列表时触发
* @example 该组件需要搭配cell-group组件使用,见官方文档示例
*/
export default {
name: 'u-cell',
data() {
return {
}
},
mixins: [mpMixin, mixin, props],
computed: {
titleTextStyle() {
return addStyle(this.titleStyle)
}
},
emits: ['click'],
methods: {
addStyle,
testEmpty: test.empty,
// 点击cell
clickHandler(e) {
if (this.disabled) return
this.$emit('click', {
name: this.name
})
// 如果配置了url(此props参数通过mixin引入)参数,跳转页面
this.openPage()
// 是否阻止事件传播
this.stop && this.preventEvent(e)
},
}
}
</script>
<style lang="scss" scoped>
$u-cell-padding: 13px 15px !default;
$u-cell-font-size: 15px !default;
$u-cell-line-height: 24px !default;
$u-cell-color: $u-main-color !default;
$u-cell-icon-size: 16px !default;
$u-cell-title-font-size: 15px !default;
$u-cell-title-line-height: 22px !default;
$u-cell-title-color: $u-main-color !default;
$u-cell-label-font-size: 12px !default;
$u-cell-label-color: $u-tips-color !default;
$u-cell-label-line-height: 18px !default;
$u-cell-value-font-size: 14px !default;
$u-cell-value-color: $u-content-color !default;
$u-cell-clickable-color: $u-bg-color !default;
$u-cell-disabled-color: #c8c9cc !default;
$u-cell-padding-top-large: 13px !default;
$u-cell-padding-bottom-large: 13px !default;
$u-cell-value-font-size-large: 15px !default;
$u-cell-label-font-size-large: 14px !default;
$u-cell-title-font-size-large: 16px !default;
$u-cell-left-icon-wrap-margin-right: 4px !default;
$u-cell-right-icon-wrap-margin-left: 4px !default;
$u-cell-title-flex:1 !default;
$u-cell-label-margin-top:5px !default;
.u-cell {
&__body {
@include flex();
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
padding: $u-cell-padding;
font-size: $u-cell-font-size;
color: $u-cell-color;
// line-height: $u-cell-line-height;
align-items: center;
&__content {
@include flex(row);
align-items: center;
flex: 1;
}
&--large {
padding-top: $u-cell-padding-top-large;
padding-bottom: $u-cell-padding-bottom-large;
}
}
&__left-icon-wrap,
&__right-icon-wrap {
@include flex();
align-items: center;
// height: $u-cell-line-height;
font-size: $u-cell-icon-size;
}
&__left-icon-wrap {
margin-right: $u-cell-left-icon-wrap-margin-right;
}
&__right-icon-wrap {
margin-left: $u-cell-right-icon-wrap-margin-left;
transition: transform 0.3s;
&--up {
transform: rotate(-90deg);
}
&--down {
transform: rotate(90deg);
}
}
&__title {
flex: $u-cell-title-flex;
display: flex;
flex-direction: column;
&-text {
font-size: $u-cell-title-font-size;
line-height: $u-cell-title-line-height;
color: $u-cell-title-color;
&--large {
font-size: $u-cell-title-font-size-large;
}
}
}
&__label {
margin-top: $u-cell-label-margin-top;
font-size: $u-cell-label-font-size;
color: $u-cell-label-color;
line-height: $u-cell-label-line-height;
&--large {
font-size: $u-cell-label-font-size-large;
}
}
&__value {
text-align: right;
/* #ifndef APP-NVUE */
margin-left: auto;
/* #endif */
font-size: $u-cell-value-font-size;
line-height: $u-cell-line-height;
color: $u-cell-value-color;
&--large {
font-size: $u-cell-value-font-size-large;
}
}
&--required {
/* #ifndef APP-NVUE */
overflow: visible;
/* #endif */
@include flex;
align-items: center;
}
&--required:before {
position: absolute;
/* #ifndef APP-NVUE */
content: '*';
/* #endif */
left: -8px;
margin-top: 4rpx;
font-size: 14px;
color: $u-error;
}
&--clickable {
background-color: $u-cell-clickable-color;
}
&--disabled {
color: $u-cell-disabled-color;
/* #ifndef APP-NVUE */
cursor: not-allowed;
/* #endif */
}
&--center {
align-items: center;
}
}
</style>
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-20 16:44:21
* @LastAuthor : LQ
* @lastTime : 2021-08-20 16:54:47
* @FilePath : /u-view2.0/uview-ui/libs/config/props/checkboxGroup.js
*/
export default {
// checkbox-group组件
checkboxGroup: {
name: '',
value: [],
shape: 'square',
disabled: false,
activeColor: '#2979ff',
inactiveColor: '#c8c9cc',
size: 18,
placement: 'row',
labelSize: 14,
labelColor: '#303133',
labelDisabled: false,
iconColor: '#ffffff',
iconSize: 12,
iconPlacement: 'left',
borderBottom: false
}
}
import { defineMixin } from '../../libs/vue'
import defProps from '../../libs/config/props.js'
export const props = defineMixin({
props: {
// 标识符
name: {
type: String,
default: () => defProps.checkboxGroup.name
},
// #ifdef VUE3
// 绑定的值
modelValue: {
type: Array,
default: () => defProps.checkboxGroup.value
},
// #endif
// #ifdef VUE2
// 绑定的值
value: {
type: Array,
default: () => defProps.checkboxGroup.value
},
// #endif
// 形状,circle-圆形,square-方形
shape: {
type: String,
default: () => defProps.checkboxGroup.shape
},
// 是否禁用全部checkbox
disabled: {
type: Boolean,
default: () => defProps.checkboxGroup.disabled
},
// 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
activeColor: {
type: String,
default: () => defProps.checkboxGroup.activeColor
},
// 未选中的颜色
inactiveColor: {
type: String,
default: () => defProps.checkboxGroup.inactiveColor
},
// 整个组件的尺寸,默认px
size: {
type: [String, Number],
default: () => defProps.checkboxGroup.size
},
// 布局方式,row-横向,column-纵向
placement: {
type: String,
default: () => defProps.checkboxGroup.placement
},
// label的字体大小,px单位
labelSize: {
type: [String, Number],
default: () => defProps.checkboxGroup.labelSize
},
// label的字体颜色
labelColor: {
type: [String],
default: () => defProps.checkboxGroup.labelColor
},
// 是否禁止点击文本操作
labelDisabled: {
type: Boolean,
default: () => defProps.checkboxGroup.labelDisabled
},
// 图标颜色
iconColor: {
type: String,
default: () => defProps.checkboxGroup.iconColor
},
// 图标的大小,单位px
iconSize: {
type: [String, Number],
default: () => defProps.checkboxGroup.iconSize
},
// 勾选图标的对齐方式,left-左边,right-右边
iconPlacement: {
type: String,
default: () => defProps.checkboxGroup.iconPlacement
},
// 竖向配列时,是否显示下划线
borderBottom: {
type: Boolean,
default: () => defProps.checkboxGroup.borderBottom
}
}
})
<template>
<view
class="u-checkbox-group"
:class="bemClass"
>
<slot></slot>
</view>
</template>
<script>
import { props } from './props';
import { mpMixin } from '../../libs/mixin/mpMixin';
import { mixin } from '../../libs/mixin/mixin';
/**
* checkboxGroup 复选框组
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
* @tutorial https://ijry.github.io/uview-plus/components/checkbox.html
* @property {String} name 标识符
* @property {Array} value 绑定的值
* @property {String} shape 形状,circle-圆形,square-方形 (默认 'square' )
* @property {Boolean} disabled 是否禁用全部checkbox (默认 false )
* @property {String} activeColor 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 (默认 '#2979ff' )
* @property {String} inactiveColor 未选中的颜色 (默认 '#c8c9cc' )
* @property {String | Number} size 整个组件的尺寸 单位px (默认 18 )
* @property {String} placement 布局方式,row-横向,column-纵向 (默认 'row' )
* @property {String | Number} labelSize label的字体大小,px单位 (默认 14 )
* @property {String} labelColor label的字体颜色 (默认 '#303133' )
* @property {Boolean} labelDisabled 是否禁止点击文本操作 (默认 false )
* @property {String} iconColor 图标颜色 (默认 '#ffffff' )
* @property {String | Number} iconSize 图标的大小,单位px (默认 12 )
* @property {String} iconPlacement 勾选图标的对齐方式,left-左边,right-右边 (默认 'left' )
* @property {Boolean} borderBottom placement为row时,是否显示下边框 (默认 false )
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
* @event {Function} input 修改通过v-model绑定的值时触发,回调为一个对象
* @example <u-checkbox-group></u-checkbox-group>
*/
export default {
name: 'u-checkbox-group',
mixins: [mpMixin, mixin,props],
computed: {
// 这里computed的变量,都是子组件u-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
// 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-checkbox-group)
// 拉取父组件新的变化后的参数
parentData() {
return [
// #ifdef VUE2
this.value,
// #endif
// #ifdef VUE3
this.modelValue,
// #endif
this.disabled,
this.inactiveColor,
this.activeColor,
this.size,
this.labelDisabled,
this.shape,
this.iconSize,
this.borderBottom,
this.placement,
];
},
bemClass() {
// this.bem为一个computed变量,在mixin中
return this.bem('checkbox-group', ['placement'])
},
},
watch: {
// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
parentData: {
handler() {
if (this.children.length) {
this.children.map((child) => {
// 判断子组件(u-checkbox)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
typeof child.init === "function" && child.init();
});
}
},
deep: true,
},
},
data() {
return {
}
},
created() {
this.children = []
},
// #ifdef VUE3
emits: ['update:modelValue', 'change'],
// #endif
methods: {
// 将其他的checkbox设置为未选中的状态
unCheckedOther(childInstance) {
const values = []
this.children.map(child => {
// 将被选中的checkbox,放到数组中返回
if (child.isChecked) {
values.push(child.name)
}
})
// 修改通过v-model绑定的值
// #ifdef VUE3
this.$emit("update:modelValue", values);
// #endif
// #ifdef VUE2
this.$emit("input", values);
// #endif
// 放在最后更新,否则change事件传出去的values不会更新
this.$emit('change', values)
},
}
}
</script>
<style lang="scss" scoped>
.u-checkbox-group {
&--row {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-flow: row wrap;
}
&--column {
@include flex(column);
}
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论