pull/1/head
脆皮鸭 2 years ago
commit c46b07d1da
  1. 11
      .env.development
  2. 11
      .env.production
  3. 23
      .gitignore
  4. 20
      index.html
  5. 9
      jsconfig.json
  6. 33
      package.json
  7. 19
      src/App.vue
  8. 10
      src/jtools/api/index.js
  9. 10
      src/jtools/api/login.js
  10. 11
      src/jtools/constants/common.js
  11. 5
      src/jtools/constants/index.js
  12. 75
      src/jtools/platform/index.js
  13. 47
      src/jtools/request/index.js
  14. 40
      src/jtools/storage/index.js
  15. 18
      src/jtools/store/index.js
  16. 68
      src/jtools/store/user.js
  17. 31
      src/jtools/utils/throttle.js
  18. 170
      src/jtools/wechat/sdk.js
  19. 19
      src/main.js
  20. 77
      src/manifest.json
  21. 62
      src/pages.json
  22. 175
      src/pages/index/components/Subject1.vue
  23. 46
      src/pages/index/components/Subject2.vue
  24. 52
      src/pages/index/index.vue
  25. 27
      src/pages/login/agreement.vue
  26. 255
      src/pages/login/forget.vue
  27. 140
      src/pages/login/login.vue
  28. 303
      src/pages/login/reg.vue
  29. 30
      src/pages/me/index.vue
  30. 13
      src/pages/public/404.vue
  31. 146
      src/pages/questionBank/components/Question.vue
  32. 22
      src/pages/questionBank/practiceExams.vue
  33. 28
      src/pages/questionBank/questionBank.vue
  34. BIN
      src/static/image/index/500icon.png
  35. BIN
      src/static/image/index/index_bg.png
  36. BIN
      src/static/image/index/realicon.png
  37. BIN
      src/static/image/index/testbeforeicon.png
  38. BIN
      src/static/image/index/vipAds.png
  39. BIN
      src/static/image/index/vipicon.png
  40. BIN
      src/static/image/index/worryicon.png
  41. BIN
      src/static/image/index/zxicon.png
  42. BIN
      src/static/image/tabbar/tab-home-selected.png
  43. BIN
      src/static/image/tabbar/tab-home.png
  44. BIN
      src/static/image/tabbar/tab-mine-selected.png
  45. BIN
      src/static/image/tabbar/tab-mine.png
  46. 3
      src/static/index.scss
  47. 429
      src/static/style/app.scss
  48. 678
      src/static/style/base.scss
  49. 3924
      src/static/style/colorui.css
  50. 121
      src/static/style/index.scss
  51. 76
      src/uni.scss
  52. 21
      src/uni_modules/uview-plus/LICENSE
  53. 64
      src/uni_modules/uview-plus/README.md
  54. 22
      src/uni_modules/uview-plus/changelog.md
  55. 80
      src/uni_modules/uview-plus/components/u--form/u--form.vue
  56. 50
      src/uni_modules/uview-plus/components/u--image/u--image.vue
  57. 74
      src/uni_modules/uview-plus/components/u--input/u--input.vue
  58. 45
      src/uni_modules/uview-plus/components/u--text/u--text.vue
  59. 47
      src/uni_modules/uview-plus/components/u--textarea/u--textarea.vue
  60. 55
      src/uni_modules/uview-plus/components/u-action-sheet/props.js
  61. 279
      src/uni_modules/uview-plus/components/u-action-sheet/u-action-sheet.vue
  62. 60
      src/uni_modules/uview-plus/components/u-album/props.js
  63. 261
      src/uni_modules/uview-plus/components/u-album/u-album.vue
  64. 45
      src/uni_modules/uview-plus/components/u-alert/props.js
  65. 245
      src/uni_modules/uview-plus/components/u-alert/u-alert.vue
  66. 53
      src/uni_modules/uview-plus/components/u-avatar-group/props.js
  67. 105
      src/uni_modules/uview-plus/components/u-avatar-group/u-avatar-group.vue
  68. 79
      src/uni_modules/uview-plus/components/u-avatar/props.js
  69. 174
      src/uni_modules/uview-plus/components/u-avatar/u-avatar.vue
  70. 55
      src/uni_modules/uview-plus/components/u-back-top/props.js
  71. 131
      src/uni_modules/uview-plus/components/u-back-top/u-back-top.vue
  72. 78
      src/uni_modules/uview-plus/components/u-badge/props.js
  73. 173
      src/uni_modules/uview-plus/components/u-badge/u-badge.vue
  74. 46
      src/uni_modules/uview-plus/components/u-button/nvue.scss
  75. 162
      src/uni_modules/uview-plus/components/u-button/props.js
  76. 494
      src/uni_modules/uview-plus/components/u-button/u-button.vue
  77. 80
      src/uni_modules/uview-plus/components/u-button/vue.scss
  78. 99
      src/uni_modules/uview-plus/components/u-calendar/header.vue
  79. 583
      src/uni_modules/uview-plus/components/u-calendar/month.vue
  80. 145
      src/uni_modules/uview-plus/components/u-calendar/props.js
  81. 386
      src/uni_modules/uview-plus/components/u-calendar/u-calendar.vue
  82. 86
      src/uni_modules/uview-plus/components/u-calendar/util.js
  83. 15
      src/uni_modules/uview-plus/components/u-car-keyboard/props.js
  84. 313
      src/uni_modules/uview-plus/components/u-car-keyboard/u-car-keyboard.vue
  85. 15
      src/uni_modules/uview-plus/components/u-cell-group/props.js
  86. 63
      src/uni_modules/uview-plus/components/u-cell-group/u-cell-group.vue
  87. 111
      src/uni_modules/uview-plus/components/u-cell/props.js
  88. 234
      src/uni_modules/uview-plus/components/u-cell/u-cell.vue
  89. 92
      src/uni_modules/uview-plus/components/u-checkbox-group/props.js
  90. 133
      src/uni_modules/uview-plus/components/u-checkbox-group/u-checkbox-group.vue
  91. 70
      src/uni_modules/uview-plus/components/u-checkbox/props.js
  92. 359
      src/uni_modules/uview-plus/components/u-checkbox/u-checkbox.vue
  93. 9
      src/uni_modules/uview-plus/components/u-circle-progress/props.js
  94. 200
      src/uni_modules/uview-plus/components/u-circle-progress/u-circle-progress.vue
  95. 80
      src/uni_modules/uview-plus/components/u-code-input/props.js
  96. 254
      src/uni_modules/uview-plus/components/u-code-input/u-code-input.vue
  97. 35
      src/uni_modules/uview-plus/components/u-code/props.js
  98. 131
      src/uni_modules/uview-plus/components/u-code/u-code.vue
  99. 30
      src/uni_modules/uview-plus/components/u-col/props.js
  100. 168
      src/uni_modules/uview-plus/components/u-col/u-col.vue
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,11 @@
# 页面标题
VITE_APP_TITLE = 金武联驾校
# 开发环境配置
VITE_APP_ENV = 'development'
# 金武联驾校/开发环境
VITE_APP_BASE_API = 'https://test.jd-mall.cn/dev/zongheng-api/'
#
VITE_WEB_BASE_URL = 'https://test.jd-mall.cn/dev/zongheng'

@ -0,0 +1,11 @@
# 页面标题
VITE_APP_TITLE = 金武联驾校
# 开发环境配置
VITE_APP_ENV = 'production'
# 金武联驾校/开发环境
VITE_APP_BASE_API = 'https://i.equ-tech.com/zongheng-api/'
#
VITE_WEB_BASE_URL = 'https://i.equ-tech.com/zongheng'

23
.gitignore vendored

@ -0,0 +1,23 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

@ -0,0 +1,9 @@
{
"compilerOptions": {
"types": [
"@dcloudio/types",
"miniprogram-api-typings",
"mini-types"
]
}
}

@ -0,0 +1,33 @@
{
"name": "OA",
"version": "0.0.0",
"scripts": {
"dev:h5": "uni",
"dev": "uni -p mp-weixin",
"build:h5": "uni build",
"build": "uni build -p mp-weixin",
"build-test:mp-weixin": "uni --mode test -p mp-weixin"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-components": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-h5": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3060420220922001",
"jsencrypt-plus": "^0.1.0",
"pinia": "^2.0.24",
"pinia-plugin-persist-uni": "^1.2.0",
"vue": "^3.2.37",
"vue-i18n": "^9.1.9"
},
"devDependencies": {
"@dcloudio/types": "^3.0.13",
"@dcloudio/uni-automator": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3060420220922001",
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3060420220922001",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3060420220922001",
"sass": "^1.63.6",
"sass-loader": "^13.3.2",
"vite": "^2.9.14"
}
}

@ -0,0 +1,19 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
}
</script>
<style lang="scss">
/*每个页面公共css */
@import "uni_modules/uview-plus/index.scss";
@import "static/style/index.scss";
</style>

@ -0,0 +1,10 @@
import request from '../request/index.js';
export function getAliCompanyInfo(data) {
return request({
url: 'alipay/findAliCompanyInfo',
method: 'POST',
data,
noToken: true
});
}

@ -0,0 +1,10 @@
import request from '../request/index.js';
export function login(data) {
return request({
url: 'api-admin/pcLogin',
method: 'POST',
data,
noToken: true
});
}

@ -0,0 +1,11 @@
// 请求状态码
const RESPONSE_TYPE = {
SUCCESS: '0000',
RELOGIN: 'E403',
ERROR: '4000'
};
export default {
RESPONSE_TYPE,
};

@ -0,0 +1,5 @@
import common from './common.js'
export default {
...common
}

@ -0,0 +1,75 @@
/**
* Platform v1.0.0
* @Class Platform
* @description jtools-platform 1.0.0 全平台兼容
* @Author lidongtony
* @Date 2021-04-07
* @Email lidongtony@qq.com
*/
// #ifdef H5
// 微信H5
import wxsdk from '@/jtools/wechat/sdk';
// #endif
export default {
// 获取当前运行平台
get() {
let platform = '';
// #ifdef H5
wxsdk.isWechat() ? (platform = 'wxOfficialAccount') : (platform = 'H5');
// #endif
// #ifdef APP-PLUS
platform = 'App';
// #endif
// #ifdef MP-WEIXIN
platform = 'wxMiniProgram';
// #endif
// #ifdef MP-ALIPAY
platform = 'alipayMiniProgram';
// #endif
if (platform !== '') {
uni.setStorageSync('platform', platform);
} else {
uni.showToast({
title: '暂不支持该平台',
icon: 'none'
});
}
return platform;
},
set(platform) {
uni.setStorageSync('platform', platform);
return platform;
},
// 检测当前运行机型
device() {
return uni.getSystemInfoSync().platform;
},
// 获取前端真实主机
host() {
let host = location.origin;
let basePath = router.$route.options.base;
let mode = router.$route.options.mode;
host += basePath;
if (mode === 'hash') {
host += '#/';
}
return host;
},
// 处理wechat jssdk 签名网址(针对IOS微信浏览器做优化)
entry() {
let that = this;
var entryUrl = location.href;
if (this.device() === 'ios') {
if (typeof location.entryUrl !== 'undefined') {
entryUrl = location.entryUrl;
} else {
location.entryUrl = entryUrl;
}
}
return entryUrl;
}
};

@ -0,0 +1,47 @@
import storage from '../storage/index.js';
//把配置项单独处理
let server_url = ' '; // 请求地址
let token = ' '; // 凭证
server_url = import.meta.env.VITE_APP_BASE_API; //环境配置
function service(options = {}) {
storage.get('token') && (token = storage.get('token'));
options.url = `${server_url}${options.url}`;
if (!options.noToken) {
if (!token.trim()) {
uni.redirectTo({
url: '/pages/login/login'
});
} else {
options.header = {
Authorization: `Bearer ${token}`
};
}
}
return new Promise((resolved, rejected) => {
//成功
options.success = res => {
if (res.data.code == 'E403') {
// 未登录
uni.showToast({
title: res.data.message,
icon: 'none'
});
uni.redirectTo({
url: '/pages/login/login'
});
//请求成功
resolved(res.data);
} else {
//请求成功
resolved(res.data);
}
};
//错误
options.fail = err => {
rejected(err); //错误
};
uni.request(options);
});
}
export default service;

@ -0,0 +1,40 @@
const APP_NAME = import.meta.env.VITE_APP_TITLE
export default {
set(key, value) {
// 命名规则 小程序名称-环境
const storageName = `${APP_NAME}-${process.env.NODE_ENV}`
const temp = uni.getStorageSync(storageName) || {}
temp[key] = value
uni.setStorageSync(storageName, temp)
},
get(key) {
// 命名规则 小程序名称-环境
const storageName = `${APP_NAME}-${process.env.NODE_ENV}`
const temp = uni.getStorageSync(storageName) || {}
if(temp.hasOwnProperty(key)) {
return temp[key]
} else {
return undefined
}
},
remove(key) {
// 命名规则 小程序名称-环境
const storageName = `${APP_NAME}-${process.env.NODE_ENV}`
const temp = uni.getStorageSync(storageName) || {}
if(temp.hasOwnProperty(key)) {
delete temp[key];
uni.setStorageSync(storageName, temp);
}
},
has(key) {
// 命名规则 小程序名称-环境
const storageName = `${APP_NAME}-${process.env.NODE_ENV}`
const temp = uni.getStorageSync(storageName) || {}
return temp.hasOwnProperty(key)
},
clear() {
// 命名规则 小程序名称-环境
const storageName = `${APP_NAME}-${process.env.NODE_ENV}`
uni.removeStorageSync(storageName)
}
}

@ -0,0 +1,18 @@
import { createPinia } from 'pinia';
// 自动注入所有pinia模块
const files = import.meta.globEager('./*.js');
const modules = {};
Object.keys(files).forEach((key) => {
modules[key.replace(/(.*\/)*([^.]+).*/gi, '$2')] = files[key].default;
});
export const setupPinia = (app) => {
const pinia = createPinia();
app.use(pinia);
};
export default (name) => {
return modules[name]();
};

@ -0,0 +1,68 @@
import { defineStore } from 'pinia';
import http from '@/jtools/request/index';
import constants from '@/jtools/constants';
import storage from '@/jtools/storage';
const user = defineStore({
id: 'user',
state: () => ({
token: storage.get('token'),
isLogin: storage.get('isLogin'), // 是否登陆
userInfo: storage.get('userInfo'), // 用户信息
}),
actions: {
// 登录
showAuth() {
// router.replaceAll('/pages/login/login');
},
// 获取个人信息
async getInfo() {
const { error, data } = await userApi.profile();
if (error !== 0) return;
this.userInfo = data;
return Promise.resolve(data);
},
// 设置token
setToken(token = '') {
if (token === '') {
this.isLogin = false;
this.token = ''
this.userInfo = {}
storage.set('token', '');
storage.set('isLogin', false);
storage.set('userInfo', {});
} else {
this.isLogin = true;
this.token = token
storage.set('token', token);
storage.set('isLogin', true);
}
return this.isLogin;
},
// 重置用户默认数据
resetUserData() {
this.setToken();
},
// 登出
async logout(force = false) {
if (!force) {
const { error } = await userApi.logout();
if (error === 0) {
this.resetUserData();
}
}
if (force) {
this.resetUserData();
}
return !this.isLogin;
},
},
});
export default user;

@ -0,0 +1,31 @@
let timer;
let flag;
/**
* 节流原理在一定时间内只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true;
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func();
timer = setTimeout(() => {
flag = false;
}, wait);
} else {
}
} else if (!flag) {
flag = true;
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false;
typeof func === 'function' && func();
}, wait);
}
}
export default throttle;

@ -0,0 +1,170 @@
var jweixin = require("jweixin-module");
import http from "@/jtools/request/index";
import $platform from "@/jtools/platform";
export default {
//判断是否在微信中
isWechat() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/micromessenger/i) == "micromessenger") {
return true;
} else {
return false;
}
},
// 鉴权页面
initJssdk(callback) {
http("common.wxJssdk", {
uri: encodeURIComponent($platform.entry())
}).then(res => {
jweixin.config({
debug: res.data.debug,
appId: res.data.appId,
timestamp: res.data.timestamp,
nonceStr: res.data.nonceStr,
signature: res.data.signature,
jsApiList: res.data.jsApiList,
openTagList: res.data.openTagList
});
if (callback) {
callback(res.data);
}
});
},
//在需要定位页面调用
getLocation(callback) {
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.getLocation({
type: "gcj02", // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
success: function(res) {
callback(res);
},
fail: function(res) {
console.log("%c微信H5sdk,getLocation失败:",
"color:green;background:yellow");
},
});
});
});
},
//获取微信收货地址
openAddress(callback) {
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.openAddress({
success: function(res) {
callback(res);
},
fail: function(err) {
console.log("%c微信H5sdk,openAddress失败:",
"color:green;background:yellow");
},
complete: function(msg) {}
});
});
});
},
// 微信扫码
scanQRCode(callback) {
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function(res) {
callback(res);
},
fail: function(res) {
console.log("%c微信H5sdk,scanQRCode失败:",
"color:green;background:yellow");
},
});
});
});
},
// 微信分享
share(data, callback) {
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
var shareData = {
title: data.title,
desc: data.desc,
link: data.path,
imgUrl: data.image,
success: function(res) {
callback(res);
// 分享后的一些操作,比如分享统计等等
},
cancel: function(res) {}
};
jweixin.updateAppMessageShareData(shareData); //新版接口
//分享到朋友圈接口
// jweixin.updateTimelineShareData(shareData);
});
});
},
// 打开坐标位置
openLocation(data, callback) { //打开位置
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.openLocation({ //根据传入的坐标打开地图
latitude: data.latitude,
longitude: data.longitude
});
});
});
},
// 选择图片
chooseImage(callback) { //选择图片
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.chooseImage({
count: 1,
sizeType: ["compressed"],
sourceType: ["album"],
success: function(rs) {
callback(rs);
}
});
});
});
},
//微信支付
wxpay(data, callback) {
let that = this;
this.isWechat() && this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.chooseWXPay({
timestamp: data
.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data.paySign, // 支付签名
success: function(res) {
callback(res);
},
fail: function(res) {
console.log("%c微信H5sdk,chooseWXPay失败:",
"color:green;background:yellow");
callback(res);
},
cancel: function(res) {
},
});
});
});
}
};

@ -0,0 +1,19 @@
import {
createSSRApp
} from "vue";
import uviewPlus from './uni_modules/uview-plus'
import platform from '@/jtools/platform';
import constants from '@/jtools/constants';
import storage from '@/jtools/storage';
import App from "./App.vue";
export function createApp() {
const app = createSSRApp(App);
app.config.globalProperties.$platform=platform
app.config.globalProperties.$constants=constants
app.config.globalProperties.$storage=storage
app.use(uviewPlus)
return {
app,
};
}

@ -0,0 +1,77 @@
{
"name" : "金武联驾校",
"appid" : "__UNI__401C711",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx756a7425037609fb",
"setting" : {
"urlCheck" : false,
"minified" : true,
"es6" : false
},
"usingComponents" : true,
"permission" : {}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"fallbackLocale" : "zh-Hans",
"locale" : "zh-Hans"
}

@ -0,0 +1,62 @@
{
"easycom": {
"^u-(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^j-(.*)": "@/components/j-$1/j-$1.vue"
},
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "金武联驾考"
}
},
{
"path": "pages/me/index",
"style": {
"navigationBarTitleText": "我的"
}
}
,{
"path" : "pages/questionBank/questionBank",
"style" :
{
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/questionBank/practiceExams",
"style": {
"navigationBarTitleText": "模拟考试"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "通用模板",
"navigationBarBackgroundColor": "#FFF",
"backgroundColor": "#FFF"
},
"tabBar": {
"borderStyle": "white",
"selectedColor": "#333333",
"backgroundColor": "#FFFFFF",
"color": "#999999",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/image/tabbar/tab-home.png",
"selectedIconPath":"static/image/tabbar/tab-home-selected.png",
"text": "首页"
},
{
"pagePath": "pages/me/index",
"iconPath": "static/image/tabbar/tab-mine.png",
"selectedIconPath": "static/image/tabbar/tab-mine-selected.png",
"text": "我的"
}
]
}
}

@ -0,0 +1,175 @@
<template>
<view>
<view class="box-nav">
<image style="width: 100%;" src="../../static/image/index/index_bg.png"></image>
<view class="center-box flex jc-sb ai-c">
<view class="box-item flex ai-c jc-c">
<view class="btn-item flex ai-c jc-c">
<view class="text-center cor-fff" style="line-height: 40rpx;" @tap="toAnswer">
<view class="fs16">顺序练习</view>
<text class="fs14">0/2344</text>
</view>
</view>
</view>
<view class="box-item flex ai-c jc-c">
<view class="btn2-item flex ai-c jc-c">
<view class="text-center cor-fff" style="line-height: 40rpx;">
<view class="fs16">模拟考试</view>
<text class="fs14">去考试</text>
</view>
</view>
</view>
</view>
</view>
<view style="padding: 0 28rpx;margin-top: 110rpx;">
<view class="tabs-box">
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto"
src="../../static/image/index/vipicon.png">
</image>
<view class="mt5">VIP课程</view>
</view>
</view>
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto"
src="../../static/image/index/500icon.png">
</image>
<view class="mt5">精简500题</view>
</view>
</view>
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto"
src="../../static/image/index/zxicon.png">
</image>
<view class="mt5">专项练习</view>
</view>
</view>
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto;"
src="../../static/image/index/realicon.png"></image>
<view class="mt5">真实考场模拟</view>
</view>
</view>
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto"
src="../../static/image/index/testbeforeicon.png"></image>
<view class="mt5">考前密卷</view>
</view>
</view>
<view class="wp33 flex ai-c jc-c">
<view class="text-center wp100">
<image style="width: 72rpx;height: 72rpx;margin: 0 auto"
src="../../static/image/index/worryicon.png"></image>
<view class="mt5">错题收藏</view>
</view>
</view>
</view>
</view>
<view style="padding: 0 28rpx;margin-top: 30rpx;">
<view class="video-box">
<view class="flex jc-sb ai-c wp100">
<text style="color: #05C341;font-size: 36rpx;">科一精品视频课</text>
<text class="cor-666 fs12">全部10节课 ></text>
</view>
<view class="flex ai-c mt20">
<image class="contain-box" src="../../static/image/index/index_bg.png"></image>
<view class="ml15 text-center">
<u-button :customStyle="{width:'200rpx',height:'66rpx',borderRadius: '33rpx'}" iconColor="#fff"
text="去看视频" color="linear-gradient(90deg, #11DF20 0%, #00B74F 100%)" icon="play-circle">
</u-button>
<view class="cor-333 fs15 fw600 mt10">科一易错试题</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {}
},
methods: {
toAnswer() {
uni.navigateTo({
url:"/pages/questionBank/questionBank"
})
}
}
}
</script>
<style scoped>
.box-nav {
width: 100%;
position: relative;
}
.center-box {
position: absolute;
width: 100%;
top: 170rpx;
padding: 0 28rpx;
}
.box-item {
width: 336rpx;
height: 336rpx;
background: #FFFFFF;
border-radius: 16rpx;
z-index: 999;
}
.btn-item {
width: 193rpx;
height: 193rpx;
background: linear-gradient(0deg, #11DF20 0%, #00B74F 100%);
border-radius: 50%;
}
.btn2-item {
width: 193rpx;
height: 193rpx;
background: linear-gradient(0deg, #E95A0E 0%, #FF9600 100%);
border-radius: 50%;
}
::v-deep .u-tabs__wrapper__nav__line {
background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%) !important;
bottom: 14rpx !important;
}
.tabs-box {
width: 694rpx;
height: 366rpx;
background: #FFFFFF;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
}
.video-box {
padding: 20rpx;
width: 694rpx;
height: 369rpx;
background: #DEEFE5;
border: 2px solid #47DB87;
border-radius: 16rpx;
}
.contain-box {
width: 406rpx;
height: 228rpx;
background: #00B74F;
border-radius: 16rpx;
}
</style>

@ -0,0 +1,46 @@
<template>
<view>
<view class="box-nav">
<image style="width: 100%;" src="../../static/image/index/index_bg.png"></image>
<view class="center-box flex jc-sb ai-c">
<view class="box-item flex ai-c jc-c">
<view class="btn-item flex ai-c jc-c">
<view class="text-center cor-fff" style="line-height: 40rpx;">
<view class="fs16">顺序练习</view>
<text class="fs14">0/2344</text>
</view>
</view>
</view>
<view class="box-item flex ai-c jc-c">
<view class="btn2-item flex ai-c jc-c">
<view class="text-center cor-fff" style="line-height: 40rpx;">
<view class="fs16">模拟考试</view>
<text class="fs14">去考试</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "Subject2"
}
</script>
<style scoped>
.box-nav{
width: 100%;
position: relative;
}
.center-box{
position: absolute;
width: 100%;
top: 170rpx;
padding: 0 28rpx;
}
</style>

@ -0,0 +1,52 @@
<template>
<view>
<u-sticky bgColor="#fff">
<u-tabs :list="categoryList" :scrollable="false"></u-tabs>
</u-sticky>
<view style="height: 100vh;background-color: rgb(245, 245, 245);">
<Subject1 />
</view>
</view>
</template>
<script>
import storage from '@/jtools/storage';
import Subject1 from "./components/Subject1";
export default {
components: {Subject1},
data() {
return {
searchValue:'',
cityName:'',
categoryList:[{
name:'科目1'
},{
name:'科目2'
},{
name:'科目3'
},{
name:'科目4'
}]
};
},
onLoad() {
},
methods:{
//
changeCategory(){
},
//
getAllQuestion(){
},
}
}
</script>
<style lang="scss" scoped>
::v-deep .u-tabs__wrapper__nav__line {
background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%) !important;
bottom: 14rpx !important;
}
</style>

@ -0,0 +1,27 @@
<template>
<view>
<web-view :webview-styles="webviewStyles" :src="articleurl"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
articleurl: '',
webviewStyles: {
progress: {
color: '#FF7200'
}
}
};
},
onLoad(options) {
this.articleurl = 'http://www.baidu.com/';
}
}
</script>
<style>
</style>

@ -0,0 +1,255 @@
<template>
<view class="content">
<view class="list">
<view class="tishi">若您忘记了密码可在此重新设置新密码</view>
<view class="list-call">
<u-icon name="phone" color="#EE2626" size="40"></u-icon>
<input class="sl-input" type="number" v-model="phone" maxlength="11" placeholder="请输入手机号" />
</view>
<view class="list-call">
<u-icon name="lock" color="#EE2626" size="40"></u-icon>
<input class="sl-input" type="text" v-model="password" maxlength="32" placeholder="请输入新密码"
:password="!showPassword" />
<u-icon @click="display" :name="showPassword?'eye-off':'eye-fill'" color="#EE2626" size="40"></u-icon>
</view>
<view class="list-call">
<u-icon name="checkmark-circle" color="#EE2626" size="40"></u-icon>
<input class="sl-input" type="number" v-model="code" maxlength="4" placeholder="验证码" />
<view class="yzm" :class="{ yzms: second>0 }" @tap="getcode">{{yanzhengma}}</view>
</view>
</view>
<view class="button-login" hover-class="button-hover" @tap="bindLogin()">
<text>修改密码</text>
</view>
</view>
</template>
<script>
var _this, js;
export default {
data() {
return {
phone: '',
second: 0,
code: "",
showPassword: false,
password: ''
}
},
onLoad() {
_this = this;
},
computed: {
yanzhengma() {
if (this.second == 0) {
return '获取验证码';
} else {
if (this.second < 10) {
return '重新获取0' + this.second;
} else {
return '重新获取' + this.second;
}
}
}
},
onUnload() {
this.clear()
},
methods: {
display() {
this.showPassword = !this.showPassword
},
clear() {
clearInterval(js)
js = null
this.second = 0
},
getcode() {
if (this.phone.length != 11) {
uni.showToast({
icon: 'none',
title: '手机号不正确'
});
return;
}
if (this.second > 0) {
return;
}
_this.second = 60;
js = setInterval(function() {
_this.second--;
if (_this.second == 0) {
_this.clear()
}
}, 1000)
uni.request({
url: 'http://***/getPassWord', //
data: {
phone: this.phone,
type: 'forget'
},
method: 'POST',
dataType: 'json',
success: (res) => {
if (res.data.code != 200) {
uni.showToast({
title: res.data.msg,
icon: 'none'
});
_this.second = 0;
} else {
uni.showToast({
title: res.data.msg
});
_this.second = 60;
js = setInterval(function() {
_this.second--;
if (_this.second == 0) {
_this.clear()
}
}, 1000)
}
},
fail() {
this.clear()
}
});
},
bindLogin() {
if (this.phone.length != 11) {
uni.showToast({
icon: 'none',
title: '手机号不正确'
});
return;
}
if (this.password.length < 6) {
uni.showToast({
icon: 'none',
title: '密码不正确'
});
return;
}
if (this.code.length != 4) {
uni.showToast({
icon: 'none',
title: '验证码不正确'
});
return;
}
uni.request({
url: 'http://***/forget',
data: {
phone: this.phone,
password: this.password,
code: this.code
},
method: 'POST',
dataType: 'json',
success: (res) => {
if (res.data.code != 200) {
uni.showToast({
title: res.data.msg,
icon: 'none'
});
} else {
uni.showToast({
title: res.data.msg
});
setTimeout(function() {
uni.navigateBack();
}, 1500)
}
}
});
}
}
}
</script>
<style>
page {
background-color: #fff;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
}
.tishi {
color: #999999;
font-size: 28rpx;
line-height: 50rpx;
margin-bottom: 50rpx;
}
.list {
display: flex;
flex-direction: column;
padding-top: 50rpx;
padding-left: 70rpx;
padding-right: 70rpx;
}
.list-call {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
color: #333333;
border-bottom: 0.5px solid #e2e2e2;
}
.list-call .sl-input {
flex: 1;
text-align: left;
font-size: 32rpx;
margin-left: 16rpx;
}
.button-login {
color: #FFFFFF;
font-size: 34rpx;
width: 470rpx;
height: 100rpx;
background: linear-gradient(-90deg, rgba(193, 25, 32, 1), rgba(238, 38, 38, 1));
border-radius: 50rpx;
line-height: 100rpx;
text-align: center;
margin-left: auto;
margin-right: auto;
margin-top: 100rpx;
}
.button-hover {
background: linear-gradient(-90deg, rgba(193, 25, 32, 0.8), rgba(238, 38, 38, 0.8));
}
.yzm {
color: #FF7D13;
font-size: 24rpx;
line-height: 64rpx;
padding-left: 10rpx;
padding-right: 10rpx;
width: auto;
height: 64rpx;
border: 1rpx solid rgba(255, 131, 30, 1);
border-radius: 50rpx;
}
.yzms {
color: #999999 !important;
border: 1rpx solid #999999;
}
</style>

@ -0,0 +1,140 @@
<template>
<view class="content">
<view class="header">
<image src="/static/images/login/logo.jpg"></image>
</view>
<view class="list">
<view class="list-call">
<u-icon name="phone" color="#EE2626" size="40"></u-icon>
<input class="sl-input" v-model="login.phone" type="number" maxlength="11" placeholder="输入手机号" />
</view>
<view class="list-call">
<u-icon name="lock" color="#EE2626" size="40"></u-icon>
<input class="sl-input" v-model="login.password" type="text" maxlength="32" placeholder="输入密码"
password="true" />
</view>
</view>
<view class="button-login" hover-class="button-hover" @tap="bindLogin()">
<text>登录</text>
</view>
<view class="agreenment">
<navigator url="/pages/login/forget" open-type="navigate">忘记密码</navigator>
<text>|</text>
<navigator url="/pages/login/reg" open-type="navigate">注册账户</navigator>
</view>
</view>
</template>
<script>
export default {
data() {
return {
login: {
phone: '',
password: ''
}
};
},
methods: {
bindLogin() {
}
}
}
</script>
<style>
page {
background-color: #fff;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
}
.header {
width: 161rpx;
height: 161rpx;
border-radius: 50%;
margin-top: 30rpx;
margin-left: auto;
margin-right: auto;
}
.header image {
width: 161rpx;
height: 161rpx;
border-radius: 50%;
}
.list {
display: flex;
flex-direction: column;
padding-top: 50rpx;
padding-left: 70rpx;
padding-right: 70rpx;
}
.list-call {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
color: #333333;
border-bottom: 0.5px solid #e2e2e2;
}
.list-call .sl-input {
flex: 1;
text-align: left;
font-size: 32rpx;
margin-left: 16rpx;
}
.button-login {
color: #FFFFFF;
font-size: 34rpx;
width: 470rpx;
height: 100rpx;
background: linear-gradient(-90deg, rgba(193, 25, 32, 1), rgba(238, 38, 38, 1));
border-radius: 50rpx;
line-height: 100rpx;
text-align: center;
margin-left: auto;
margin-right: auto;
margin-top: 100rpx;
}
.button-hover {
background: linear-gradient(-90deg, rgba(193, 25, 32, 0.8), rgba(238, 38, 38, 0.8));
}
.agreenment {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 30rpx;
margin-top: 80rpx;
color: #FFA800;
text-align: center;
height: 40rpx;
line-height: 40rpx;
}
.agreenment text {
font-size: 24rpx;
margin-left: 15rpx;
margin-right: 15rpx;
}
</style>

@ -0,0 +1,303 @@
<template>
<view class="content">
<view class="header">
<image src="/static/images/login/logo.jpg"></image>
</view>
<view class="list">
<view class="list-call">
<u-icon name="phone" color="#EE2626" size="40"></u-icon>
<input class="sl-input" v-model="phone" type="number" maxlength="11" placeholder="手机号" />
</view>
<view class="list-call">
<u-icon name="lock" color="#EE2626" size="40"></u-icon>
<input class="sl-input" v-model="password" type="text" maxlength="32" placeholder="登录密码"
:password="!showPassword" />
<u-icon @click="display" :name="showPassword?'eye-off':'eye-fill'" color="#EE2626" size="40"></u-icon>
</view>
<view class="list-call">
<u-icon name="checkmark-circle" color="#EE2626" size="40"></u-icon>
<input class="sl-input" v-model="code" type="number" maxlength="4" placeholder="验证码" />
<view class="yzm" :class="{ yzms: second>0 }" @tap="getcode">{{yanzhengma}}</view>
</view>
</view>
<view class="button-login" hover-class="button-hover" @tap="bindLogin">
<text>注册</text>
</view>
<view class="agreement">
<image @tap="agreementSuccess"
:src="agreement==true?'/static/images/login/ty1.png':'/static/images/login/ty0.png'"></image>
<text @tap="agreementSuccess"> 同意</text>
<navigator url="/pages/login/agreement?id=1" open-type="navigate">软件用户协议</navigator>
</view>
</view>
</template>
<script>
var _this, js;
export default {
onLoad() {
_this = this;
},
onUnload() {
clearInterval(js)
this.second = 0;
},
data() {
return {
phone: '',
password: '',
code: '',
agreement: true,
showPassword: false,
second: 0
};
},
computed: {
yanzhengma() {
if (this.second == 0) {
return '获取验证码';
} else {
if (this.second < 10) {
return '重新获取0' + this.second;
} else {
return '重新获取' + this.second;
}
}
}
},
onUnload() {
this.clear()
},
methods: {
clear() {
clearInterval(js)
js = null
this.second = 0
},
display() {
this.showPassword = !this.showPassword
},
agreementSuccess() {
this.agreement = !this.agreement;
},
getcode() {
if (this.phone.length != 11) {
uni.showToast({
icon: 'none',
title: '手机号不正确'
});
return;
}
if (this.second > 0) {
return;
}
this.second = 60;
//
js = setInterval(function() {
_this.second--;
if (_this.second == 0) {
_this.clear()
}
}, 1000)
// uni.request({
// url: 'http://***/getcode.html', //
// data: {
// phone: this.phone,
// type: 'reg'
// },
// method: 'POST',
// dataType: 'json',
// success: (res) => {
// if (res.data.code != 200) {
// uni.showToast({
// title: res.data.msg,
// icon: 'none'
// });
// } else {
// uni.showToast({
// title: res.data.msg
// });
// js = setInterval(function() {
// _this.second--;
// if (_this.second == 0) {
// _this.clear()
// }
// }, 1000)
// }
// },
// fail() {
// this.second == 0
// }
// });
},
bindLogin() {
if (this.agreement == false) {
uni.showToast({
icon: 'none',
title: '请先阅读《软件用户协议》'
});
return;
}
if (this.phone.length != 11) {
uni.showToast({
icon: 'none',
title: '手机号不正确'
});
return;
}
if (this.password.length < 6) {
uni.showToast({
icon: 'none',
title: '密码不正确'
});
return;
}
if (this.code.length != 4) {
uni.showToast({
icon: 'none',
title: '验证码不正确'
});
return;
}
uni.request({
url: 'http://***/reg.html',
data: {
phone: this.phone,
password: this.password,
code: this.code,
},
method: 'POST',
dataType: 'json',
success: (res) => {
if (res.data.code != 200) {
uni.showToast({
title: res.data.msg,
icon: 'none'
});
} else {
uni.showToast({
title: res.data.msg
});
setTimeout(function() {
uni.navigateBack();
}, 1500)
}
}
});
}
}
}
</script>
<style>
page {
background-color: #fff;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
}
.header {
width: 161rpx;
height: 161rpx;
border-radius: 50%;
margin-top: 30rpx;
margin-left: auto;
margin-right: auto;
}
.header image {
width: 161rpx;
height: 161rpx;
border-radius: 50%;
}
.list {
display: flex;
flex-direction: column;
padding-top: 50rpx;
padding-left: 70rpx;
padding-right: 70rpx;
}
.list-call {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
color: #333333;
border-bottom: 0.5px solid #e2e2e2;
}
.list-call .sl-input {
flex: 1;
text-align: left;
font-size: 32rpx;
margin-left: 16rpx;
}
.yzm {
color: #FF7D13;
font-size: 24rpx;
line-height: 64rpx;
padding-left: 10rpx;
padding-right: 10rpx;
width: auto;
height: 64rpx;
border: 1rpx solid #FFA800;
border-radius: 50rpx;
}
.yzms {
color: #999999 !important;
border: 1rpx solid #999999;
}
.button-login {
color: #FFFFFF;
font-size: 34rpx;
width: 470rpx;
height: 100rpx;
line-height: 100rpx;
background: linear-gradient(-90deg, rgba(193, 25, 32, 1), rgba(238, 38, 38, 1));
border-radius: 50rpx;
text-align: center;
margin-left: auto;
margin-right: auto;
margin-top: 100rpx;
}
.button-hover {
background: linear-gradient(-90deg, rgba(193, 25, 32, 0.8), rgba(238, 38, 38, 0.8));
}
.agreement {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 30rpx;
margin-top: 80rpx;
color: #FFA800;
text-align: center;
height: 40rpx;
line-height: 40rpx;
}
.agreement image {
width: 40rpx;
height: 40rpx;
}
</style>

@ -0,0 +1,30 @@
<template>
<view>
<view class="bg-white padding">
<view class="text-xl text-center">我的
</view>
</view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {
};
},
onShow() {
//
},
onLoad() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,13 @@
<template>
<u-empty mode="page">
<u-button slot="bottom" size="medium" @click="$Router.pushTab('/pages/tabbar/home')">
去首页
</u-button>
</u-empty>
</template>
<script></script>
<style></style>

@ -0,0 +1,146 @@
<template>
<view style="margin-top: 100px;">
<view class="flex ai-c jc-c">
<view class="flex type_box">
<view class="type_item" :class="tCurrent==0?'checked':'unchecked'" @tap="sectionChange(0)">答题</view>
<view class="type_item" :class="tCurrent==1?'checked':'unchecked'" @tap="sectionChange(1)">背题</view>
</view>
</view>
<view class="m14lr">
<text class="tag_box">{{questionList[currentIndex].questionTypeDesc}}</text>
<text class="fs18">{{questionList[currentIndex].questionDesc}}</text>
</view>
<view class="flex m14lr ai-c mt20" v-for="(item,index) in questionList[currentIndex].optionList" :key="item.op">
<template v-if="clickAnswer&&item.op===questionList[currentIndex].rightAnswer">
<u-icon name="checkmark-circle-fill" color="#05C341" size="30"></u-icon>
</template>
<template v-else-if="clickAnswer===item.op&&item.op!==questionList[currentIndex].rightAnswer">
<u-icon name="close-circle-fill" color="red" size="30"></u-icon>
</template>
<template v-else-if="!clickAnswer">
<view class="option_item">{{item.op}}</view>
</template>
<text class="fs18">{{item.opDesc}}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
tCurrent:0,
clickAnswer:undefined,
questionList:[],
currentIndex:0,
}
},
onshow(){
this.getQuestionList()
},
methods: {
sectionChange(index){
this.tCurrent=index
},
getQuestionList(){
this.questionList=[{
questionId:0,
questionTypeDesc:'单选',
questionDesc:'在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?',
optionList:[{
op:'A',
opDesc:'注意新手标志'
},{
op:'B',
opDesc:'注意新手标志'
},{
op:'C',
opDesc:'注意新手标志'
},{
op:'D',
opDesc:'注意新手标志'
}],
rightOp:'C',
},{
questionId:1,
questionDesc:'在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?',
optionList:[{
op:'A',
opDesc:'注意新手标志'
},{
op:'B',
opDesc:'注意新手标志'
},{
op:'C',
opDesc:'注意新手标志'
},{
op:'D',
opDesc:'注意新手标志'
}],
rightOp:'B',
},{
questionId:2,
questionDesc:'在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?',
optionList:[{
op:'A',
opDesc:'注意新手标志'
},{
op:'B',
opDesc:'注意新手标志'
},{
op:'C',
opDesc:'注意新手标志'
},{
op:'D',
opDesc:'注意新手标志'
}],
rightOp:'A',
}]
}
}
}
</script>
<style scoped>
.type_box{
width: 280rpx;
height: 72rpx;
background-color: #FFFFFF;
border-radius: 8rpx;
}
.type_item{
text-align: center;
line-height: 64rpx;
width: 126rpx;
height: 64rpx;
border-radius: 8rpx;
}
.checked{
color: #fff;
background-color: #05C341;
}
.unchecked{
color: #666;
}
.tag_box{
display: inline-block;
width: 78rpx;
height: 42rpx;
background: #05C341;
border-radius: 8rpx;
text-align: center;
line-height: 42rpx;
color: #fff;
font-size: 12px;
margin-right: 5px;
}
.option_item{
width: 60rpx;
height: 60rpx;
border: 1px solid #666;
border-radius: 50%;
text-align: center;
line-height: 60rpx;
margin-right: 30rpx;
}
</style>

@ -0,0 +1,22 @@
<template>
<view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>

@ -0,0 +1,28 @@
<template>
<view>
<u-navbar title="顺序答题" @rightClick="rightClick" :autoBack="true">
</u-navbar>
<Question />
</view>
</template>
<script>
import Question from './components/Question.vue';
export default {
components: {Question},
data() {
return {
}
},
methods: {
rightClick(){
console.log('返回');
}
}
}
</script>
<style>
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1,3 @@
page {
color: $uni-color-primary;
}

@ -0,0 +1,429 @@
/*每个页面公共css */
page {
background: #f4f4f4;
color: #383838;
font-size: 26rpx;
}
/* image{
background: skyblue;
} */
image,
video {
display: block;
}
image{will-change: transform}
/*字体颜色*/
.cor_fff {
color: #fff;
}
.cor_000 {
color: #000;
}
.cor_red {
color: #eb3831;
}
.cor_333 {
color: #333;
}
.cor_666 {
color: #666;
}
.cor_999 {
color: #999;
}
.cor_ccc {
color: #ccc;
}
.cor_eee{
color: #eee;
}
.cor_text {
color: #262626;
}
.cor_38{
color: #383838;
}
.cor_8c {
color: #8c8c8c;
}
.cor_80 {
color: #808080;
}
.cor_A6 {
color: #A6A6A6;
}
.cor_theme {
color: $uni-color-primary !important;
}
.cor_blue {
color: #43aefd;
}
.bk_theme {
background-color: $uni-color-primary !important;
color: #fff !important;
}
.fwb {
font-weight: bold;
}
/**图片大小**/
.img16 {
width: 16rpx;
height: 16rpx;
}
.mt70 {
margin-top: 70rpx;
}
.mt80 {
margin-top: 80rpx;
}
.mt90 {
margin-top: 90rpx;
}
.mr60 {
margin-right: 60rpx;
}
.mr70 {
margin-right: 70rpx;
}
.mr100 {
margin-right: 100rpx;
}
.m20lr {
margin-left: 20rpx;
margin-right: 20rpx;
}
.m30lr {
margin-left: 30rpx;
margin-right: 30rpx;
}
/**border**/
.bb1 {
border-bottom: solid 1px #f4f4f4;
}
.bt1 {
border-top: solid 1px #eee;
}
.border1 {
border: solid 1px #eee;
}
.border_tb1{
border-bottom: solid 1px #eee;
border-top: solid 1px #eee;
}
/***背景**/
.bk_f {
background-color: #fff;
}
.bk_f9 {
background-color: #f9f9f9;
}
.bk_f2 {
background-color: #f2f2f2;
}
.bk_rgba05 {
background-color: rgba(0, 0, 0, 0.5);
}
.bk_main {
background-color: #3d92e1;
}
.bk_blue {
background: skyblue;
}
.bk_red {
background-color: #ff2d17;
}
.bk_white {
background-color: #fff;
}
.opt5 {
opacity: 0.5;
}
.br_p50 {
border-radius: 50%;
}
.br_ltb{
border-radius: 50% 0 0 50% !important;
}
.br_rtb{
border-radius: 0 50% 50% 0 !important;
}
/**宽度**/
.wp20 {
width: 20%;
}
.wp25 {
width: 25%;
}
.wp40 {
width: 40%;
}
.wp50 {
width: 50%;
}
.wp100 {
width: 100%;
}
/**高度**/
.hp100 {
height: 100%;
}
/**行距**/
.lh1 {
line-height: 1;
}
.lh50{
line-height: 50rpx;
}
/**flex 设置**/
.df {
display: flex;
}
.fldr {
flex-direction: row !important;
}
.fldc {
flex-direction: column !important;
}
.fldrr {
flex-direction: row-reverse !important;
}
.jcsb {
justify-content: space-between !important;
}
.jcsba {
justify-content: space-around !important;
}
.jcfs {
justify-content: flex-start !important;
}
.jcc {
justify-content: center !important;
}
.jcfe {
justify-content: flex-end;
}
.fl1 {
flex: 1 !important;
}
.fw {
flex-wrap: wrap;
}
.ai-center {
align-items: center !important;
}
.ai-start {
align-items: flex-start;
}
.ai-baseline {
align-items: flex-end;
}
.ai-end {
align-items: flex-end;
}
.fls0 {
flex-shrink: 0;
}
/*对齐*/
.tac {
text-align: center;
}
.tar {
text-align: right;
}
.tal {
text-align: left;
}
/** 其他样式 **/
.ov {
overflow: hidden;
}
.ovya {
overflow-y: auto;
}
.bsb {
box-sizing: border-box;
}
.re {
position: relative;
}
.ab {
position: absolute;
}
.ab_full {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.fixed {
position: fixed;
}
.db {
display: block;
}
.di {
display: inline;
}
.dib {
display: inline-block;
}
.dif {
display: inline-flex;
}
.v-middle {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.h-middle {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.middle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.text-line-through {
text-decoration: line-through;
}
.text-underline {
text-decoration: underline;
}
.wb {
display: block;
word-break: break-all;
word-wrap: break-word;
}
.vam {
vertical-align: middle;
}
/*灰色分割条*/
.gray_bar {
height: 20rpx;
background: #f5f5f5;
}
.scroll-box {
flex: 1;
height: 100%;
position: relative;
}
.content_box {
flex: 1;
overflow-y: auto;
}
.theme-tag {
display: inline-block;
padding: 0 25rpx;
height: 36rpx;
line-height: 36rpx;
border-radius: 20rpx;
border: 2rpx solid $uni-color-primary;
box-sizing: content-box;
font-size: 24rpx;
color: $uni-color-primary;
}
.selector {
position: relative;
padding-left: 30rpx;
padding-right: 20rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx;
font-size: 24rpx;
color: #333;
background-color: #fff;
}
.selector.actived {
color: $uni-color-primary;
border: 1rpx solid $uni-color-primary;
background: #e6f2ff;
}
.img24 {
width: 24px;
height: 24px;
}
.img36 {
width: 36px;
height: 36px;
}
.img48 {
width: 48px;
height: 48px;
}
.img50 {
width: 50px;
height: 50px;
}
.img120 {
width: 120px;
height: 120px;
}
.img140 {
width: 140px;
height: 140px;
}
.theme-bg-light {
background-color: $uni-color-primary;
}
.pt100 {
padding-top: 100rpx;
}
.theme-btn {
padding: 0 20px;
min-width: 250rpx;
height: 78rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
color: #fff;
border-radius: 40rpx;
background-color: $uni-color-primary;
}
.theme-btn-light {
padding: 0 20px;
min-width: 250rpx;
height: 78rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
color: #fff;
border-radius: 40rpx;
color: $uni-color-primary;
border: 1px solid $uni-color-primary;
}
.img70 {
width:70px;
height: 70px;
}
// .u-tabbar {
// max-height: 50px;
// }

@ -0,0 +1,678 @@
html,
body,
#app {
box-sizing: border-box;
height: 100%;
font-family: Avenir, Helvetica, Arial, sans-serif;
}
/* 背景 */
.bc-000 {
background-color: #000;
}
.bc-f5 {
background-color: #f5f5f5;
}
.bc-f7 {
background-color: #f7f7f7;
}
.bc-fff {
background-color: #fff;
}
.bc-t {
background-color: transparent;
}
/* border */
.border-top {
border-top: solid 1px #eee;
}
.border-bottom {
border-bottom: solid 1px #eee;
}
.border-0 {
border: 0px;
}
.border-1 {
border: 1px solid #eee;
}
.border-2 {
border: 2px solid #eee;
}
.border-3 {
border: 3px solid #eee;
}
.border-4 {
border: 4px solid #eee;
}
.border-5 {
border: 5px solid #eee;
}
/* 文本格式 */
.i {
word-wrap: break-word;
text-align: justify;
text-justify: inter-ideograph;
}
/* 字体颜色 */
.cor-000 {
color: #000000;
}
.cor-333 {
color: #333333;
}
.cor-666 {
color: #666666;
}
.cor-999 {
color: #999999;
}
.cor-aaa {
color: #aaaaaa;
}
.cor-ccc {
color: #cccccc;
}
.cor-ddd {
color: #dddddd;
}
.cor-fff {
color: #ffffff;
}
.cor-price {
color: #C03639;
}
/* 行距 */
.lh10 {
line-height: 1;
}
.lh11 {
line-height: 1.1;
}
.lh12 {
line-height: 1.2;
}
.lh13 {
line-height: 1.3;
}
.lh14 {
line-height: 1.4;
}
.lh15 {
line-height: 1.5;
}
.lh16 {
line-height: 1.6;
}
.lh18 {
line-height: 1.8;
}
.lh20 {
line-height: 2;
}
.lh25 {
line-height: 2.5;
}
.lh30 {
line-height: 3;
}
/* 高度 */
.hvh100 {
height: 100vh;
overflow: hidden;
}
.hp100 {
height: 100%;
overflow: hidden;
}
/* float */
.float-l {
float: left;
}
.float-r {
float: right;
}
.clearfix-both::after {
display: table;
clear: both;
content: '';
}
/* flex */
.flex {
display: flex;
}
.fl0 {
flex: 0;
}
.fl1 {
flex: 1;
}
.fl2 {
flex: 2;
}
.fl3 {
flex: 3;
}
.fl4 {
flex: 4;
}
.fld-r {
flex-direction: row;
}
.fld-c {
flex-direction: column;
}
.fld-rr {
flex-direction: row-reverse;
}
.flw-w {
flex-wrap: wrap;
}
.fls0 {
flex-shrink: 0;
}
.jc-sb {
justify-content: space-between;
}
.jc-sa {
justify-content: space-around;
}
.jc-fs {
justify-content: flex-start;
}
.jc-c {
justify-content: center;
}
.jc-fe {
justify-content: flex-end;
}
.ai-c {
align-items: center;
}
.ai-s {
align-items: stretch;
}
.ai-fs {
align-items: flex-start;
}
.ai-fe {
align-items: flex-end;
}
/* 对齐 */
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.text-left {
text-align: left;
}
/* display */
.none {
display: none;
}
.block {
display: block;
}
.inline {
display: inline;
}
.inline-block {
display: inline-block;
}
/* 溢出 */
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-ellipsis2 {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.text-ellipsis3 {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
/* 其他 */
.middle {
position: absolute;
z-index: 2;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.middle-y {
position: absolute;
z-index: 2;
top: 50%;
transform: translateY(-50%);
}
.middle-x {
position: absolute;
z-index: 2;
left: 50%;
transform: translateX(-50%);
}
.text-line-through {
text-decoration: line-through;
}
.text-underline {
text-decoration: underline;
}
.overflow-h {
overflow: hidden;
}
.overflow-y {
overflow-y: auto;
overflow-x: hidden;
}
.overflow-x {
overflow-x: auto;
overflow-y: hidden;
}
.border-box {
box-sizing: border-box;
}
.content-box {
box-sizing: content-box;
}
.relative {
position: relative;
z-index: 1;
}
.absolute {
position: absolute;
z-index: 2;
}
.absolute-full {
position: absolute;
z-index: 2;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.fixed {
position: fixed;
z-index: 9;
}
.break-all {
display: block;
word-break: break-all;
word-wrap: break-word;
}
.nowrap {
white-space: nowrap;
}
.va-m {
vertical-align: middle;
}
.va-t {
vertical-align: top;
}
.va-b {
vertical-align: bottom;
}
.opacity0 {
opacity: 0;
}
.opacity1 {
opacity: 0.1;
}
.opacity2 {
opacity: 0.2;
}
.opacity3 {
opacity: 0.3;
}
.opacity4 {
opacity: 0.4;
}
.opacity5 {
opacity: 0.5;
}
.opacity6 {
opacity: 0.6;
}
.opacity7 {
opacity: 0.7;
}
.opacity8 {
opacity: 0.8;
}
.opacity9 {
opacity: 0.9;
}
.opacity10 {
opacity: 1;
}
/* z-index */
.z-index-1 {
z-index: -1;
}
.z-index0 {
z-index: 0;
}
.z-index1 {
z-index: 1;
}
.z-index2 {
z-index: 2;
}
.z-index3 {
z-index: 3;
}
.z-index4 {
z-index: 4;
}
.z-index5 {
z-index: 5;
}
.z-index6 {
z-index: 6;
}
.z-index7 {
z-index: 7;
}
.z-index8 {
z-index: 8;
}
.z-index9 {
z-index: 9;
}
.z-index10 {
z-index: 10;
}
.z-index15 {
z-index: 15;
}
.z-index19 {
z-index: 19;
}
.z-index20 {
z-index: 20;
}
.z-index99 {
z-index: 99;
}
.z-index100 {
z-index: 100;
}
.z-index300 {
z-index: 300;
}
.z-index500 {
z-index: 500;
}
.z-index999 {
z-index: 999;
}
/* 宽度 */
.wp20 {
width: 20%;
}
.wp23 {
width: 23%;
}
.wp24 {
width: 24%;
}
.wp25 {
width: 25%;
}
.wp30 {
width: 30%;
}
.wp31 {
width: 31%;
}
.wp32 {
width: 32%;
}
.wp33 {
width: 33%;
}
.wp40 {
width: 40%;
}
.wp45 {
width: 45%;
}
.wp48 {
width: 48%;
}
.wp49 {
width: 49%;
}
.wp50 {
width: 50%;
}
.wp60 {
width: 60%;
}
.wp70 {
width: 70%;
}
.wp80 {
width: 80%;
}
.wp85 {
width: 85%;
}
.wp90 {
width: 90%;
}
.wp95 {
width: 95%;
}
.wp100 {
width: 100%;
}
.wvw100 {
width: 100vw;
}
.wp100-i {
width: 100% !important;
}
/* 字体样式 */
.arial {
font-family: Arial;
}
/* 字体大小 */
@for $i from 0 through 100 {
.fs#{$i} {
font-size: $i + px;
}
.img#{$i} {
width: $i + px;
height: $i + px;
}
}
.fw400 {
font-weight: 400;
}
.fw500 {
font-weight: 500;
}
.fw600 {
font-weight: 600;
}
.fw700 {
font-weight: 700;
}
.fw800 {
font-weight: 800;
}
.fw900 {
font-weight: 900;
}
.m0a {
margin: 0 auto;
}
.br-p50 {
border-radius: 50%;
}
/* marging */
.mt-3 {
margin-top: -3px;
}
.mt-2 {
margin-top: -2px;
}
.mt-1 {
margin-top: -1px;
}
.mr-3 {
margin-right: -3px;
}
.mr-2 {
margin-right: -2px;
}
.mr-1 {
margin-right: -1px;
}
.mr-p1 {
margin-right: 1%;
}
.mr-p2 {
margin-right: 2%;
}
.mr-p3 {
margin-right: 3%;
}
.mr-p4 {
margin-right: 4%;
}
.mr-p5 {
margin-right: 5%;
}
.mb-5 {
margin-bottom: -5px;
}
.mb-4 {
margin-bottom: -4px;
}
.mb-3 {
margin-bottom: -3px;
}
.mb-2 {
margin-bottom: -2px;
}
.mb-1 {
margin-bottom: -1px;
}
.ml-5 {
margin-left: -5px;
}
.ml-4 {
margin-left: -4px;
}
.ml-3 {
margin-left: -3px;
}
.ml-2 {
margin-left: -2px;
}
.ml-1 {
margin-left: -1px;
}
@for $i from 0 through 50 {
.m#{$i} {
margin: $i + px;
}
.mt#{$i} {
margin-top: $i + px;
}
.ml#{$i} {
margin-left: $i + px;
}
.mb#{$i} {
margin-bottom: $i + px;
}
.mr#{$i} {
margin-right: $i + px;
}
.m#{$i}tb {
margin-top: $i + px;
margin-bottom: $i + px;
}
.m#{$i}lr {
margin-left: $i + px;
margin-right: $i + px;
}
.p#{$i} {
padding: $i + px;
}
.pt#{$i} {
padding-top: $i + px;
}
.pl#{$i} {
padding-left: $i + px;
}
.pb#{$i} {
padding-bottom: $i + px;
}
.pr#{$i} {
padding-right: $i + px;
}
.p#{$i}lr {
padding-left: $i + px;
padding-right: $i + px;
}
.p#{$i}tb {
padding-top: $i + px;
padding-bottom: $i + px;
}
.br#{$i} {
border-radius: $i + px;
}
}
@for $i from -10 through 20 {
.top#{$i} {
top: $i + px;
}
.left#{$i} {
left: $i + px;
}
.right#{$i} {
right: $i + px;
}
.bottom#{$i} {
bottom: $i + px;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,121 @@
@import '@/static/style/colorui.css';
@import './base.scss';
@import './app.scss';
page {
-webkit-overflow-scrolling: touch; // ios滑动不流畅
height: 100%;
background: #f6f6f6;
width: 100%;
font-size: 30rpx;
font-family: Arial;
word-break: break-all; //英文文本不换行
white-space: normal;
color: $u-main-color;
// padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
// box-sizing: content-box;
}
/* #ifdef MP-WEIXIN || APP-PLUS */
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
color: transparent;
}
/* #endif */
uni-tabbar.uni-tabbar-bottom .uni-tabbar {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
}
.box-safe-area {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
}
.u-tabs .uni-scroll-view::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
display: none !important;
}
.content-wrapper {
padding: 25rpx;
}
.input-placeholder {
font-size: 28rpx !important;
color: #a6a6a6 !important;
font-weight: 400 !important;
}
.uni-input-input, .uni-textarea-textarea, {
font-size: 28rpx;
color: #333;
}
.value-form .u-form-item__body {
flex-wrap: wrap !important;
align-items: flex-start !important;
}
.u-form-item__body__right__message {
margin-left: 0 !important;
text-align: center;
}
.u-form-item__body {
padding-top: 30rpx !important;
padding-bottom: 30rpx !important;
.u-form-item__body__left {
margin-right: 30rpx !important;
}
.u-form-item__body__right {
font-size: 28rpx !important;
}
}
.form-label {
font-size: 28rpx;
color: #666;
line-height: 1;
}
.form-value {
font-size: 28rpx;
color: #000;
line-height: 40rpx;
}
.u-tabs__wrapper__nav__line {
bottom: 0 !important;
}
.u-notice .uicon-volume {
font-size: 40rpx !important;
}
.uni-modal__btn_primary {
color: $uni-color-primary !important;
}
.u-empty__text {
font-size: 30rpx !important;
}
.notice .u-icon__icon {
color: $uni-color-primary !important;
}
.u-popup {
flex: none !important;
.u-popup__content__close {
padding: 15rpx;
}
}
input[type='password'] {
font-size: 14px;
}

@ -0,0 +1,76 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
@import '@/uni_modules/uview-plus/theme.scss';
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:24rpx;
$uni-font-size-base:28rpx;
$uni-font-size-lg:32rpx;
/* 图片尺寸 */
$uni-img-size-sm:40rpx;
$uni-img-size-base:52rpx;
$uni-img-size-lg:80rpx;
/* Border Radius */
$uni-border-radius-sm: 4rpx;
$uni-border-radius-base: 6rpx;
$uni-border-radius-lg: 12rpx;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 10px;
$uni-spacing-row-base: 20rpx;
$uni-spacing-row-lg: 30rpx;
/* 垂直间距 */
$uni-spacing-col-sm: 8rpx;
$uni-spacing-col-base: 16rpx;
$uni-spacing-col-lg: 24rpx;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:40rpx;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:36rpx;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:30rpx;

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 www.uviewui.com
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.

@ -0,0 +1,64 @@
<p align="center">
<img alt="logo" src="https://uviewui.com/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/uiadmin/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生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。
## [官方文档:https://uiadmin.net/uview-plus](https://uiadmin.net/uview-plus)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uiadmin.net/uview-plus/common/h5_qrcode.png" width="220" height="220" >
## 链接
- [官方文档](https://uiadmin.net/uview-plus)
- [更新日志](https://uiadmin.net/uview-plus/components/changelog.html)
- [升级指南](https://uiadmin.net/uview-plus/components/changeGuide.html)
- [关于我们](https://uiadmin.net/uview-plus/cooperation/about.html)
## 交流反馈
欢迎加入我们的QQ群交流反馈:[点此跳转](https://uiadmin.net/uview-plus/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://uiadmin.net/uview-plus/components/install.html)了解更详细的内容
## 快速上手
请通过[快速上手](https://uiadmin.net/uview-plus/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应用到您的产品中。

@ -0,0 +1,22 @@
## 3.1.31(2023-05-15)
本地累计修复一些问题提交
## 3.0.9(2022-07-14)
修复u-search双向绑定
## 3.0.8(2022-07-12)
修复u-tag默认宽度撑满容器
## 3.0.7(2022-07-12)
修复u-navbar自定义插槽演示示例
## 3.0.6(2022-07-11)
修复u-image缺少emits申明
## 3.0.5(2022-07-11)
修复u-upload缺少emits申明
## 3.0.4(2022-07-10)
修复u-textarea/u-input/u-datetime-picker/u-number-box/u-radio-group/u-switch/u-rate在vue3下数据绑定
## 3.0.3(2022-07-09)
启用自建演示二维码
## 3.0.2(2022-07-09)
修复dayjs/clipboard等导致打包报错
## 3.0.1(2022-07-09)
增加插件市场地址
## 3.0.0(2022-07-09)
# uview-plus(vue3)初步发布

@ -0,0 +1,80 @@
<template>
<uvForm
ref="uForm"
:model="model"
:rules="rules"
:errorType="errorType"
:borderBottom="borderBottom"
:labelPosition="labelPosition"
:labelWidth="labelWidth"
:labelAlign="labelAlign"
:labelStyle="labelStyle"
:customStyle="customStyle"
>
<slot />
</uvForm>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-form被uni-app官方占用了u-form在nvue中相当于form组件
* 所以在nvue下取名为u--form内部其实还是u-form.vue只不过做一层中转
*/
import uvForm from '../u-form/u-form.vue';
import props from '../u-form/props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
export default {
// #ifdef MP-WEIXIN
name: 'u-form',
// #endif
// #ifndef MP-WEIXIN
name: 'u--form',
// #endif
mixins: [mpMixin, props, mixin],
components: {
uvForm
},
created() {
this.children = []
},
methods: {
//
setRules(rules) {
this.$refs.uForm.setRules(rules)
},
validate() {
/**
* 在微信小程序中通过this.$parent拿到的父组件是u--form而不是其内嵌的u-form
* 导致在u-form组件中拿不到对应的children数组从而校验无效所以这里每次调用u-form组件中的
* 对应方法的时候在小程序中都先将u--form的children赋值给u-form中的children
*/
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validate()
},
validateField(value, callback) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validateField(value, callback)
},
resetFields() {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.resetFields()
},
clearValidate(props) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.clearValidate(props)
},
setMpData() {
this.$refs.uForm.children = this.children
}
},
}
</script>

@ -0,0 +1,50 @@
<template>
<uvImage
:src="src"
:mode="mode"
:width="width"
:height="height"
:shape="shape"
:radius="radius"
:lazyLoad="lazyLoad"
:showMenuByLongpress="showMenuByLongpress"
:loadingIcon="loadingIcon"
:errorIcon="errorIcon"
:showLoading="showLoading"
:showError="showError"
:fade="fade"
:webp="webp"
:duration="duration"
:bgColor="bgColor"
:customStyle="customStyle"
@click="$emit('click')"
@error="$emit('error')"
@load="$emit('load')"
>
<template v-slot:loading>
<slot name="loading"></slot>
</template>
<template v-slot:error>
<slot name="error"></slot>
</template>
</uvImage>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-image被uni-app官方占用了u-image在nvue中相当于image组件
* 所以在nvue下取名为u--image内部其实还是u-iamge.vue只不过做一层中转
*/
import uvImage from '../u-image/u-image.vue';
import props from '../u-image/props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
export default {
name: 'u--image',
mixins: [mpMixin, props, mixin],
components: {
uvImage
},
emits: ['click', 'error', 'load']
}
</script>

@ -0,0 +1,74 @@
<template>
<uvInput
<!-- #ifdef VUE2 -->
:value="value"
@input="e => $emit('input', e)"
<!-- #endif -->
<!-- #ifdef VUE3 -->
:modelValue="modelValue"
@update:modelValue="e => $emit('update:modelValue', e)"
<!-- #endif -->
:type="type"
:fixed="fixed"
:disabled="disabled"
:disabledColor="disabledColor"
:clearable="clearable"
:password="password"
:maxlength="maxlength"
:placeholder="placeholder"
:placeholderClass="placeholderClass"
:placeholderStyle="placeholderStyle"
:showWordLimit="showWordLimit"
:confirmType="confirmType"
:confirmHold="confirmHold"
:holdKeyboard="holdKeyboard"
:focus="focus"
:autoBlur="autoBlur"
:disableDefaultPadding="disableDefaultPadding"
:cursor="cursor"
:cursorSpacing="cursorSpacing"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:inputAlign="inputAlign"
:fontSize="fontSize"
:color="color"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:suffixIconStyle="suffixIconStyle"
:prefixIconStyle="prefixIconStyle"
:border="border"
:readonly="readonly"
:shape="shape"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
>
<!-- #ifdef MP -->
<slot name="prefix"></slot>
<slot name="suffix"></slot>
<!-- #endif -->
<!-- #ifndef MP -->
<slot name="prefix" slot="prefix"></slot>
<slot name="suffix" slot="suffix"></slot>
<!-- #endif -->
</uvInput>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-input被uni-app官方占用了u-input在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-input.vue只不过做一层中转
*/
import uvInput from '../u-input/u-input.vue';
import props from '../u-input/props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
export default {
name: 'u--input',
mixins: [mpMixin, props, mixin],
components: {
uvInput
},
}
</script>

@ -0,0 +1,45 @@
<template>
<uvText
:type="type"
:show="show"
:text="text"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:mode="mode"
:href="href"
:format="format"
:call="call"
:openType="openType"
:bold="bold"
:block="block"
:lines="lines"
:color="color"
:decoration="decoration"
:size="size"
:iconStyle="iconStyle"
:margin="margin"
:lineHeight="lineHeight"
:align="align"
:wordWrap="wordWrap"
:customStyle="customStyle"
></uvText>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-text被uni-app官方占用了u-text在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-text.vue只不过做一层中转
* 不使用v-bind="$attrs"而是分开独立写传参是因为微信小程序不支持此写法
*/
import uvText from "../u-text/u-text.vue";
import props from "../u-text/props.js";
import mpMixin from '../../libs/mixin/mpMixin.js'
import mixin from '../../libs/mixin/mixin.js'
export default {
name: "u--text",
mixins: [mpMixin, mixin, props,],
components: {
uvText,
},
};
</script>

@ -0,0 +1,47 @@
<template>
<uvTextarea
:value="value"
:modelValue="modelValue"
:placeholder="placeholder"
:height="height"
:confirmType="confirmType"
:disabled="disabled"
:count="count"
:focus="focus"
:autoHeight="autoHeight"
:fixed="fixed"
:cursorSpacing="cursorSpacing"
:cursor="cursor"
:showConfirmBar="showConfirmBar"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:disableDefaultPadding="disableDefaultPadding"
:holdKeyboard="holdKeyboard"
:maxlength="maxlength"
:border="border"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@input="e => $emit('input', e)"
@update:modelValue="e => $emit('update:modelValue', e)"
></uvTextarea>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u--textarea被uni-app官方占用了u-textarea在nvue中相当于textarea组件
* 所以在nvue下取名为u--textarea内部其实还是u-textarea.vue只不过做一层中转
*/
import uvTextarea from '../u-textarea/u-textarea.vue';
import props from '../u-textarea/props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
export default {
name: 'u--textarea',
mixins: [mpMixin, props, mixin],
components: {
uvTextarea
},
}
</script>

@ -0,0 +1,55 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,279 @@
<template>
<u-popup
:show="show"
mode="bottom"
@close="closeHandler"
:safeAreaInsetBottom="safeAreaInsetBottom"
:round="round"
>
<view class="u-action-sheet">
<view
class="u-action-sheet__header"
v-if="title"
>
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
<view
class="u-action-sheet__header__icon-wrap"
@tap.stop="cancel"
>
<u-icon
name="close"
size="17"
color="#c8c9cc"
bold
></u-icon>
</view>
</view>
<text
class="u-action-sheet__description"
:style="[{
marginTop: `${title && description ? 0 : '18px'}`
}]"
v-if="description"
>{{description}}</text>
<slot>
<u-line v-if="description"></u-line>
<view class="u-action-sheet__item-wrap">
<view :key="index" v-for="(item, index) in actions">
<!-- #ifdef MP -->
<button
class="u-reset-button"
:openType="item.openType"
@getuserinfo="onGetUserInfo"
@contact="onContact"
@getphonenumber="onGetPhoneNumber"
@error="onError"
@launchapp="onLaunchApp"
@opensetting="onOpenSetting"
:lang="lang"
:session-from="sessionFrom"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
:app-parameter="appParameter"
@tap="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
>
<!-- #endif -->
<view
class="u-action-sheet__item-wrap__item"
@tap.stop="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
:hover-stay-time="150"
>
<template v-if="!item.loading">
<text
class="u-action-sheet__item-wrap__item__name"
:style="[itemStyle(index)]"
>{{ item.name }}</text>
<text
v-if="item.subname"
class="u-action-sheet__item-wrap__item__subname"
>{{ item.subname }}</text>
</template>
<u-loading-icon
v-else
custom-class="van-action-sheet__loading"
size="18"
mode="circle"
/>
</view>
<!-- #ifdef MP -->
</button>
<!-- #endif -->
<u-line v-if="index !== actions.length - 1"></u-line>
</view>
</view>
</slot>
<u-gap
bgColor="#eaeaec"
height="6"
v-if="cancelText"
></u-gap>
<view hover-class="u-action-sheet--hover">
<text
@touchmove.stop.prevent
:hover-stay-time="150"
v-if="cancelText"
class="u-action-sheet__cancel-text"
@tap="cancel"
>{{cancelText}}</text>
</view>
</view>
</u-popup>
</template>
<script>
import openType from '../../libs/mixin/openType'
import button from '../../libs/mixin/button'
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* ActionSheet 操作菜单
* @description 本组件用于从底部弹出一个操作菜单供用户选择并返回结果本组件功能类似于uni的uni.showActionSheetAPI配置更加灵活所有平台都表现一致
* @tutorial https://ijry.github.io/uview-plus/components/actionSheet.html
*
* @property {Boolean} show 操作菜单是否展示 默认 false
* @property {String} title 操作菜单标题
* @property {String} description 选项上方的描述信息
* @property {Array<Object>} actions 按钮的文字数组见官方文档示例
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 默认 true
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 默认 true
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting getPhoneNumber error )
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
* @property {Number|String} round 圆角值默认无圆角 (默认 0 )
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效 默认 false
* @property {String} appParameter 打开 APP APP 传递的参数openType=launchApp 时有效
*
* @event {Function} select 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息回调的 detail 数据与 wx.getUserInfo 返回的一致openType="getUserInfo"时有效
* @event {Function} contact 客服消息回调openType="contact"时有效
* @event {Function} getphonenumber 获取用户手机号回调openType="getPhoneNumber"时有效
* @event {Function} error 当使用开放能力时发生错误的回调openType="error"时有效
* @event {Function} launchapp 打开 APP 成功的回调openType="launchApp"时有效
* @event {Function} opensetting 在打开授权设置页后回调openType="openSetting"时有效
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
// propsmethodsmixin
mixins: [openType, button, mixin, props],
data() {
return {
}
},
computed: {
//
itemStyle() {
return (index) => {
let style = {};
if (this.actions[index].color) style.color = this.actions[index].color
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
//
if (this.actions[index].disabled) style.color = '#c0c4cc'
return style;
}
},
},
methods: {
closeHandler() {
// close
if(this.closeOnClickOverlay) {
this.$emit('close')
}
},
//
cancel() {
this.$emit('close')
},
selectHandler(index) {
const item = this.actions[index]
if (item && !item.disabled && !item.loading) {
this.$emit('select', item)
if (this.closeOnClickAction) {
this.$emit('close')
}
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-action-sheet-reset-button-width:100% !default;
$u-action-sheet-title-font-size: 16px !default;
$u-action-sheet-title-padding: 12px 30px !default;
$u-action-sheet-title-color: $u-main-color !default;
$u-action-sheet-header-icon-wrap-right:15px !default;
$u-action-sheet-header-icon-wrap-top:15px !default;
$u-action-sheet-description-font-size:13px !default;
$u-action-sheet-description-color:14px !default;
$u-action-sheet-description-margin: 18px 15px !default;
$u-action-sheet-item-wrap-item-padding:15px !default;
$u-action-sheet-item-wrap-name-font-size:16px !default;
$u-action-sheet-item-wrap-subname-font-size:13px !default;
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
$u-action-sheet-cancel-text-font-size:16px !default;
$u-action-sheet-cancel-text-color:$u-content-color !default;
$u-action-sheet-cancel-text-font-size:15px !default;
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
.u-reset-button {
width: $u-action-sheet-reset-button-width;
}
.u-action-sheet {
text-align: center;
&__header {
position: relative;
padding: $u-action-sheet-title-padding;
&__title {
font-size: $u-action-sheet-title-font-size;
color: $u-action-sheet-title-color;
font-weight: bold;
text-align: center;
}
&__icon-wrap {
position: absolute;
right: $u-action-sheet-header-icon-wrap-right;
top: $u-action-sheet-header-icon-wrap-top;
}
}
&__description {
font-size: $u-action-sheet-description-font-size;
color: $u-tips-color;
margin: $u-action-sheet-description-margin;
text-align: center;
}
&__item-wrap {
&__item {
padding: $u-action-sheet-item-wrap-item-padding;
@include flex;
align-items: center;
justify-content: center;
flex-direction: column;
&__name {
font-size: $u-action-sheet-item-wrap-name-font-size;
color: $u-main-color;
text-align: center;
}
&__subname {
font-size: $u-action-sheet-item-wrap-subname-font-size;
color: $u-action-sheet-item-wrap-subname-color;
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
text-align: center;
}
}
}
&__cancel-text {
font-size: $u-action-sheet-cancel-text-font-size;
color: $u-action-sheet-cancel-text-color;
text-align: center;
padding: $u-action-sheet-cancel-text-font-size;
}
&--hover {
background-color: $u-action-sheet-cancel-text-hover-background-color;
}
}
</style>

@ -0,0 +1,60 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,261 @@
<template>
<view class="u-album">
<view
class="u-album__row"
ref="u-album__row"
v-for="(arr, index) in showUrls"
:forComputedUse="albumWidth"
:key="index"
>
<view
class="u-album__row__wrapper"
v-for="(item, index1) in arr"
:key="index1"
:style="[imageStyle(index + 1, index1 + 1)]"
@tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
>
<image
:src="getSrc(item)"
:mode="
urls.length === 1
? imageHeight > 0
? singleMode
: 'widthFix'
: multipleMode
"
:style="[
{
width: imageWidth,
height: imageHeight
}
]"
></image>
<view
v-if="
showMore &&
urls.length > rowCount * showUrls.length &&
index === showUrls.length - 1 &&
index1 === showUrls[showUrls.length - 1].length - 1
"
class="u-album__row__wrapper__text"
>
<u--text
:text="`+${urls.length - maxCount}`"
color="#fff"
:size="multipleSize * 0.3"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
// #ifdef APP-NVUE
// weexKPIdom
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* Album 相册
* @description 本组件提供一个类似相册的功能让开发者开发起来更加得心应手减少重复的模板代码
* @tutorial https://ijry.github.io/uview-plus/components/album.html
*
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} singleSize 单图时图片长边的长度 默认 180
* @property {String | Number} multipleSize 多图时图片边长 默认 70
* @property {String | Number} space 多图时图片水平和垂直之间的间隔 默认 6
* @property {String} singleMode 单图时图片缩放裁剪的模式 默认 'scaleToFill'
* @property {String} multipleMode 多图时图片缩放裁剪的模式 默认 'aspectFill'
* @property {String | Number} maxCount 取消按钮的提示文字 默认 9
* @property {Boolean} previewFullImage 是否可以预览图片 默认 true
* @property {String | Number} rowCount 每行展示图片数量如设置singleSize和multipleSize将会无效 默认 3
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 默认 true
*
* @event {Function} albumWidth 某些特殊的情况下需要让文字与相册的宽度相等这里事件的形式对外发送 回调参数 width
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
*/
export default {
name: 'u-album',
mixins: [mpMixin, mixin, props],
data() {
return {
//
singleWidth: 0,
//
singleHeight: 0,
//
singlePercent: 0.6
}
},
watch: {
urls: {
immediate: true,
handler(newVal) {
if (newVal.length === 1) {
this.getImageRect()
}
}
}
},
computed: {
imageStyle() {
return (index1, index2) => {
const { space, rowCount, multipleSize, urls } = this,
{ addUnit, addStyle } = uni.$u,
rowLen = this.showUrls.length,
allLen = this.urls.length
const style = {
marginRight: addUnit(space),
marginBottom: addUnit(space)
}
//
if (index1 === rowLen) style.marginBottom = 0
//
if (
index2 === rowCount ||
(index1 === rowLen &&
index2 === this.showUrls[index1 - 1].length)
)
style.marginRight = 0
return style
}
},
//
showUrls() {
const arr = []
this.urls.map((item, index) => {
//
if (index + 1 <= this.maxCount) {
//
const itemIndex = Math.floor(index / this.rowCount)
//
if (!arr[itemIndex]) {
arr[itemIndex] = []
}
arr[itemIndex].push(item)
}
})
return arr
},
imageWidth() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleWidth : this.multipleSize
)
},
imageHeight() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleHeight : this.multipleSize
)
},
// computedurls
//
albumWidth() {
let width = 0
if (this.urls.length === 1) {
width = this.singleWidth
} else {
width =
this.showUrls[0].length * this.multipleSize +
this.space * (this.showUrls[0].length - 1)
}
this.$emit('albumWidth', width)
return width
}
},
methods: {
//
onPreviewTap(url) {
const urls = this.urls.map((item) => {
return this.getSrc(item)
})
uni.previewImage({
current: url,
urls
})
},
//
getSrc(item) {
return uni.$u.test.object(item)
? (this.keyName && item[this.keyName]) || item.src
: item
},
//
// download
// (singlePercent)
getImageRect() {
const src = this.getSrc(this.urls[0])
uni.getImageInfo({
src,
success: (res) => {
//
const isHorizotal = res.width >= res.height
this.singleWidth = isHorizotal
? this.singleSize
: (res.width / res.height) * this.singleSize
this.singleHeight = !isHorizotal
? this.singleSize
: (res.height / res.width) * this.singleWidth
},
fail: () => {
this.getComponentWidth()
}
})
},
//
async getComponentWidth() {
// dom
await uni.$u.sleep(30)
// #ifndef APP-NVUE
this.$uGetRect('.u-album__row').then((size) => {
this.singleWidth = size.width * this.singlePercent
})
// #endif
// #ifdef APP-NVUE
// ref="u-album__row"forthis.$refs['u-album__row']
const ref = this.$refs['u-album__row'][0]
ref &&
dom.getComponentRect(ref, (res) => {
this.singleWidth = res.size.width * this.singlePercent
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-album {
@include flex(column);
&__row {
@include flex(row);
flex-wrap: wrap;
&__wrapper {
position: relative;
&__text {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex(row);
justify-content: center;
align-items: center;
}
}
}
}
</style>

@ -0,0 +1,45 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,245 @@
<template>
<u-transition
mode="fade"
:show="show"
>
<view
class="u-alert"
:class="[`u-alert--${type}--${effect}`]"
@tap.stop="clickHandler"
:style="[$u.addStyle(customStyle)]"
>
<view
class="u-alert__icon"
v-if="showIcon"
>
<u-icon
:name="iconName"
size="18"
:color="iconColor"
></u-icon>
</view>
<view
class="u-alert__content"
:style="[{
paddingRight: closable ? '20px' : 0
}]"
>
<text
class="u-alert__content__title"
v-if="title"
:style="[{
fontSize: $u.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: $u.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"
>
<u-icon
name="close"
:color="iconColor"
size="15"
></u-icon>
</view>
</view>
</u-transition>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* 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 定义需要用到的外部样式
* @event {Function} click 点击组件时触发
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
*/
export default {
name: 'u-alert',
mixins: [mpMixin, mixin, props],
data() {
return {
show: true
}
},
computed: {
iconColor() {
return this.effect === 'light' ? this.type : '#fff'
},
//
iconName() {
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';
}
}
},
methods: {
//
clickHandler() {
this.$emit('click')
},
//
closeHandler() {
this.show = false
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.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>

@ -0,0 +1,53 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,105 @@
<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 : $u.addUnit(-size * gap)
}"
>
<u-avatar
:size="size"
:shape="shape"
:mode="mode"
:src="$u.test.object(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"
>
<u--text
color="#ffffff"
:size="size * 0.4"
:text="`+${extraValue || urls.length - showUrl.length}`"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* 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)
}
},
methods: {
clickHandler() {
this.$emit('showMore')
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar-group {
@include flex;
&__item {
margin-left: -10px;
position: relative;
&--no-indent {
// 使:first-childnvue
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>

@ -0,0 +1,79 @@
import defprops from '../../libs/config/props';
export default {
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 uni.$u.test.range(n, [0, 19]) || n === ''
},
default: defprops.avatar.colorIndex
},
// 组件标识符
name: {
type: String,
default: defprops.avatar.name
}
}
}

@ -0,0 +1,174 @@
<template>
<view
class="u-avatar"
:class="[`u-avatar--${shape}`]"
:style="[{
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
width: $u.addUnit(size),
height: $u.addUnit(size),
}, $u.addStyle(customStyle)]"
@tap="clickHandler"
>
<slot>
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
<open-data
v-if="mpAvatar && allowMp"
type="userAvatarUrl"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
/>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
<template v-if="mpAvatar && allowMp"></template>
<!-- #endif -->
<u-icon
v-else-if="icon"
:name="icon"
:size="fontSize"
:color="color"
></u-icon>
<u--text
v-else-if="text"
:text="text"
:size="fontSize"
:color="color"
align="center"
customStyle="justify-content: center"
></u--text>
<image
class="u-avatar__image"
v-else
:class="[`u-avatar__image--${shape}`]"
:src="avatarUrl || defaultUrl"
:mode="mode"
@error="errorHandler"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
></image>
</slot>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
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 {
// randomBgColortrue
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: {
// srcavatarUrlsrc
// props
src: {
immediate: true,
handler(newVal) {
this.avatarUrl = newVal
// srcerrorsrc''
if(!newVal) {
this.errorHandler()
}
}
}
},
computed: {
imageStyle() {
const style = {}
return style
}
},
created() {
this.init()
},
methods: {
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() {
this.$emit('click', this.name)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar {
@include flex;
align-items: center;
justify-content: center;
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
&__image {
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
}
}
</style>

@ -0,0 +1,55 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,131 @@
<template>
<u-transition
mode="fade"
:customStyle="backTopStyle"
:show="show"
>
<view
class="u-back-top"
:style="[contentStyle]"
v-if="!$slots.default && !$slots.$default"
@click="backToTop"
>
<u-icon
:name="icon"
:custom-style="iconStyle"
></u-icon>
<text
v-if="text"
class="u-back-top__text"
>{{text}}</text>
</view>
<slot v-else />
</u-transition>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* backTop 返回顶部
* @description 本组件一个用于长页面滑动一定距离后出现返回顶部按钮方便快速返回顶部的场景
* @tutorial https://uviewui.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: uni.$u.addUnit(this.bottom),
right: uni.$u.addUnit(this.right),
width: '40px',
height: '40px',
position: 'fixed',
zIndex: 10,
}
return style
},
show() {
return uni.$u.getPx(this.scrollTop) > uni.$u.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 uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
methods: {
backToTop() {
// #ifdef APP-NVUE
if (!this.$parent.$refs['u-back-top']) {
uni.$u.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>
@import '../../libs/css/components.scss';
$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>

@ -0,0 +1,78 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,173 @@
<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="[$u.addStyle(customStyle), badgeStyle]"
class="u-badge"
>{{ isDot ? '' :showValue }}</text>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* badge 徽标数
* @description 该组件一般用于图标右上角显示未读的消息数量提示用户点击有圆点和圆包含文字两种形式
* @tutorial https://uviewui.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) {
// toprightoffsetrighttop
const top = this.offset[0]
const right = this.offset[1] || top
style.top = uni.$u.addUnit(top)
style.right = uni.$u.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)
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$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>

@ -0,0 +1,46 @@
$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;
}
}

@ -0,0 +1,162 @@
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-16 10:04:04
* @LastAuthor : LQ
* @lastTime : 2021-08-16 10:04:24
* @FilePath : /u-view2.0/uview-ui/components/u-button/props.js
*/
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,494 @@
<template>
<!-- #ifndef APP-NVUE -->
<button
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
:form-type="formType"
:open-type="openType"
:app-parameter="appParameter"
:hover-stop-propagation="hoverStopPropagation"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:lang="lang"
:data-name="dataName"
:session-from="sessionFrom"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
@getphonenumber="getphonenumber"
@getuserinfo="getuserinfo"
@error="error"
@opensetting="opensetting"
@launchapp="launchapp"
:hover-class="!disabled && !loading ? 'u-button--active' : ''"
class="u-button u-reset-button"
:style="[baseColor, $u.addStyle(customStyle)]"
@tap="clickHandler"
:class="bemClass"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
:customStyle="{ marginRight: '2px' }"
></u-icon>
<slot>
<text
class="u-button__text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ text }}</text
>
</slot>
</template>
</button>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
class="u-button"
:hover-class="
!disabled && !loading && !color && (plain || type === 'info')
? 'u-button--active--plain'
: !disabled && !loading && !plain
? 'u-button--active'
: ''
"
@tap="clickHandler"
:class="bemClass"
:style="[baseColor, $u.addStyle(customStyle)]"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[nvueTextStyle]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
></u-icon>
<text
class="u-button__text"
:style="[
{
marginLeft: icon ? '2px' : 0,
},
nvueTextStyle,
]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ text }}</text
>
</template>
</view>
<!-- #endif -->
</template>
<script>
import button from "../../libs/mixin/button.js";
import openType from "../../libs/mixin/openType.js";
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
import props from "./props.js";
/**
* button 按钮
* @description Button 按钮
* @tutorial https://ijry.github.io/uview-plus/components/button.html
*
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
* @property {String} type 按钮的预置样式infoprimaryerrorwarningsuccess (默认 'info' )
* @property {String} size 按钮尺寸largenormalmini 默认 normal
* @property {String} shape 按钮形状circle两边为半圆square带圆角 默认 'square'
* @property {Boolean} plain 按钮是否镂空背景色透明 默认 false
* @property {Boolean} disabled 是否禁用 默认 false
* @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台 ios 上为雪花Android上为圆圈) 默认 false
* @property {String | Number} loadingText 加载中提示文字
* @property {String} loadingMode 加载状态图标类型 默认 'spinner'
* @property {String | Number} loadingSize 加载图标大小 默认 15
* @property {String} openType 开放能力具体请看uniapp稳定关于button组件部分说明
* @property {String} formType 用于 <form> 组件点击分别会触发 <form> 组件的 submit/reset 事件
* @property {String} appParameter 打开 APP APP 传递的参数open-type=launchApp时有效 只微信小程序QQ小程序有效
* @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态微信小程序有效默认 true
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文默认 en
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效默认false
* @property {String} dataName 额外传参参数用于小程序的data-xxx属性通过target.dataset.name获取
* @property {String | Number} throttleTime 节流一定时间内只能触发一次 默认 0 )
* @property {String | Number} hoverStartTime 按住后多久出现点击态单位毫秒 默认 0 )
* @property {String | Number} hoverStayTime 手指松开后点击态保留时间单位毫秒 默认 200 )
* @property {String | Number} text 按钮文字之所以通过props传入是因为slot传入的话nvue中无法控制文字的样式
* @property {String} icon 按钮图标
* @property {String} iconColor 按钮图标颜色
* @property {String} color 按钮颜色支持传入linear-gradient渐变色
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 非禁止并且非加载中才能点击
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息从返回参数的detail中获取到的值同uni.getUserInfo
* @event {Function} error 当使用开放能力时发生错误的回调
* @event {Function} opensetting 在打开授权设置页并关闭后回调
* @event {Function} launchapp 打开 APP 成功的回调
* @example <u-button>月落</u-button>
*/
export default {
name: "u-button",
// #ifdef MP
mixins: [mpMixin, mixin, button, openType, props],
// #endif
// #ifndef MP
mixins: [mpMixin, mixin, props],
// #endif
data() {
return {};
},
computed: {
// bem
bemClass() {
// this.bemcomputedmixin
if (!this.color) {
return this.bem(
"button",
["type", "shape", "size"],
["disabled", "plain", "hairline"]
);
} else {
// nvuecolortypetype
return this.bem(
"button",
["shape", "size"],
["disabled", "plain", "hairline"]
);
}
},
loadingColor() {
if (this.plain) {
// colorcolor使type
return this.color
? this.color
: uni.$u.config.color[`u-${this.type}`];
}
if (this.type === "info") {
return "#c9c9c9";
}
return "rgb(200, 200, 200)";
},
iconColorCom() {
// colorcolor使
// u-iconcolor
if (this.iconColor) return this.iconColor;
if (this.plain) {
return this.color ? this.color : this.type;
} else {
return this.type === "info" ? "#000000" : "#ffffff";
}
},
baseColor() {
let style = {};
if (this.color) {
// color
style.color = this.plain ? this.color : "white";
if (!this.plain) {
// 使
style["background-color"] = this.color;
}
if (this.color.indexOf("gradient") !== -1) {
// backgroundImage
// weexborderWidth
// weex西
style.borderTopWidth = 0;
style.borderRightWidth = 0;
style.borderBottomWidth = 0;
style.borderLeftWidth = 0;
if (!this.plain) {
style.backgroundImage = this.color;
}
} else {
//
style.borderColor = this.color;
style.borderWidth = "1px";
style.borderStyle = "solid";
}
}
return style;
},
// nvuetext
nvueTextStyle() {
let style = {};
// color
if (this.type === "info") {
style.color = "#323233";
}
if (this.color) {
style.color = this.plain ? this.color : "white";
}
style.fontSize = this.textSize + "px";
return style;
},
//
textSize() {
let fontSize = 14,
{ size } = this;
if (size === "large") fontSize = 16;
if (size === "normal") fontSize = 14;
if (size === "small") fontSize = 12;
if (size === "mini") fontSize = 10;
return fontSize;
},
},
emits: ['click', 'getphonenumber', 'getuserinfo',
'error', 'opensetting', 'launchapp'],
methods: {
clickHandler() {
//
if (!this.disabled && !this.loading) {
// this.throttle
uni.$u.throttle(() => {
this.$emit("click");
}, this.throttleTime);
}
},
// uniapp
getphonenumber(res) {
this.$emit("getphonenumber", res);
},
getuserinfo(res) {
this.$emit("getuserinfo", res);
},
error(res) {
this.$emit("error", res);
},
opensetting(res) {
this.$emit("opensetting", res);
},
launchapp(res) {
this.$emit("launchapp", res);
},
},
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
/* #ifndef APP-NVUE */
@import "./vue.scss";
/* #endif */
/* #ifdef APP-NVUE */
@import "./nvue.scss";
/* #endif */
$u-button-u-button-height: 40px !default;
$u-button-text-font-size: 15px !default;
$u-button-loading-text-font-size: 15px !default;
$u-button-loading-text-margin-left: 4px !default;
$u-button-large-width: 100% !default;
$u-button-large-height: 50px !default;
$u-button-normal-padding: 0 12px !default;
$u-button-large-padding: 0 15px !default;
$u-button-normal-font-size: 14px !default;
$u-button-small-min-width: 60px !default;
$u-button-small-height: 30px !default;
$u-button-small-padding: 0px 8px !default;
$u-button-mini-padding: 0px 8px !default;
$u-button-small-font-size: 12px !default;
$u-button-mini-height: 22px !default;
$u-button-mini-font-size: 10px !default;
$u-button-mini-min-width: 50px !default;
$u-button-disabled-opacity: 0.5 !default;
$u-button-info-color: #323233 !default;
$u-button-info-background-color: #fff !default;
$u-button-info-border-color: #ebedf0 !default;
$u-button-info-border-width: 1px !default;
$u-button-info-border-style: solid !default;
$u-button-success-color: #fff !default;
$u-button-success-background-color: $u-success !default;
$u-button-success-border-color: $u-button-success-background-color !default;
$u-button-success-border-width: 1px !default;
$u-button-success-border-style: solid !default;
$u-button-primary-color: #fff !default;
$u-button-primary-background-color: $u-primary !default;
$u-button-primary-border-color: $u-button-primary-background-color !default;
$u-button-primary-border-width: 1px !default;
$u-button-primary-border-style: solid !default;
$u-button-error-color: #fff !default;
$u-button-error-background-color: $u-error !default;
$u-button-error-border-color: $u-button-error-background-color !default;
$u-button-error-border-width: 1px !default;
$u-button-error-border-style: solid !default;
$u-button-warning-color: #fff !default;
$u-button-warning-background-color: $u-warning !default;
$u-button-warning-border-color: $u-button-warning-background-color !default;
$u-button-warning-border-width: 1px !default;
$u-button-warning-border-style: solid !default;
$u-button-block-width: 100% !default;
$u-button-circle-border-top-right-radius: 100px !default;
$u-button-circle-border-top-left-radius: 100px !default;
$u-button-circle-border-bottom-left-radius: 100px !default;
$u-button-circle-border-bottom-right-radius: 100px !default;
$u-button-square-border-top-right-radius: 3px !default;
$u-button-square-border-top-left-radius: 3px !default;
$u-button-square-border-bottom-left-radius: 3px !default;
$u-button-square-border-bottom-right-radius: 3px !default;
$u-button-icon-min-width: 1em !default;
$u-button-plain-background-color: #fff !default;
$u-button-hairline-border-width: 0.5px !default;
.u-button {
height: $u-button-u-button-height;
position: relative;
align-items: center;
justify-content: center;
@include flex;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
flex-direction: row;
&__text {
font-size: $u-button-text-font-size;
}
&__loading-text {
font-size: $u-button-loading-text-font-size;
margin-left: $u-button-loading-text-margin-left;
}
&--large {
/* #ifndef APP-NVUE */
width: $u-button-large-width;
/* #endif */
height: $u-button-large-height;
padding: $u-button-large-padding;
}
&--normal {
padding: $u-button-normal-padding;
font-size: $u-button-normal-font-size;
}
&--small {
/* #ifndef APP-NVUE */
min-width: $u-button-small-min-width;
/* #endif */
height: $u-button-small-height;
padding: $u-button-small-padding;
font-size: $u-button-small-font-size;
}
&--mini {
height: $u-button-mini-height;
font-size: $u-button-mini-font-size;
/* #ifndef APP-NVUE */
min-width: $u-button-mini-min-width;
/* #endif */
padding: $u-button-mini-padding;
}
&--disabled {
opacity: $u-button-disabled-opacity;
}
&--info {
color: $u-button-info-color;
background-color: $u-button-info-background-color;
border-color: $u-button-info-border-color;
border-width: $u-button-info-border-width;
border-style: $u-button-info-border-style;
}
&--success {
color: $u-button-success-color;
background-color: $u-button-success-background-color;
border-color: $u-button-success-border-color;
border-width: $u-button-success-border-width;
border-style: $u-button-success-border-style;
}
&--primary {
color: $u-button-primary-color;
background-color: $u-button-primary-background-color;
border-color: $u-button-primary-border-color;
border-width: $u-button-primary-border-width;
border-style: $u-button-primary-border-style;
}
&--error {
color: $u-button-error-color;
background-color: $u-button-error-background-color;
border-color: $u-button-error-border-color;
border-width: $u-button-error-border-width;
border-style: $u-button-error-border-style;
}
&--warning {
color: $u-button-warning-color;
background-color: $u-button-warning-background-color;
border-color: $u-button-warning-border-color;
border-width: $u-button-warning-border-width;
border-style: $u-button-warning-border-style;
}
&--block {
@include flex;
width: $u-button-block-width;
}
&--circle {
border-top-right-radius: $u-button-circle-border-top-right-radius;
border-top-left-radius: $u-button-circle-border-top-left-radius;
border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
}
&--square {
border-bottom-left-radius: $u-button-square-border-top-right-radius;
border-bottom-right-radius: $u-button-square-border-top-left-radius;
border-top-left-radius: $u-button-square-border-bottom-left-radius;
border-top-right-radius: $u-button-square-border-bottom-right-radius;
}
&__icon {
/* #ifndef APP-NVUE */
min-width: $u-button-icon-min-width;
line-height: inherit !important;
vertical-align: top;
/* #endif */
}
&--plain {
background-color: $u-button-plain-background-color;
}
&--hairline {
border-width: $u-button-hairline-border-width !important;
}
}
</style>

@ -0,0 +1,80 @@
// 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-error;
.u-button {
width: 100%;
&__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;
}
}
}

@ -0,0 +1,99 @@
<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"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
</view>
</view>
</template>
<script>
export default {
name: 'u-calendar-header',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
props: {
//
title: {
type: String,
default: ''
},
//
subtitle: {
type: String,
default: ''
},
//
showTitle: {
type: Boolean,
default: true
},
//
showSubtitle: {
type: Boolean,
default: true
},
},
data() {
return {
}
},
methods: {
name() {
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-header {
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>

@ -0,0 +1,583 @@
<template>
<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}{{ item.month }}</text>
<view class="u-calendar-month__days">
<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
</view>
<view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
:class="[item1.selected && 'u-calendar-month__days__day__select--selected']">
<view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
<text class="u-calendar-month__days__day__select__info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']"
:style="[textStyle(item1)]">{{ item1.day }}</text>
<text v-if="getBottomInfo(index, index1, item1)"
class="u-calendar-month__days__day__select__buttom-info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']"
:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
<text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
// nvue
const dom = uni.requireNativePlugin('dom')
// #endif
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
import defprops from '../../libs/config/props';
// import dayjs from '../../libs/util/dayjs.js';
import dayjs from 'dayjs'
export default {
name: 'u-calendar-month',
mixins: [mpMixin, mixin],
props: {
//
showMark: {
type: Boolean,
default: true
},
//
color: {
type: String,
default: '#3c9cff'
},
//
months: {
type: Array,
default: () => []
},
//
mode: {
type: String,
default: 'single'
},
//
rowHeight: {
type: [String, Number],
default: 58
},
// mode=multiple
maxCount: {
type: [String, Number],
default: Infinity
},
// mode=range
startText: {
type: String,
default: '开始'
},
// mode=range
endText: {
type: String,
default: '结束'
},
// modemultiplerange
defaultDate: {
type: [Array, String, Date],
default: null
},
//
minDate: {
type: [String, Number],
default: 0
},
//
maxDate: {
type: [String, Number],
default: 0
},
// maxDate
maxMonth: {
type: [String, Number],
default: 2
},
//
readonly: {
type: Boolean,
default: defprops.calendar.readonly
},
// mode = range
maxRange: {
type: [Number, String],
default: Infinity
},
// mode = range
rangePrompt: {
type: String,
default: ''
},
// mode = range
showRangePrompt: {
type: Boolean,
default: true
},
// mode = range
allowSameDay: {
type: Boolean,
default: false
}
},
data() {
return {
//
width: 0,
// item
item: {},
selected: []
}
},
watch: {
selectedChange: {
immediate: true,
handler(n) {
this.setDefaultDate()
}
}
},
computed: {
//
selectedChange() {
return [this.minDate, this.maxDate, this.defaultDate]
},
dayStyle(index1, index2, item) {
return (index1, index2, item) => {
const style = {}
let week = item.week
// 2
const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
//
// #ifdef APP-NVUE
style.width = uni.$u.addUnit(dayWidth)
// #endif
style.height = uni.$u.addUnit(this.rowHeight)
if (index2 === 0) {
// 0item
week = (week === 0 ? 7 : week) - 1
style.marginLeft = uni.$u.addUnit(week * dayWidth)
}
if (this.mode === 'range') {
// DCloudiOSbug
style.paddingLeft = 0
style.paddingRight = 0
style.paddingBottom = 0
style.paddingTop = 0
}
return style
}
},
daySelectStyle() {
return (index1, index2, item) => {
let date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
// dateselected0使dateSameincludes
if (this.selected.some(item => this.dateSame(item, date))) {
style.backgroundColor = this.color
}
if (this.mode === 'single') {
if (date === this.selected[0]) {
// nvue
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
} else if (this.mode === 'range') {
if (this.selected.length >= 2) {
const len = this.selected.length - 1
//
if (this.dateSame(date, this.selected[0])) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
//
if (this.dateSame(date, this.selected[len])) {
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90]
// mark
style.opacity = 0.7
}
} else if (this.selected.length === 1) {
// DCloudiOSbug
// nvueiOSuni-appbug
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
} else {
if (this.selected.some(item => this.dateSame(item, date))) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
}
return style
}
},
//
textStyle() {
return (item) => {
const date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
//
if (this.selected.some(item => this.dateSame(item, date))) {
style.color = '#ffffff'
}
if (this.mode === 'range') {
const len = this.selected.length - 1
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.color = this.color
}
}
return style
}
},
//
getBottomInfo() {
return (index1, index2, item) => {
const date = dayjs(item.date).format("YYYY-MM-DD")
const bottomInfo = item.bottomInfo
// 0
if (this.mode === 'range' && this.selected.length > 0) {
if (this.selected.length === 1) {
//
if (this.dateSame(date, this.selected[0])) return this.startText
else return bottomInfo
} else {
const len = this.selected.length - 1
// 2
if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
len === 1) {
// 2item
return `${this.startText}/${this.endText}`
} else if (this.dateSame(date, this.selected[0])) {
return this.startText
} else if (this.dateSame(date, this.selected[len])) {
return this.endText
} else {
return bottomInfo
}
}
} else {
return bottomInfo
}
}
}
},
mounted() {
this.init()
},
methods: {
init() {
//
this.$emit('monthSelected', this.selected)
this.$nextTick(() => {
//
// nvue$nextTick100%
uni.$u.sleep(10).then(() => {
this.getWrapperWidth()
this.getMonthRect()
})
})
},
//
dateSame(date1, date2) {
return dayjs(date1).isSame(dayjs(date2))
},
// nvuecssitem
getWrapperWidth() {
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
this.width = res.size.width
})
// #endif
// #ifndef APP-NVUE
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
this.width = size.width
})
// #endif
},
getMonthRect() {
// scroll-view
const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
`u-calendar-month-${index}`))
//
Promise.all(promiseAllArr).then(
sizes => {
let height = 1
const topArr = []
for (let i = 0; i < this.months.length; i++) {
// monthsscroll-view
topArr[i] = height
height += sizes[i].height
}
// this.months[i].top()monthtop使
this.$emit('updateMonthTop', topArr)
})
},
//
getMonthRectByPromise(el) {
// #ifndef APP-NVUE
// $uGetRectuViewhttps://ijry.github.io/uview-plus/js/getRect.html
// this.$uGetRectuni.$u.getRect
return new Promise(resolve => {
this.$uGetRect(`.${el}`).then(size => {
resolve(size)
})
})
// #endif
// #ifdef APP-NVUE
// nvue使dom
// promise使then
return new Promise(resolve => {
dom.getComponentRect(this.$refs[el][0], res => {
resolve(res.size)
})
})
// #endif
},
//
clickHandler(index1, index2, item) {
if (this.readonly) {
return;
}
this.item = item
const date = dayjs(item.date).format("YYYY-MM-DD")
if (item.disabled) return
//
let selected = uni.$u.deepClone(this.selected)
if (this.mode === 'single') {
//
selected = [date]
} else if (this.mode === 'multiple') {
if (selected.some(item => this.dateSame(item, date))) {
//
const itemIndex = selected.findIndex(item => item === date)
selected.splice(itemIndex, 1)
} else {
//
if (selected.length < this.maxCount) selected.push(date)
}
} else {
//
if (selected.length === 0 || selected.length >= 2) {
// 02
selected = [date]
} else if (selected.length === 1) {
//
const existsDate = selected[0]
//
if (dayjs(date).isBefore(existsDate)) {
selected = [date]
} else if (dayjs(date).isAfter(existsDate)) {
//
if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
if(this.rangePrompt) {
uni.$u.toast(this.rangePrompt)
} else {
uni.$u.toast(`选择天数不能超过 ${this.maxRange}`)
}
return
}
//
selected.push(date)
const startDate = selected[0]
const endDate = selected[1]
const arr = []
let i = 0
do {
//
arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
i++
//
} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
// computedarr
arr.push(endDate)
selected = arr
} else {
//
if (selected[0] === date && !this.allowSameDay) return
selected.push(date)
}
}
}
this.setSelected(selected)
},
//
setDefaultDate() {
if (!this.defaultDate) {
//
const selected = [dayjs().format("YYYY-MM-DD")]
return this.setSelected(selected, false)
}
let defaultDate = []
const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
if (this.mode === 'single') {
// Date
if (!uni.$u.test.array(this.defaultDate)) {
defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
} else {
defaultDate = [this.defaultDate[0]]
}
} else {
//
if (!uni.$u.test.array(this.defaultDate)) return
defaultDate = this.defaultDate
}
//
defaultDate = defaultDate.filter(item => {
return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
maxDate).add(1, 'day'))
})
this.setSelected(defaultDate, false)
},
setSelected(selected, event = true) {
this.selected = selected
event && this.$emit('monthSelected', this.selected)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-month-wrapper {
margin-top: 4px;
}
.u-calendar-month {
&__title {
font-size: 14px;
line-height: 42px;
height: 42px;
color: $u-main-color;
text-align: center;
font-weight: bold;
}
&__days {
position: relative;
@include flex;
flex-wrap: wrap;
&__month-mark-wrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
@include flex;
justify-content: center;
align-items: center;
&__text {
font-size: 155px;
color: rgba(231, 232, 234, 0.83);
}
}
&__day {
@include flex;
padding: 2px;
/* #ifndef APP-NVUE */
// vue使cssjs
width: calc(100% / 7);
box-sizing: border-box;
/* #endif */
&__select {
flex: 1;
@include flex;
align-items: center;
justify-content: center;
position: relative;
&__dot {
width: 7px;
height: 7px;
border-radius: 100px;
background-color: $u-error;
position: absolute;
top: 12px;
right: 7px;
}
&__buttom-info {
color: $u-content-color;
text-align: center;
position: absolute;
bottom: 5px;
font-size: 10px;
text-align: center;
left: 0;
right: 0;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&__info {
text-align: center;
font-size: 16px;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&--selected {
background-color: $u-primary;
@include flex;
justify-content: center;
align-items: center;
flex: 1;
border-radius: 3px;
}
&--range-selected {
opacity: 0.3;
border-radius: 0;
}
&--range-start-selected {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&--range-end-selected {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
}
}
</style>

@ -0,0 +1,145 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,386 @@
<template>
<u-popup
:show="show"
mode="bottom"
closeable
@close="close"
:round="round"
:closeOnClickOverlay="closeOnClickOverlay"
>
<view class="u-calendar">
<uHeader
:title="title"
:subtitle="subtitle"
:showSubtitle="showSubtitle"
:showTitle="showTitle"
></uHeader>
<scroll-view
:style="{
height: $u.addUnit(listHeight)
}"
scroll-y
@scroll="onScroll"
:scroll-top="scrollTop"
:scrollIntoView="scrollIntoView"
>
<uMonth
:color="color"
:rowHeight="rowHeight"
:showMark="showMark"
:months="months"
:mode="mode"
:maxCount="maxCount"
:startText="startText"
:endText="endText"
:defaultDate="defaultDate"
:minDate="innerMinDate"
:maxDate="innerMaxDate"
:maxMonth="monthNum"
:readonly="readonly"
:maxRange="maxRange"
:rangePrompt="rangePrompt"
:showRangePrompt="showRangePrompt"
:allowSameDay="allowSameDay"
ref="month"
@monthSelected="monthSelected"
@updateMonthTop="updateMonthTop"
></uMonth>
</scroll-view>
<slot name="footer" v-if="showConfirm">
<view class="u-calendar__confirm">
<u-button
shape="circle"
:text="
buttonDisabled ? confirmDisabledText : confirmText
"
:color="color"
@click="confirm"
:disabled="buttonDisabled"
></u-button>
</view>
</slot>
</view>
</u-popup>
</template>
<script>
import uHeader from './header.vue'
import uMonth from './month.vue'
import props from './props.js'
import util from './util.js'
// import dayjs from '../../libs/util/dayjs.min.js'
import dayjs from 'dayjs'
import Calendar from '../../libs/util/calendar.js'
import mpMixin from '../../libs/mixin/mpMixin.js'
import mixin from '../../libs/mixin/mixin.js'
/**
* Calendar 日历
* @description 此组件用于单个选择日期范围选择日期等日历被包裹在底部弹起的容器中.
* @tutorial https://ijry.github.io/uview-plus/components/calendar.html
*
* @property {String} title 标题内容 (默认 日期选择 )
* @property {Boolean} showTitle 是否显示标题 (默认 true )
* @property {Boolean} showSubtitle 是否显示副标题 (默认 true )
* @property {String} mode 日期类型选择 single-选择单个日期multiple-可以选择多个日期range-选择日期范围 默认 'single' )
* @property {String} startText mode=range时第一个日期底部的提示文字 (默认 '开始' )
* @property {String} endText mode=range时最后一个日期底部的提示文字 (默认 '结束' )
* @property {Array} customList 自定义列表
* @property {String} color 主题色对底部按钮和选中日期有效 (默认 #3c9cff' )
* @property {String | Number} minDate 最小的可选日期 (默认 0 )
* @property {String | Number} maxDate 最大可选日期 (默认 0 )
* @property {Array | String| Date} defaultDate 默认选中的日期mode为multiple或range是必须为数组格式
* @property {String | Number} maxCount mode=multiple时最多可选多少个日期 (默认 Number.MAX_SAFE_INTEGER )
* @property {String | Number} rowHeight 日期行高 (默认 56 )
* @property {Function} formatter 日期格式化函数
* @property {Boolean} showLunar 是否显示农历 (默认 false )
* @property {Boolean} showMark 是否显示月份背景色 (默认 true )
* @property {String} confirmText 确定按钮的文字 (默认 '确定' )
* @property {String} confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
* @property {Boolean} show 是否显示日历弹窗 (默认 false )
* @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
* @property {Boolean} readonly 是否为只读状态只读状态下禁止选择日期 (默认 false )
* @property {String | Number} maxRange 日期区间最多可选天数默认无限制mode = range时有效
* @property {String} rangePrompt 范围选择超过最多可选天数时的提示文案mode = range时有效
* @property {Boolean} showRangePrompt 范围选择超过最多可选天数时是否展示提示文案mode = range时有效 (默认 true )
* @property {Boolean} allowSameDay 是否允许日期范围的起止时间为同一天mode = range时有效 (默认 false )
* @property {Number|String} round 圆角值默认无圆角 (默认 0 )
* @property {Number|String} monthNum 最多展示的月份数量 (默认 3 )
*
* @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
* @event {Function()} close 日历关闭时触发 可定义页面关闭时的回调事件
* @example <u-calendar :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm">
</u-calendar>
* */
export default {
name: 'u-calendar',
mixins: [mpMixin, mixin, props],
components: {
uHeader,
uMonth
},
data() {
return {
//
months: [],
// index
monthIndex: 0,
//
listHeight: 0,
// month
selected: [],
scrollIntoView: '',
scrollTop:0,
//
innerFormatter: (value) => value
}
},
watch: {
selectedChange: {
immediate: true,
handler(n) {
this.setMonth()
}
},
//
show: {
immediate: true,
handler(n) {
this.setMonth()
}
}
},
computed: {
// maxDateminDate(2021-10-10)()dayjs
innerMaxDate() {
return uni.$u.test.number(this.maxDate)
? Number(this.maxDate)
: this.maxDate
},
innerMinDate() {
return uni.$u.test.number(this.minDate)
? Number(this.minDate)
: this.minDate
},
//
selectedChange() {
return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
},
subtitle() {
// this.months
if (this.months.length) {
return `${this.months[this.monthIndex].year}${
this.months[this.monthIndex].month
}`
} else {
return ''
}
},
buttonDisabled() {
// range1disabled
if (this.mode === 'range') {
if (this.selected.length <= 1) {
return true
} else {
return false
}
} else {
return false
}
}
},
mounted() {
this.start = Date.now()
this.init()
},
methods: {
// propsref
setFormatter(e) {
this.innerFormatter = e
},
// month
monthSelected(e) {
this.selected = e
if (!this.showConfirm) {
// 2
if (
this.mode === 'multiple' ||
this.mode === 'single' ||
(this.mode === 'range' && this.selected.length >= 2)
) {
this.$emit('confirm', this.selected)
}
}
},
init() {
// maxDate
if (
this.innerMaxDate &&
new Date(this.innerMaxDate).getTime() <= Date.now()
) {
return uni.$u.error('maxDate不能小于当前时间')
}
//
this.listHeight = this.rowHeight * 5 + 30
this.setMonth()
},
close() {
this.$emit('close')
},
//
confirm() {
if (!this.buttonDisabled) {
this.$emit('confirm', this.selected)
}
},
//
getMonths(minDate, maxDate) {
const minYear = dayjs(minDate).year()
const minMonth = dayjs(minDate).month() + 1
const maxYear = dayjs(maxDate).year()
const maxMonth = dayjs(maxDate).month() + 1
return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
},
//
setMonth() {
//
const minDate = this.innerMinDate || dayjs().valueOf()
// 3
const maxDate =
this.innerMaxDate ||
dayjs(minDate)
.add(this.monthNum - 1, 'month')
.valueOf()
//
const months = uni.$u.range(
1,
this.monthNum,
this.getMonths(minDate, maxDate)
)
//
this.months = []
for (let i = 0; i < months; i++) {
this.months.push({
date: new Array(
dayjs(minDate).add(i, 'month').daysInMonth()
)
.fill(1)
.map((item, index) => {
// 1-31
let day = index + 1
// 0-60
const week = dayjs(minDate)
.add(i, 'month')
.date(day)
.day()
const date = dayjs(minDate)
.add(i, 'month')
.date(day)
.format('YYYY-MM-DD')
let bottomInfo = ''
if (this.showLunar) {
//
const lunar = Calendar.solar2lunar(
dayjs(date).year(),
dayjs(date).month() + 1,
dayjs(date).date()
)
bottomInfo = lunar.IDayCn
}
let config = {
day,
week,
// disabled
disabled:
dayjs(date).isBefore(
dayjs(minDate).format('YYYY-MM-DD')
) ||
dayjs(date).isAfter(
dayjs(maxDate).format('YYYY-MM-DD')
),
// formatter
date: new Date(date),
bottomInfo,
dot: false,
month:
dayjs(minDate).add(i, 'month').month() + 1
}
const formatter =
this.formatter || this.innerFormatter
return formatter(config)
}),
//
month: dayjs(minDate).add(i, 'month').month() + 1,
//
year: dayjs(minDate).add(i, 'month').year()
})
}
},
//
scrollIntoDefaultMonth(selected) {
//
const _index = this.months.findIndex(({
year,
month
}) => {
month = uni.$u.padZero(month)
return `${year}-${month}` === selected
})
if (_index !== -1) {
// #ifndef MP-WEIXIN
this.$nextTick(() => {
this.scrollIntoView = `month-${_index}`
})
// #endif
// #ifdef MP-WEIXIN
this.scrollTop = this.months[_index].top || 0;
// #endif
}
},
// scroll-view
onScroll(event) {
// 0scroll-view
const scrollTop = Math.max(0, event.detail.scrollTop)
//
for (let i = 0; i < this.months.length; i++) {
if (scrollTop >= (this.months[i].top || this.listHeight)) {
this.monthIndex = i
}
}
},
// top
updateMonthTop(topArr = []) {
// toponScroll
topArr.map((item, index) => {
this.months[index].top = item
})
//
if (!this.defaultDate) {
//
const selected = dayjs().format("YYYY-MM")
this.scrollIntoDefaultMonth(selected)
return
}
let selected = dayjs().format("YYYY-MM");
// Date
if (!uni.$u.test.array(this.defaultDate)) {
selected = dayjs(this.defaultDate).format("YYYY-MM")
} else {
selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
}
this.scrollIntoDefaultMonth(selected)
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-calendar {
&__confirm {
padding: 7px 18px;
}
}
</style>

@ -0,0 +1,86 @@
import dayjs from 'dayjs'
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
}
})
)
}
}
}
}

@ -0,0 +1,15 @@
import defprops from '../../libs/config/props';
export default {
props: {
// 是否打乱键盘按键的顺序
random: {
type: Boolean,
default: false
},
// 输入一个中文后,是否自动切换到英文
autoChange: {
type: Boolean,
default: false
}
}
}

@ -0,0 +1,313 @@
<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"
>
<u-icon
size="28"
name="backspace"
color="#303133"
></u-icon>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* keyboard 键盘组件
* @description 此为uView自定义的键盘面板内含了数字键盘车牌号键身份证号键盘3种模式都有可以打乱按键顺序的选项
* @tutorial https://uviewui.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-keyboard",
mixins: [mpMixin, mixin, props],
data() {
return {
// abc=truebac=false
abc: false
};
},
computed: {
areaList() {
let data = [
'京',
'沪',
'粤',
'津',
'冀',
'豫',
'云',
'辽',
'黑',
'湘',
'皖',
'鲁',
'苏',
'浙',
'赣',
'鄂',
'桂',
'甘',
'晋',
'陕',
'蒙',
'吉',
'闽',
'贵',
'渝',
'川',
'青',
'琼',
'宁',
'挂',
'藏',
'港',
'澳',
'新',
'使',
'学'
];
let tmp = [];
//
if (this.random) data = uni.$u.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 = uni.$u.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;
}
},
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) uni.$u.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>
@import "../../libs/css/components.scss";
$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>

@ -0,0 +1,15 @@
import defprops from '../../libs/config/props';
export default {
props: {
// 分组标题
title: {
type: String,
default: defprops.cellGroup.title
},
// 是否显示外边框
border: {
type: Boolean,
default: defprops.cellGroup.border
}
}
}

@ -0,0 +1,63 @@
<template>
<view :style="[$u.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.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* cellGroup 单元格
* @description cell单元格一般用于一组列表的情况比如个人中心页设置页等
* @tutorial https://uviewui.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],
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$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>

@ -0,0 +1,111 @@
import defprops from '../../libs/config/props';
export default {
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 uni.$u.props.cell.iconStyle
}
},
// 右侧箭头图标的样式
rightIconStyle: {
type: [Object, String],
default: () => {
return uni.$u.props.cell.rightIconStyle
}
},
// 标题的样式
titleStyle: {
type: [Object, String],
default: () => {
return uni.$u.props.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
}
}
}

@ -0,0 +1,234 @@
<template>
<view class="u-cell" :class="[customClass]" :style="[$u.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">
<slot name="icon">
<u-icon v-if="icon" :name="icon"
:custom-style="iconStyle"
:size="size === 'large' ? 22 : 18"></u-icon>
</slot>
</view>
<view class="u-cell__title">
<slot name="title">
<text v-if="title" class="u-cell__title-text" :style="[titleTextStyle]"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
</slot>
<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="!$u.test.empty(value)">{{ value }}</text>
</slot>
<view class="u-cell__right-icon-wrap"
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
<slot name="right-icon">
<u-icon v-if="isLink" :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
:size="size === 'large' ? 18 : 16"></u-icon>
</slot>
</view>
</view>
<u-line v-if="border"></u-line>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* cell 单元格
* @description cell单元格一般用于一组列表的情况比如个人中心页设置页等
* @tutorial https://uviewui.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 右侧箭头的方向可选值为leftupdown
* @property {Object | String} rightIconStyle 右侧箭头图标的样式
* @property {Object | String} titleStyle 标题的样式
* @property {Object | String} iconStyle 左侧图标样式
* @property {String} size 单位元的大小可选值为 largenormalmini
* @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 uni.$u.addStyle(this.titleStyle)
}
},
emits: ['click'],
methods: {
// cell
clickHandler(e) {
if (this.disabled) return
this.$emit('click', {
name: this.name
})
// url(propsmixin)
this.openPage()
//
this.stop && this.preventEvent(e)
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-cell-padding: 10px 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;
&-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;
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;
}
}
&--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>

@ -0,0 +1,92 @@
import defprops from '../../libs/config/props';
export default {
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
}
}
}

@ -0,0 +1,133 @@
<template>
<view
class="u-checkbox-group"
:class="bemClass"
>
<slot></slot>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* 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: {
// computedu-checkbox
// parentDatawatch(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.bemcomputedmixin
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)
}
})
//
this.$emit('change', values)
// v-model
// #ifdef VUE3
this.$emit("update:modelValue", values);
// #endif
// #ifdef VUE2
this.$emit("input", values);
// #endif
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-checkbox-group {
&--row {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-flow: row wrap;
}
&--column {
@include flex(column);
}
}
</style>

@ -0,0 +1,70 @@
import defprops from '../../libs/config/props';
export default {
props: {
// checkbox的名称
name: {
type: [String, Number, Boolean],
default: defprops.checkbox.name
},
// 形状,square为方形,circle为圆型
shape: {
type: String,
default: defprops.checkbox.shape
},
// 整体的大小
size: {
type: [String, Number],
default: defprops.checkbox.size
},
// 是否默认选中
checked: {
type: Boolean,
default: defprops.checkbox.checked
},
// 是否禁用
disabled: {
type: [String, Boolean],
default: defprops.checkbox.disabled
},
// 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
activeColor: {
type: String,
default: defprops.checkbox.activeColor
},
// 未选中的颜色
inactiveColor: {
type: String,
default: defprops.checkbox.inactiveColor
},
// 图标的大小,单位px
iconSize: {
type: [String, Number],
default: defprops.checkbox.iconSize
},
// 图标颜色
iconColor: {
type: String,
default: defprops.checkbox.iconColor
},
// label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
label: {
type: [String, Number],
default: defprops.checkbox.label
},
// label的字体大小,px单位
labelSize: {
type: [String, Number],
default: defprops.checkbox.labelSize
},
// label的颜色
labelColor: {
type: String,
default: defprops.checkbox.labelColor
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: [String, Boolean],
default: defprops.checkbox.labelDisabled
}
}
}

@ -0,0 +1,359 @@
<template>
<view
class="u-checkbox"
:style="[checkboxStyle]"
@tap.stop="wrapperClickHandler"
:class="[`u-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']"
>
<view
class="u-checkbox__icon-wrap"
@tap.stop="iconClickHandler"
:class="iconClasses"
:style="[iconWrapStyle]"
>
<slot name="icon">
<u-icon
class="u-checkbox__icon-wrap__icon"
name="checkbox-mark"
:size="elIconSize"
:color="elIconColor"
/>
</slot>
</view>
<text
@tap.stop="labelClickHandler"
:style="{
color: elDisabled ? elInactiveColor : elLabelColor,
fontSize: elLabelSize,
lineHeight: elLabelSize
}"
>{{label}}</text>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* checkbox 复选框
* @description 复选框组件一般用于需要多个选择的场景该组件功能完整使用方便
* @tutorial https://uviewui.com/components/checkbox.html
* @property {String | Number | Boolean} name checkbox组件的标示符
* @property {String} shape 形状square为方形circle为圆型
* @property {String | Number} size 整体的大小
* @property {Boolean} checked 是否默认选中
* @property {String | Boolean} disabled 是否禁用
* @property {String} activeColor 选中状态下的颜色如设置此值将会覆盖parent的activeColor值
* @property {String} inactiveColor 未选中的颜色
* @property {String | Number} iconSize 图标的大小单位px
* @property {String} iconColor 图标颜色
* @property {String | Number} label label提示文字因为nvue下直接slot进来的文字由于特殊的结构无法修改样式
* @property {String} labelColor label的颜色
* @property {String | Number} labelSize label的字体大小px单位
* @property {String | Boolean} labelDisabled 是否禁止点击提示语选中复选框
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} change 任一个checkbox状态发生变化时触发回调为一个对象
* @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
*/
export default {
name: "u-checkbox",
mixins: [mpMixin, mixin, props],
data() {
return {
isChecked: false,
// computed使this.parent.shape
// 使
parentData: {
iconSize: 12,
labelDisabled: null,
disabled: null,
shape: 'square',
activeColor: null,
inactiveColor: null,
size: 18,
// #ifdef VUE2
value: null,
// #endif
// #ifdef VUE3
modelValue: null,
// #endif
iconColor: null,
placement: 'row',
borderBottom: false,
iconPlacement: 'left'
}
}
},
computed: {
// u-raios-group
elDisabled() {
return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
},
// label
elLabelDisabled() {
return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
false;
},
// size21px
elSize() {
return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
},
// 12px
elIconSize() {
return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
},
//
elActiveColor() {
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
},
//
elInactiveColor() {
return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
'#c8c9cc');
},
// label
elLabelColor() {
return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
},
//
elShape() {
return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
},
// label
elLabelSize() {
return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
'15'))
},
elIconColor() {
const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
'#ffffff');
//
if (this.elDisabled) {
// disabledcheckboxelInactiveColor
return this.isChecked ? this.elInactiveColor : 'transparent'
} else {
return this.isChecked ? iconColor : 'transparent'
}
},
iconClasses() {
let classes = []
//
classes.push('u-checkbox__icon-wrap--' + this.elShape)
if (this.elDisabled) {
classes.push('u-checkbox__icon-wrap--disabled')
}
if (this.isChecked && this.elDisabled) {
classes.push('u-checkbox__icon-wrap--disabled--checked')
}
// ","
// #ifdef MP-ALIPAY || MP-TOUTIAO
classes = classes.join(' ')
// #endif
return classes
},
iconWrapStyle() {
// checkbox
const style = {}
style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
style.width = uni.$u.addUnit(this.elSize)
style.height = uni.$u.addUnit(this.elSize)
//
if (this.parentData.iconPlacement === 'right') {
style.marginRight = 0
}
return style
},
checkboxStyle() {
const style = {}
if (this.parentData.borderBottom && this.parentData.placement === 'row') {
uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-checkbox-group的placement设置为column才有效')
}
//
if (this.parentData.borderBottom && this.parentData.placement === 'column') {
style.paddingBottom = '8px'
}
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
mounted() {
this.init()
},
methods: {
init() {
// provide/inject使created
this.updateParentData()
if (!this.parent) {
uni.$u.error('u-checkbox必须搭配u-checkbox-group组件使用')
}
// #ifdef VUE2
const value = this.parentData.value
// #endif
// #ifdef VUE3
const value = this.parentData.modelValue
// #endif
// u-checkbox-groupvaluearray
if (this.checked) {
this.isChecked = true
} else if (uni.$u.test.array(value)) {
// this.name
this.isChecked = value.some(item => {
return item === this.name
})
}
},
updateParentData() {
this.getParentData('u-checkbox-group')
},
//
wrapperClickHandler(e) {
this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
},
//
iconClickHandler(e) {
this.preventEvent(e)
//
if (!this.elDisabled) {
this.setRadioCheckedStatus()
}
},
// label
labelClickHandler(e) {
this.preventEvent(e)
// label
if (!this.elLabelDisabled && !this.elDisabled) {
this.setRadioCheckedStatus()
}
},
emitEvent() {
this.$emit('change', this.isChecked)
// u-form
this.$nextTick(() => {
uni.$u.formValidate(this, 'change')
})
},
//
// checkedtrueu-checkbox
// u-checkboxcheckedfalse()
setRadioCheckedStatus() {
//
this.isChecked = !this.isChecked
this.emitEvent()
typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
}
},
watch:{
checked(){
this.isChecked = this.checked
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-checkbox-icon-wrap-margin-right:6px !default;
$u-checkbox-icon-wrap-font-size:6px !default;
$u-checkbox-icon-wrap-border-width:1px !default;
$u-checkbox-icon-wrap-border-color:#c8c9cc !default;
$u-checkbox-icon-wrap-icon-line-height:0 !default;
$u-checkbox-icon-wrap-circle-border-radius:100% !default;
$u-checkbox-icon-wrap-square-border-radius:3px !default;
$u-checkbox-icon-wrap-checked-color:#fff !default;
$u-checkbox-icon-wrap-checked-background-color:red !default;
$u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
$u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
$u-checkbox-label-margin-left:5px !default;
$u-checkbox-label-margin-right:12px !default;
$u-checkbox-label-color:$u-content-color !default;
$u-checkbox-label-font-size:15px !default;
$u-checkbox-label-disabled-color:#c8c9cc !default;
.u-checkbox {
/* #ifndef APP-NVUE */
@include flex(row);
/* #endif */
overflow: hidden;
flex-direction: row;
align-items: center;
margin-bottom: 5px;
margin-top: 5px;
&-label--left {
flex-direction: row
}
&-label--right {
flex-direction: row-reverse;
justify-content: space-between
}
&__icon-wrap {
/* #ifndef APP-NVUE */
box-sizing: border-box;
// nvueborder-color
transition-property: border-color, background-color, color;
transition-duration: 0.2s;
/* #endif */
color: $u-content-color;
@include flex;
align-items: center;
justify-content: center;
color: transparent;
text-align: center;
margin-right: $u-checkbox-icon-wrap-margin-right;
font-size: $u-checkbox-icon-wrap-font-size;
border-width: $u-checkbox-icon-wrap-border-width;
border-color: $u-checkbox-icon-wrap-border-color;
border-style: solid;
/* #ifdef MP-TOUTIAO */
// 0
&__icon {
line-height: $u-checkbox-icon-wrap-icon-line-height;
}
/* #endif */
&--circle {
border-radius: $u-checkbox-icon-wrap-circle-border-radius;
}
&--square {
border-radius: $u-checkbox-icon-wrap-square-border-radius;
}
&--checked {
color: $u-checkbox-icon-wrap-checked-color;
background-color: $u-checkbox-icon-wrap-checked-background-color;
border-color: $u-checkbox-icon-wrap-checked-border-color;
}
&--disabled {
background-color: $u-checkbox-icon-wrap-disabled-background-color !important;
}
&--disabled--checked {
color: $u-checkbox-icon-wrap-disabled-checked-color !important;
}
}
&__label {
/* #ifndef APP-NVUE */
word-wrap: break-word;
/* #endif */
margin-left: $u-checkbox-label-margin-left;
margin-right: $u-checkbox-label-margin-right;
color: $u-checkbox-label-color;
font-size: $u-checkbox-label-font-size;
&--disabled {
color: $u-checkbox-label-disabled-color;
}
}
}
</style>

@ -0,0 +1,9 @@
import defprops from '../../libs/config/props';
export default {
props: {
percentage: {
type: [String, Number],
default: defprops.circleProgress.percentage
}
}
}

@ -0,0 +1,200 @@
<template>
<view class="u-circle-progress">
<view class="u-circle-progress__left">
<view
class="u-circle-progress__left__circle"
:style="[leftSyle]"
ref="left-circle"
>
</view>
</view>
<view
class="u-circle-progress__right"
>
<view
class="u-circle-progress__right__circle"
ref="right-circle"
:style="[rightSyle]"
>
</view>
</view>
<view class="u-circle-progress__circle">
</view>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation')
// #endif
/**
* CircleProgress 圆形进度条 TODO: 待完善
* @description 展示操作或任务的当前进度比如上传文件是一个圆形的进度环
* @tutorial https://ijry.github.io/uview-plus/components/circleProgress.html
* @property {String | Number} percentage 圆环进度百分比值为数值类型0-100 (默认 30 )
* @example
*/
export default {
name: 'u-circle-progress',
mixins: [mpMixin, mixin, props],
data() {
return {
leftBorderColor: 'rgb(200, 200, 200)',
rightBorderColor: 'rgb(200, 200, 200)',
}
},
computed: {
leftSyle() {
const style = {}
style.borderTopColor = this.leftBorderColor
style.borderRightColor = this.leftBorderColor
return style
},
rightSyle() {
const style = {}
style.borderLeftColor = this.rightBorderColor
style.borderBottomColor = this.rightBorderColor
return style
}
},
mounted() {
uni.$u.sleep().then(() => {
this.rightBorderColor = 'rgb(66, 185, 131)'
// this.init()
})
},
methods: {
init() {
animation.transition(this.$refs['right-circle'].ref, {
styles: {
transform: 'rotate(45deg)',
transformOrigin: 'center center'
},
}, () => {
this.rightBorderColor = 'rgb(66, 185, 131)'
// animation.transition(this.$refs['right-circle'].ref, {
// styles: {
// transform: 'rotate(225deg)',
// transformOrigin: 'center center'
// },
// duration: 3000,
// }, () => {
// animation.transition(this.$refs['left-circle'].ref, {
// styles: {
// transform: 'rotate(45deg)',
// transformOrigin: 'center center'
// },
// }, () => {
// this.leftBorderColor = 'rgb(66, 185, 131)'
// animation.transition(this.$refs['left-circle'].ref, {
// styles: {
// transform: 'rotate(225deg)',
// transformOrigin: 'center center'
// },
// duration: 1500,
// }, () => {
// })
// })
// })
})
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-circle-progress {
@include flex(row);
position: relative;
border-radius: 100px;
height: 100px;
width: 100px;
// transform: rotate(0deg);
// background-color: rgb(66, 185, 131);
background-color: rgb(200, 200, 200);
overflow: hidden;
justify-content: space-between;
&__circle {
border-radius: 100px;
height: 90px;
width: 90px;
transform: translate(-50%, -50%);
background-color: rgb(255, 255, 255);
left: 50px;
top: 50px;
position: absolute;
}
&__left {
position: absolute;
left: 0;
width: 50px;
height: 100px;
overflow: hidden;
box-sizing: border-box;
// background-color: rgb(66, 185, 131);
// background-color: rgb(200, 200, 200);
// transform-origin: left center;
&__circle {
box-sizing: border-box;
// background-color: red;
border-left-color: transparent;
border-bottom-color: transparent;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
// border-left-color: rgb(66, 185, 131);
// border-bottom-color: rgb(66, 185, 131);
border-top-color: rgb(66, 185, 131);
border-right-color: rgb(66, 185, 131);
border-width: 5px;
width: 100px;
height: 100px;
transform: rotate(225deg);
// border-radius: 100px;
}
}
&__right {
position: absolute;
right: 0;
width: 50px;
height: 100px;
overflow: hidden;
&__circle {
position: absolute;
right: 0;
box-sizing: border-box;
// background-color: red;
border-top-color: transparent;
border-right-color: transparent;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
// border-left-color: rgb(66, 185, 131);
// border-bottom-color: rgb(66, 185, 131);
border-left-color: rgb(200, 200, 200);
border-bottom-color: rgb(200, 200, 200);
border-width: 5px;
width: 100px;
height: 100px;
transform: rotate(45deg);
transform-origin: center center;
// border-radius: 100px;
}
}
}
</style>

@ -0,0 +1,80 @@
import defprops from '../../libs/config/props';
export default {
props: {
// 键盘弹起时,是否自动上推页面
adjustPosition: {
type: Boolean,
default: defprops.codeInput.adjustPosition
},
// 最大输入长度
maxlength: {
type: [String, Number],
default: defprops.codeInput.maxlength
},
// 是否用圆点填充
dot: {
type: Boolean,
default: defprops.codeInput.dot
},
// 显示模式,box-盒子模式,line-底部横线模式
mode: {
type: String,
default: defprops.codeInput.mode
},
// 是否细边框
hairline: {
type: Boolean,
default: defprops.codeInput.hairline
},
// 字符间的距离
space: {
type: [String, Number],
default: defprops.codeInput.space
},
// 预置值
value: {
type: [String, Number],
default: defprops.codeInput.value
},
// 是否自动获取焦点
focus: {
type: Boolean,
default: defprops.codeInput.focus
},
// 字体是否加粗
bold: {
type: Boolean,
default: defprops.codeInput.bold
},
// 字体颜色
color: {
type: String,
default: defprops.codeInput.color
},
// 字体大小
fontSize: {
type: [String, Number],
default: defprops.codeInput.fontSize
},
// 输入框的大小,宽等于高
size: {
type: [String, Number],
default: defprops.codeInput.size
},
// 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
disabledKeyboard: {
type: Boolean,
default: defprops.codeInput.disabledKeyboard
},
// 边框和线条颜色
borderColor: {
type: String,
default: defprops.codeInput.borderColor
},
// 是否禁止输入"."符号
disabledDot: {
type: Boolean,
default: defprops.codeInput.disabledDot
}
}
}

@ -0,0 +1,254 @@
<template>
<view class="u-code-input">
<view
class="u-code-input__item"
:style="[itemStyle(index)]"
v-for="(item, index) in codeLength"
:key="index"
>
<view
class="u-code-input__item__dot"
v-if="dot && codeArray.length > index"
></view>
<text
v-else
:style="{
fontSize: $u.addUnit(fontSize),
fontWeight: bold ? 'bold' : 'normal',
color: color
}"
>{{codeArray[index]}}</text>
<view
class="u-code-input__item__line"
v-if="mode === 'line'"
:style="[lineStyle]"
></view>
<!-- #ifndef APP-PLUS -->
<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="u-code-input__item__cursor"></view>
<!-- #endif -->
</view>
<input
:disabled="disabledKeyboard"
type="number"
:focus="focus"
:value="inputValue"
:maxlength="maxlength"
:adjustPosition="adjustPosition"
class="u-code-input__input"
@input="inputHandler"
:style="{
height: $u.addUnit(size)
}"
@focus="isFocus = true"
@blur="isFocus = false"
/>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* CodeInput 验证码输入
* @description 该组件一般用于验证用户短信验证码的场景也可以结合uView的键盘组件使用
* @tutorial https://ijry.github.io/uview-plus/components/codeInput.html
* @property {String | Number} maxlength 最大输入长度 默认 6
* @property {Boolean} dot 是否用圆点填充 默认 false
* @property {String} mode 显示模式box-盒子模式line-底部横线模式 默认 'box'
* @property {Boolean} hairline 是否细边框 默认 false
* @property {String | Number} space 字符间的距离 默认 10
* @property {String | Number} value 预置值
* @property {Boolean} focus 是否自动获取焦点 默认 false
* @property {Boolean} bold 字体和输入横线是否加粗 默认 false
* @property {String} color 字体颜色 默认 '#606266'
* @property {String | Number} fontSize 字体大小单位px 默认 18
* @property {String | Number} size 输入框的大小宽等于高 默认 35
* @property {Boolean} disabledKeyboard 是否隐藏原生键盘如果想用自定义键盘的话需设置此参数为true 默认 false
* @property {String} borderColor 边框和线条颜色 默认 '#c9cacc'
* @property {Boolean} disabledDot 是否禁止输入"."符号 默认 true
*
* @event {Function} change 输入内容发生改变时触发具体见上方说明 value当前输入的值
* @event {Function} finish 输入字符个数达maxlength值时触发见上方说明 value当前输入的值
* @example <u-code-input v-model="value4" :focus="true"></u-code-input>
*/
export default {
name: 'u-code-input',
mixins: [mpMixin, mixin, props],
data() {
return {
inputValue: '',
isFocus: this.focus
}
},
watch: {
value: {
immediate: true,
handler(val) {
//
this.inputValue = String(val).substring(0, this.maxlength)
}
},
},
computed: {
// v-for
codeLength() {
return new Array(Number(this.maxlength))
},
// item
itemStyle() {
return index => {
const addUnit = uni.$u.addUnit
const style = {
width: addUnit(this.size),
height: addUnit(this.size)
}
//
if (this.mode === 'box') {
// 0.5px
style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`
// 0
if (uni.$u.getPx(this.space) === 0) {
//
if (index === 0) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
if (index === this.codeLength.length - 1) {
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
//
if (index !== this.codeLength.length - 1) {
style.borderRight = 'none'
}
}
}
if (index !== this.codeLength.length - 1) {
// margin-right
style.marginRight = addUnit(this.space)
} else {
//
style.marginRight = 0
}
return style
}
},
// item
codeArray() {
return String(this.inputValue).split('')
},
// 线线
lineStyle() {
const style = {}
style.height = this.hairline ? '2px' : '4px'
style.width = uni.$u.addUnit(this.size)
// 线
style.backgroundColor = this.borderColor
return style
}
},
methods: {
//
inputHandler(e) {
const value = e.detail.value
this.inputValue = value
// .
if(this.disabledDot) {
this.$nextTick(() => {
this.inputValue = value.replace('.', '')
})
}
// maxlengthchangefinish
this.$emit('change', value)
// v-model
this.$emit('input', value)
//
if (String(value).length >= Number(this.maxlength)) {
this.$emit('finish', value)
}
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-code-input-cursor-width: 1px;
$u-code-input-cursor-height: 40%;
$u-code-input-cursor-animation-duration: 1s;
$u-code-input-cursor-animation-name: u-cursor-flicker;
.u-code-input {
@include flex;
position: relative;
overflow: hidden;
&__item {
@include flex;
justify-content: center;
align-items: center;
position: relative;
&__text {
font-size: 15px;
color: $u-content-color;
}
&__dot {
width: 7px;
height: 7px;
border-radius: 100px;
background-color: $u-content-color;
}
&__line {
position: absolute;
bottom: 0;
height: 4px;
border-radius: 100px;
width: 40px;
background-color: $u-content-color;
}
/* #ifndef APP-PLUS */
&__cursor {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: $u-code-input-cursor-width;
height: $u-code-input-cursor-height;
animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite;
}
/* #endif */
}
&__input {
// input
//
position: absolute;
left: -750rpx;
width: 1500rpx;
top: 0;
background-color: transparent;
text-align: left;
}
}
/* #ifndef APP-PLUS */
@keyframes u-cursor-flicker {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
/* #endif */
</style>

@ -0,0 +1,35 @@
import defprops from '../../libs/config/props';
export default {
props: {
// 倒计时总秒数
seconds: {
type: [String, Number],
default: defprops.code.seconds
},
// 尚未开始时提示
startText: {
type: String,
default: defprops.code.startText
},
// 正在倒计时中的提示
changeText: {
type: String,
default: defprops.code.changeText
},
// 倒计时结束时的提示
endText: {
type: String,
default: defprops.code.endText
},
// 是否在H5刷新或各端返回再进入时继续倒计时
keepRunning: {
type: Boolean,
default: defprops.code.keepRunning
},
// 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
uniqueKey: {
type: String,
default: defprops.code.uniqueKey
}
}
}

@ -0,0 +1,131 @@
<template>
<view class="u-code">
<!-- 此组件功能由js完成无需写html逻辑 -->
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* Code 验证码输入框
* @description 考虑到用户实际发送验证码的场景可能是一个按钮也可能是一段文字提示语各有不同所以本组件 不提供界面显示只提供提示语由用户将提示语嵌入到具体的场景
* @tutorial https://ijry.github.io/uview-plus/components/code.html
* @property {String | Number} seconds 倒计时所需的秒数默认 60
* @property {String} startText 开始前的提示语见官网说明默认 '获取验证码'
* @property {String} changeText 倒计时期间的提示语必须带有字母"x"见官网说明默认 'X秒重新获取'
* @property {String} endText 倒计结束的提示语见官网说明默认 '重新获取'
* @property {Boolean} keepRunning 是否在H5刷新或各端返回再进入时继续倒计时 默认false
* @property {String} uniqueKey 为了区分多个页面或者一个页面多个倒计时组件本地存储的继续倒计时变了
*
* @event {Function} change 倒计时期间每秒触发一次
* @event {Function} start 开始倒计时触发
* @event {Function} end 结束倒计时触发
* @example <u-code ref="uCode" @change="codeChange" seconds="20"></u-code>
*/
export default {
name: "u-code",
mixins: [mpMixin, mixin,props],
data() {
return {
secNum: this.seconds,
timer: null,
canGetCode: true, //
}
},
mounted() {
this.checkKeepRunning()
},
watch: {
seconds: {
immediate: true,
handler(n) {
this.secNum = n
}
}
},
methods: {
checkKeepRunning() {
// 退(H5)
let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))
if(!lastTimestamp) return this.changeEvent(this.startText)
//
let nowTimestamp = Math.floor((+ new Date()) / 1000)
//
if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
//
this.secNum = lastTimestamp - nowTimestamp
//
uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')
//
this.start()
} else {
//
this.changeEvent(this.startText)
}
},
//
start() {
//
if(this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.$emit('start')
this.canGetCode = false
// setInterval1
this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
this.setTimeToStorage()
this.timer = setInterval(() => {
if (--this.secNum) {
// "x"
this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
} else {
clearInterval(this.timer)
this.timer = null
this.changeEvent(this.endText)
this.secNum = this.seconds
this.$emit('end')
this.canGetCode = true
}
}, 1000)
},
//
reset() {
this.canGetCode = true
clearInterval(this.timer)
this.secNum = this.seconds
this.changeEvent(this.endText)
},
changeEvent(text) {
this.$emit('change', text)
},
// H5
setTimeToStorage() {
if(!this.keepRunning || !this.timer) return
//
// 0
if(this.secNum > 0 && this.secNum <= this.seconds) {
// (+ new Date())1000
let nowTimestamp = Math.floor((+ new Date()) / 1000)
// => +
uni.setStorage({
key: this.uniqueKey + '_$uCountDownTimestamp',
data: nowTimestamp + Number(this.secNum)
})
}
}
},
//
beforeDestroy() {
this.setTimeToStorage()
clearTimeout(this.timer)
this.timer = null
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
</style>

@ -0,0 +1,30 @@
import defprops from '../../libs/config/props';
export default {
props: {
// 占父容器宽度的多少等分,总分为12份
span: {
type: [String, Number],
default: defprops.col.span
},
// 指定栅格左侧的间隔数(总12栏)
offset: {
type: [String, Number],
default: defprops.col.offset
},
// 水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
justify: {
type: String,
default: defprops.col.justify
},
// 垂直对齐方式,可选值为top、center、bottom、stretch
align: {
type: String,
default: defprops.col.align
},
// 文字对齐方式
textAlign: {
type: String,
default: defprops.col.textAlign
}
}
}

@ -0,0 +1,168 @@
<template>
<view
class="u-col"
ref="u-col"
:class="[
'u-col-' + span
]"
:style="[colStyle]"
@tap="clickHandler"
>
<slot></slot>
</view>
</template>
<script>
import props from './props.js';
import mpMixin from '../../libs/mixin/mpMixin.js';
import mixin from '../../libs/mixin/mixin.js';
/**
* CodeInput 栅格系统的列
* @description 该组件一般用于Layout 布局 通过基础的 12 分栏迅速简便地创建布局
* @tutorial https://ijry.github.io/uview-plus/components/Layout.html
* @property {String | Number} span 栅格占据的列数总12等份 (默认 12 )
* @property {String | Number} offset 分栏左边偏移计算方式与span相同 (默认 0 )
* @property {String} justify 水平排列方式可选值为`start`(`flex-start`)`end`(`flex-end`)`center``around`(`space-around`)`between`(`space-between`) (默认 'start' )
* @property {String} align 垂直对齐方式可选值为topcenterbottomstretch (默认 'stretch' )
* @property {String} textAlign 文字水平对齐方式 (默认 'left' )
* @property {Object} customStyle 定义需要用到的外部样式
* @event {Function} click col被点击会阻止事件冒泡到row
* @example <u-col span="3" offset="3" > <view class="demo-layout bg-purple"></view> </u-col>
*/
export default {
name: 'u-col',
mixins: [mpMixin, mixin, props],
data() {
return {
width: 0,
parentData: {
gutter: 0
},
gridNum: 12
}
},
// options
options: {
virtualHost: true // Vue flex
},
computed: {
uJustify() {
if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify
else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify
else return this.justify
},
uAlignItem() {
if (this.align == 'top') return 'flex-start'
if (this.align == 'bottom') return 'flex-end'
else return this.align
},
colStyle() {
const style = {
// "padding: 0 10px"nvue
paddingLeft: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2),
paddingRight: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2),
alignItems: this.uAlignItem,
justifyContent: this.uJustify,
textAlign: this.textAlign,
// #ifndef APP-NVUE
// nvue使
flex: `0 0 ${100 / this.gridNum * this.span}%`,
marginLeft: 100 / 12 * this.offset + '%',
// #endif
// #ifdef APP-NVUE
// nvue使
width: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.span))),
marginLeft: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.offset))),
// #endif
}
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
mounted() {
this.init()
},
methods: {
async init() {
// provide/inject使created
this.updateParentData()
this.width = await this.parent.getComponentWidth()
},
updateParentData() {
this.getParentData('u-row')
},
clickHandler(e) {
this.$emit('click');
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-col {
padding: 0;
/* #ifndef APP-NVUE */
box-sizing:border-box;
/* #endif */
/* #ifdef MP */
display: block;
/* #endif */
}
// nvue
/* #ifndef APP-NVUE */
.u-col-0 {
width: 0;
}
.u-col-1 {
width: calc(100%/12);
}
.u-col-2 {
width: calc(100%/12 * 2);
}
.u-col-3 {
width: calc(100%/12 * 3);
}
.u-col-4 {
width: calc(100%/12 * 4);
}
.u-col-5 {
width: calc(100%/12 * 5);
}
.u-col-6 {
width: calc(100%/12 * 6);
}
.u-col-7 {
width: calc(100%/12 * 7);
}
.u-col-8 {
width: calc(100%/12 * 8);
}
.u-col-9 {
width: calc(100%/12 * 9);
}
.u-col-10 {
width: calc(100%/12 * 10);
}
.u-col-11 {
width: calc(100%/12 * 11);
}
.u-col-12 {
width: calc(100%/12 * 12);
}
/* #endif */
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save