commit 1cd4b94cfe0e2b0e5283aeb8fe9b2d8ed883e6de
Author: yujialong <479214531@qq.com>
Date: Mon Feb 20 11:27:44 2023 +0800
initial
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..efe7735
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+unpackage
\ No newline at end of file
diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json
new file mode 100644
index 0000000..81f13f4
--- /dev/null
+++ b/.hbuilderx/launch.json
@@ -0,0 +1,16 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+ // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+ "version": "0.0",
+ "configurations": [{
+ "default" :
+ {
+ "launchtype" : "local"
+ },
+ "mp-weixin" :
+ {
+ "launchtype" : "local"
+ },
+ "type" : "uniCloud"
+ }
+ ]
+}
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..55be1b2
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,36 @@
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..654e9e1
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# 或然中台小程序端
\ No newline at end of file
diff --git a/apis/modules/client.js b/apis/modules/client.js
new file mode 100644
index 0000000..560370c
--- /dev/null
+++ b/apis/modules/client.js
@@ -0,0 +1,54 @@
+import request from '@/apis/request.js'
+const { get, post } = request
+
+export const queryCustomer = (data) => {
+ return post('nakadai/nakadai/customer/queryCustomer', data)
+}
+
+export const list = (data) => {
+ return post('nakadai/nakadai/applets/customer/getCustomerListBasedOnBusinessManagerId', data)
+}
+
+export const all = (data) => {
+ return post('nakadai/nakadai/applets/customer/customerList', data)
+}
+
+export const queryCustomerDetails = (data) => {
+ return get('nakadai/nakadai/customer/queryCustomerDetails', data)
+}
+
+export const querySchool = (data) => {
+ return get('nakadai/nakadai/school/querySchool', data)
+}
+
+export const queryIndustryClass = (data) => {
+ return get('nakadai/nakadai/hrIndustryClass/queryIndustryClass', data)
+}
+
+export const queryIndustry = (data) => {
+ return get('nakadai/nakadai/hrIndustry/queryIndustry', data)
+}
+
+export const queryCustomerIsExists = (data) => {
+ return get('nakadai/nakadai/customer/queryCustomerIsExists', data)
+}
+
+export const addCustomer = (data) => {
+ return post('nakadai/nakadai/customer/addCustomer', data)
+}
+
+export const updateCustomer = (data) => {
+ return post('nakadai/nakadai/customer/updateCustomer', data)
+}
+
+export const getProductsSubscribedByCustomers = (data) => {
+ return get('nakadai/nakadai/customer/getProductsSubscribedByCustomers', data)
+}
+
+export const getTeamsByAccountId = (data) => {
+ return post('nakadai/nakadai/applets/customer/getTeamsByAccountId', data)
+}
+
+export const getTheBusinessManagerIdsUnderTheTeam = id => {
+ return post(`nakadai/nakadai/applets/customer/getTheBusinessManagerIdsUnderTheTeam?id=${id}`)
+}
\ No newline at end of file
diff --git a/apis/modules/order.js b/apis/modules/order.js
new file mode 100644
index 0000000..0d8332b
--- /dev/null
+++ b/apis/modules/order.js
@@ -0,0 +1,38 @@
+import request from '@/apis/request.js'
+const { get, post } = request
+
+export const getOrderOtherTime = (data) => {
+ return post('nakadai/nakadai/orderOther/getOrderOtherTime', data)
+}
+
+export const add = (data) => {
+ return post('nakadai/nakadai/order/add', data)
+}
+
+export const update = (data) => {
+ return post('nakadai/nakadai/order/update', data)
+}
+
+export const getDetail = (data) => {
+ return get('nakadai/nakadai/order/get', data)
+}
+
+export const renew = (data) => {
+ return post('nakadai/nakadai/orderOther/renew', data)
+}
+
+export const list = (data) => {
+ return post('nakadai/nakadai/applets/order/orderList', data)
+}
+
+export const orderList = (data) => {
+ return post('nakadai/nakadai/order/list', data)
+}
+
+export const del = (data) => {
+ return post('nakadai/nakadai/order/delete', data)
+}
+
+export const miniProgramOrderRecord = (data) => {
+ return post('nakadai/nakadai/applets/order/miniProgramOrderRecord', data)
+}
\ No newline at end of file
diff --git a/apis/modules/parner.js b/apis/modules/parner.js
new file mode 100644
index 0000000..8d9925e
--- /dev/null
+++ b/apis/modules/parner.js
@@ -0,0 +1,26 @@
+import request from '@/apis/request.js'
+const { get, post } = request
+
+export const savePartnerAccount = (data) => {
+ return post('nakadai/nakadai/partnerAccount/savePartnerAccount', data)
+}
+
+export const teamList = (data) => {
+ return post('nakadai/nakadai/partnerAccount/partnerAccountList', data)
+}
+
+export const generateInvitationCode = accountId => {
+ return post(`nakadai/nakadai/partnerAccount/generateInvitationCode?accountId=${accountId}`)
+}
+
+export const treeList = (data) => {
+ return post('nakadai/nakadai/partnerClassification/treeList', data)
+}
+
+export const my = (data) => {
+ return get('nakadai/nakadai/partner-team/my', data)
+}
+
+export const mailFileSend = (data) => {
+ return post('nakadai/nakadai/partnerAccount/mailFileSend', data)
+}
\ No newline at end of file
diff --git a/apis/modules/product.js b/apis/modules/product.js
new file mode 100644
index 0000000..739f421
--- /dev/null
+++ b/apis/modules/product.js
@@ -0,0 +1,6 @@
+import request from '@/apis/request.js'
+const { get, post } = request
+
+export const AppletsDataProductList = (data) => {
+ return post('nakadai/nakadai/dataProduct/AppletsDataProductList', data)
+}
\ No newline at end of file
diff --git a/apis/modules/user.js b/apis/modules/user.js
new file mode 100644
index 0000000..3b8b175
--- /dev/null
+++ b/apis/modules/user.js
@@ -0,0 +1,52 @@
+import request from '@/apis/request.js'
+const { get, post } = request
+
+export const login = (data) => {
+ return post('users/users/user/weChatAppletCallback', data)
+}
+
+export const userBinding = (data) => {
+ return post('users/users/user/userBinding', data)
+}
+
+export const examinePassword = (data) => {
+ return post('users/users/userAccount/examinePassword', data)
+}
+
+export const getUserRolesPermissionMenu = (data) => {
+ return get('users/users/user-role/getUserRolesPermissionMenu', data)
+}
+
+export const updatePersonCenter = (data) => {
+ return post('users/users/userAccount/updatePersonCenter', data)
+}
+
+export const queryUserInfoDetails = () => {
+ return get('users/users/userAccount/queryUserInfoDetails')
+}
+
+export const updateMyEmail = (data) => {
+ return post('nakadai/nakadai/partner-team/updateMyEmail', data)
+}
+
+export const mailCodeSend = (data) => {
+ return post('nakadai/nakadai/partner-team/mailCodeSend', data)
+}
+
+export const changeAccount = account => {
+ return post(`users/users/applets/mine/changeAccount?account=${account}`)
+}
+
+export const changePhoneNumber = (phone, code) => {
+ return post(`users/users/applets/mine/changePhoneNumber?phone=${phone}&code=${code}`)
+}
+
+export const checkIfAnAccountExists = account => {
+ return post(`users/users/applets/mine/checkIfAnAccountExists?account=${account}`)
+}
+
+export const checkIfThePhoneNumberExists = phone => {
+ return post(`users/users/applets/mine/checkIfThePhoneNumberExists?phone=${phone}`)
+}
+
+export const updateUserAvatars = `http://39.108.250.202:9000/users/users/userAccount/updateUserAvatars`
\ No newline at end of file
diff --git a/apis/request.js b/apis/request.js
new file mode 100644
index 0000000..a75d827
--- /dev/null
+++ b/apis/request.js
@@ -0,0 +1,89 @@
+import config from '@/config/request'
+let HTTP_COUNT = 0 // loading次数
+
+const request = options => {
+ HTTP_COUNT++
+ if (config.showLoading) {
+ // 请求数据时的loading
+ // uni.showToast({
+ // title: '加载中',
+ // duration: 200,
+ // icon: 'loading'
+ // })
+ }
+ const header = Object.assign({}, config.headers, {
+ token: uni.getStorageSync('token')
+ })
+ const otherUrl = ['getTeamsByAccountId']
+ return new Promise((resolve, reject)=>{
+ const { url } = options
+ uni.request({
+ header,
+ // url: (otherUrl.map(e => config.baseURL.includes(e)) ? 'http://192.168.31.137:9000/' : config.baseURL) + url,
+ url: config.baseURL + url,
+ method: options.method || 'GET', // 请求类型,默认为GET
+ data: options.data || {}, // 请求参数,默认空对象
+ success: ({ data }) => {
+ const { status, message } = data
+ // 状态判断,根据后台定义并提示
+ if (status === 200) {
+ resolve(data)
+ } else if (status == 401) {
+ // 登录过期
+ uni.clearStorageSync()
+ uni.showToast({
+ title: message,
+ icon: 'none'
+ })
+ setTimeout(() => {
+ uni.navigateTo({
+ url: '../login/login'
+ })
+ }, 1500)
+ reject(data)
+ } else if (!status) {
+ resolve(data)
+ } else {
+ uni.showToast({
+ title: message,
+ icon: 'none'
+ })
+ reject(data)
+ }
+ },
+ fail: err => {
+ uni.showToast({
+ title: '请求失败!',
+ icon: 'none'
+ })
+ reject(err)
+ },
+ complete: () => {
+ if (config.showLoading) {
+ // HTTP_COUNT--
+ // HTTP_COUNT || uni.hideLoading()
+ }
+ }
+ })
+ })
+}
+
+const get = (url, data, options = {}) => {
+ options.method = 'GET'
+ options.data = data
+ options.url = url
+ return request(options)
+}
+
+const post = (url, data, options = {}) => {
+ options.method = 'POST'
+ options.data = data
+ options.url = url
+ return request(options)
+}
+
+export default {
+ request,
+ get,
+ post
+}
\ No newline at end of file
diff --git a/components/empty/empty.vue b/components/empty/empty.vue
new file mode 100644
index 0000000..42d2f06
--- /dev/null
+++ b/components/empty/empty.vue
@@ -0,0 +1,40 @@
+
+
+
+ {{ text }}
+
+
+
+
+
+
diff --git a/components/filter-popup/components/mask.vue b/components/filter-popup/components/mask.vue
new file mode 100644
index 0000000..521f0d9
--- /dev/null
+++ b/components/filter-popup/components/mask.vue
@@ -0,0 +1,130 @@
+
+ {}"
+ :class="{
+ 'u-mask-zoom': zoom,
+ 'u-mask-show': show,
+ }"
+ >
+
+
+
+
+
+
+
diff --git a/components/filter-popup/components/popup.vue b/components/filter-popup/components/popup.vue
new file mode 100644
index 0000000..fffcfdc
--- /dev/null
+++ b/components/filter-popup/components/popup.vue
@@ -0,0 +1,510 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/filter-popup/detail.md b/components/filter-popup/detail.md
new file mode 100644
index 0000000..e704412
--- /dev/null
+++ b/components/filter-popup/detail.md
@@ -0,0 +1,155 @@
+## 导入即用 全端支持
+
+### 有问题 + wx : zy597172583 标注来意 可评论 看到及时回复
+1.使用方式
+
+```javascript
+
+
+
+
+
diff --git a/components/uni-section/uni-section.vue b/components/uni-section/uni-section.vue
new file mode 100644
index 0000000..a68c7b7
--- /dev/null
+++ b/components/uni-section/uni-section.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/product.js b/config/product.js
new file mode 100644
index 0000000..206e21d
--- /dev/null
+++ b/config/product.js
@@ -0,0 +1,10 @@
+/**
+/**
+ * 产品 配置文件
+ * @author yujialong
+ */
+
+export default {
+ normalIcon: 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220609/png/1534733700683030528.png', // 通用图标
+ dataIcon: 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220627/png/1541256164447641600.png' // 数据图标
+}
diff --git a/config/request.js b/config/request.js
new file mode 100644
index 0000000..3b20681
--- /dev/null
+++ b/config/request.js
@@ -0,0 +1,21 @@
+/**
+/**
+ * 请求配置文件
+ * @author yujialong
+ */
+
+export default {
+ baseURL: 'https://huorantech.cn/',
+ // baseURL: 'http://192.168.31.137:9000/',
+ // baseURL: 'http://121.37.12.51/',
+ headers: {
+ 'Content-Type': 'application/json;charset=UTF-8'
+ },
+ data: {},
+ method: 'POST',
+ responseType: 'json', // 响应数据类型
+ withCredentials: false, // 携带cookie
+ // ======================== 以下为注入axios的配置项 =============================
+ showLoading: true, // 是否显示加载动画
+ isFormData: false // 是否序列化表单数据
+}
diff --git a/directives/auth.js b/directives/auth.js
new file mode 100644
index 0000000..be3a722
--- /dev/null
+++ b/directives/auth.js
@@ -0,0 +1,16 @@
+/**
+ * @description 鉴权指令
+ * 当传入的权限当前用户没有时,会移除该组件
+ * 用例:text 或者:text
+ * */
+export default {
+ inserted(el, binding, vnode) {
+ const btnText = el.innerText
+ const btnPermissions = uni.getStorageSync('auth')
+ if (btnText && btnPermissions && btnPermissions.length) {
+ const isPermission = btnPermissions.includes(btnText)
+ // 如果按钮集合里没有该权限,就把该按钮给去除
+ !isPermission && el.parentNode && el.parentNode.removeChild(el)
+ }
+ },
+};
diff --git a/directives/index.js b/directives/index.js
new file mode 100644
index 0000000..63e26af
--- /dev/null
+++ b/directives/index.js
@@ -0,0 +1,12 @@
+/**
+ * 插件
+ * */
+
+import auth from './auth'
+
+export default {
+ async install(Vue, options) {
+ // 指令
+ Vue.directive('auth', auth)
+ }
+};
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9efb733
--- /dev/null
+++ b/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/WXBizDataCrypt.js b/libs/WXBizDataCrypt.js
new file mode 100644
index 0000000..36b3de1
--- /dev/null
+++ b/libs/WXBizDataCrypt.js
@@ -0,0 +1,35 @@
+var crypto = require('crypto')
+
+function WXBizDataCrypt(appId, sessionKey) {
+ this.appId = appId
+ this.sessionKey = sessionKey
+}
+
+WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
+ // base64 decode
+ var sessionKey = new Buffer(this.sessionKey, 'base64')
+ encryptedData = new Buffer(encryptedData, 'base64')
+ iv = new Buffer(iv, 'base64')
+
+ try {
+ // 解密
+ var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
+ // 设置自动 padding 为 true,删除填充补位
+ decipher.setAutoPadding(true)
+ var decoded = decipher.update(encryptedData, 'binary', 'utf8')
+ decoded += decipher.final('utf8')
+
+ decoded = JSON.parse(decoded)
+
+ } catch (err) {
+ throw new Error('Illegal Buffer')
+ }
+
+ if (decoded.watermark.appid !== this.appId) {
+ throw new Error('Illegal Buffer')
+ }
+
+ return decoded
+}
+
+module.exports = WXBizDataCrypt
\ No newline at end of file
diff --git a/libs/util.js b/libs/util.js
new file mode 100644
index 0000000..70d94da
--- /dev/null
+++ b/libs/util.js
@@ -0,0 +1,107 @@
+import Product from '@/config/product'
+
+const files = [
+ 'https://huorantech.cn/%E7%94%A8%E6%88%B7%E6%9C%8D%E5%8A%A1%E5%8D%8F%E8%AE%AE.docx', // 用户服务协议
+ 'https://huorantech.cn/%E7%94%A8%E6%88%B7%E9%9A%90%E7%A7%81%E5%8D%8F%E8%AE%AE.docx', // 用户隐私协议
+ 'https://huorantech.cn/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%AE%9E%E9%AA%8C%E5%AE%A4%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88-2020.1.docx', // 人工智能
+ 'https://huorantech.cn/%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86%E4%B8%8E%E5%BA%94%E7%94%A8%E4%B8%93%E4%B8%9A%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88.docx', // 大数据
+ 'https://huorantech.cn/%E9%87%91%E8%9E%8D%E7%A7%91%E6%8A%80%E5%AE%9E%E9%AA%8C%E5%AE%A4%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88V2.0.docx', // 金融科技
+]
+export default {
+ // 路由跳转
+ to(url) {
+ uni.navigateTo({
+ url
+ })
+ },
+ // 成功提示
+ sucMsg(title, duration = 1500) {
+ uni.showToast({
+ title,
+ duration
+ })
+ },
+ // 错误提示
+ errMsg(title, duration = 1500) {
+ uni.showToast({
+ title,
+ icon: 'none',
+ duration
+ })
+ },
+ // 如果非数字,则返回0
+ handleNaN(val) {
+ return isNaN(val) ? 0 : val
+ },
+ // 小于10,返回0+传入值
+ preZero(val) {
+ return val < 10 ? '0' + val : val
+ },
+ //返回格式化时间,传参例如:"yyyy-MM-dd hh:mm:ss"
+ formatDate(date, fmt = 'yyyy-MM-dd hh:mm:ss') {
+ var date = date ? date : new Date()
+ var o = {
+ "M+" : date.getMonth()+1, //月份
+ "d+" : date.getDate(), //日
+ "h+" : date.getHours(), //小时
+ "m+" : date.getMinutes(), //分
+ "s+" : date.getSeconds(), //秒
+ "q+" : Math.floor((date.getMonth()+3)/3), //季度
+ "S" : date.getMilliseconds() //毫秒
+ }
+ if(/(y+)/.test(fmt)) {
+ fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length))
+ }
+ for(var k in o) {
+ if(new RegExp("("+ k +")").test(fmt)){
+ fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)))
+ }
+ }
+ return fmt
+ },
+ // 获取商务经理id
+ getBmId(val) {
+ return uni.getStorageSync('team').partnerId
+ },
+ // 获取商务经理名称
+ getBmName(val) {
+ return uni.getStorageSync('team').partnerClassificationName
+ },
+ // 返回图标。如果有图标,则直接返回,否则判断是否是数据产品,即productType=2,如果是,则取数据图标,否则则显示通用图标,这两个图标都在config/product.js里有配置
+ getIcon(e) {
+ return e.miniProgramPictureAddress || (e.productType === 2 ? Product.dataIcon : Product.normalIcon)
+ },
+ // 预览文档
+ openFile(id) {
+ uni.showLoading({
+ title: '加载中',
+ mask: true
+ })
+ // 下载文件资源到本地
+ uni.downloadFile({
+ url: files[id],
+ success: function(res) {
+ uni.hideLoading();
+ uni.showLoading({
+ title: '正在打开',
+ mask: true
+ })
+ // 新开页面打开文档,支持格式:doc, xls, ppt, pdf, docx, xlsx, pptx。
+ uni.openDocument({
+ filePath: res.tempFilePath,
+ fileType: 'docx', // 文件类型,指定文件类型打开文件,有效值 doc, xls, ppt, pdf, docx, xlsx, pptx
+ showMenu: true, // 允许出现分享功能
+ success: res => {
+ uni.hideLoading()
+ },
+ fail: openError => {
+ uni.hideLoading()
+ }
+ })
+ },
+ fail: function(err) {
+ uni.hideLoading()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..a0768de
--- /dev/null
+++ b/main.js
@@ -0,0 +1,39 @@
+
+// #ifndef VUE3
+import Vue from 'vue'
+import App from './App'
+import util from '@/libs/util'
+import plugins from '@/directives'
+
+Vue.config.productionTip = false
+Vue.prototype.$util = util
+Vue.use(plugins)
+
+App.mpType = 'app'
+
+// 权限控制
+Vue.prototype.auth = function(text){
+ const auth = uni.getStorageSync('auth')
+ if (text && auth && auth.length) {
+ const isPermission = auth.includes(text)
+ return auth.includes(text)
+ }
+ // return true
+}
+
+const app = new Vue({
+ ...App
+})
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+import App from './App.vue'
+export function createApp() {
+ const app = createSSRApp(App)
+ return {
+ app
+ }
+}
+// #endif
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..58d36e2
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,60 @@
+{
+ "name" : "或然crm",
+ "appid" : "__UNI__2E89BA6",
+ "description" : "",
+ "versionName" : "1.0.0",
+ "versionCode" : "100",
+ "transformPx" : false,
+ "app-plus" : {
+ /* 5+App特有相关 */
+ "usingComponents" : true,
+ "nvueCompiler" : "uni-app",
+ "splashscreen" : {
+ "alwaysShowBeforeRender" : true,
+ "waiting" : true,
+ "autoclose" : true,
+ "delay" : 0
+ },
+ "modules" : {},
+ /* 模块配置 */
+ "distribute" : {
+ /* 应用发布信息 */
+ "android" : {
+ /* android打包配置 */
+ "permissions" : [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ "ios" : {},
+ /* ios打包配置 */
+ "sdkConfigs" : {}
+ }
+ },
+ /* SDK配置 */
+ "quickapp" : {},
+ /* 快应用特有相关 */
+ "mp-weixin" : {
+ "appid" : "wx88cd6037d54f230a",
+ "setting" : {
+ "urlCheck" : false,
+ "es6" : true,
+ "minified" : true
+ },
+ "usingComponents" : true
+ },
+ "vueVersion" : "2"
+}
diff --git a/order/addCourse/addCourse.vue b/order/addCourse/addCourse.vue
new file mode 100644
index 0000000..ddcac1d
--- /dev/null
+++ b/order/addCourse/addCourse.vue
@@ -0,0 +1,329 @@
+
+
+
+
+
+
+
+
+
+ -
+ checkChange(e, i)">
+ checkChange(e, i)">
+
+ {{ item.productName }}
+
+
+
+
+
+
+ 确定({{ checked.length }})
+
+
+
+
+
+
+
diff --git a/order/curClient/curClient.vue b/order/curClient/curClient.vue
new file mode 100644
index 0000000..1fa3992
--- /dev/null
+++ b/order/curClient/curClient.vue
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.orderNumber }}
+
+
+
+ 商务经理:
+ {{ item.businessManagerName }}
+
+
+ 客户名称:
+ {{ item.customerName }}
+
+
+ 订单金额:
+ {{ item.orderAmount }}元
+
+
+ 订单内容:
+
+ {{ item.productName }}
+ {{ item.toggle ? '收起' : '展开' }}
+
+
+
+ 下单日期:
+ {{ item.createTime }}
+
+
+
+ {{ filterData[0].data.find(e => e.value === item.orderStatus).title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/order/editCourse/editCourse.vue b/order/editCourse/editCourse.vue
new file mode 100644
index 0000000..ae21e0e
--- /dev/null
+++ b/order/editCourse/editCourse.vue
@@ -0,0 +1,420 @@
+
+
+
+
+ {{ c.name }}
+
+
+
+
+
+
+ {{ item.productName }}
+
+
+
+
+
+ 产品类型
+ {{ productTypes.find(e => e.id === item.productType).name }}
+
+
+ 使用期限
+
+
+ {{ units.find(e => e.id === item.options).text }}
+
+
+
+
+ 起止日期
+
+
+ {{ item.endTime ? item.startTime + ' - ' + item.endTime : item.startTime}}
+
+
+
+
+ 数量
+ 1
+
+
+
+ {{ item.authority ? '市场价' : '市场单价' }}
+ {{ item.marketValue }}元
+
+
+ 结算价
+ {{ item.settlementPrice }}元
+
+
+ 折扣率
+ {{ item.discountRate }}
+
+
+ 平台服务费
+ {{ item.serviceFee }}元
+
+
+ 成交价
+
+
+ 元
+
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
diff --git a/order/orderDetail/orderDetail.vue b/order/orderDetail/orderDetail.vue
new file mode 100644
index 0000000..39a8e04
--- /dev/null
+++ b/order/orderDetail/orderDetail.vue
@@ -0,0 +1,644 @@
+
+
+
+ 基本信息
+
+
+ 商务经理
+ {{ form.businessManagerName }}
+
+
+ 客户名称
+ {{ form.customerName }}
+ {{ form.customerName || '请选择客户' }}
+
+
+ 省份
+ {{ form.provinceName }}
+
+
+ 城市
+ {{ form.cityName }}
+
+
+ 联系人
+ {{ form.orderContact }}
+
+
+ 电话
+ {{ form.phone }}
+
+
+ 邮箱
+ {{ form.email }}
+
+
+ 订单类型
+ {{ orderTypes.find(e => e.value === form.orderType).text }}
+
+
+
+ 订单编号
+ {{ form.orderNumber }}
+
+
+ 订单时间
+ {{ form.createTime }}
+
+
+ 订单金额(元)
+ {{ form.orderAmount }}
+
+
+
+
+
+
+ {{ c.name }}
+
+
+ -
+
+
+
+ {{ item.productName }}
+
+
+
+
+
+ 使用期限
+ {{ item.startTime + ' - ' + item.endTime }}
+
+
+ 市场价(元)
+ {{ item.marketValue }}元
+
+
+ 结算价
+ {{ item.settlementPrice }}元
+
+
+ 折扣率
+ {{ item.discountRate }}
+
+
+ 平台服务费
+ {{ item.serviceFee }}元
+
+
+ 成交价格
+ {{ item.finalPrice }}元
+
+
+
+
+
+
+
+
+
+
+
+ 添加产品
+
+
+
+
+
+
+ 共选{{ courses.length }}个产品
+ 总成交价合计{{ form.orderAmount }}元
+
+
+
+ 总采购成本:{{ form.purchaseCost }}元
+
+
+ 总产品利润: {{ form.profit }} 元
+
+
+
+ 提交({{ courses.length }})
+
+
+
+
+
+
+
+
+
+
+
diff --git a/order/ordered/ordered.vue b/order/ordered/ordered.vue
new file mode 100644
index 0000000..e412121
--- /dev/null
+++ b/order/ordered/ordered.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ {{ item.productName }}
+
+
+
+ 起止日期:
+ {{ item.startAndEndTime }}
+
+
+ 订阅状态:
+ {{ item.status }}
+
+
+ 产品状态:
+ {{ item.isEnable }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/order/orders/orders.vue b/order/orders/orders.vue
new file mode 100644
index 0000000..17fa698
--- /dev/null
+++ b/order/orders/orders.vue
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.orderNumber }}
+
+
+
+ 商务经理:
+ {{ item.businessManagerName }}
+
+
+ 客户名称:
+ {{ item.customerName }}
+
+
+ 订单金额:
+ {{ item.orderAmount }}元
+
+
+ 订单内容:
+
+ {{ item.orderContent }}
+ {{ item.toggle ? '收起' : '展开' }}
+
+
+
+ 下单日期:
+ {{ item.createTime }}
+
+
+
+ {{ filterData[0].data.find(e => e.value === item.orderStatus).title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..de153de
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "id": "filter-popup",
+ "name": "筛选 菜单 筛选菜单 上拉筛选 ",
+ "version": "1.0.4",
+ "description": "筛选菜单,支持单选和多选 , 选择后的数据通过.sync双向绑定,全端支持 导入即用",
+ "keywords": [
+ "筛选",
+ "菜单",
+ "筛选菜单",
+ "上拉筛选"
+ ]
+}
\ No newline at end of file
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..89bba10
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,231 @@
+{
+ "pages": [
+ {
+ "path" : "pages/login/login",
+ "style" :
+ {
+ "navigationBarTitleText": "登录",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/index/index",
+ "style" :
+ {
+ "navigationBarTitleText": "",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/qrcode/qrcode",
+ "style" :
+ {
+ "navigationBarTitleText": "邀请加入",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/clients/clients",
+ "style" :
+ {
+ "navigationBarTitleText": "客户列表",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path" : "pages/products/products",
+ "style" :
+ {
+ "navigationBarTitleText": "产品",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path" : "pages/clientDetail/clientDetail",
+ "style" :
+ {
+ "navigationBarTitleText": "客户详情",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/addStaff/addStaff",
+ "style" :
+ {
+ "navigationBarTitleText": "邀请成员",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/plans/plans",
+ "style" :
+ {
+ "navigationBarTitleText": "产品方案",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/person/person",
+ "style" :
+ {
+ "navigationBarTitleText": "我的",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/send/send",
+ "style" :
+ {
+ "navigationBarTitleText": "下载发送",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/password/password",
+ "style" :
+ {
+ "navigationBarTitleText": "修改密码",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/setting/setting",
+ "style" :
+ {
+ "navigationBarTitleText": "设置",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "pages/teams/teams",
+ "style" :
+ {
+ "navigationBarTitleText": "团队",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path" : "pages/account/account",
+ "style" :
+ {
+ "navigationBarTitleText": "修改账号",
+ "enablePullDownRefresh": false
+ }
+ }
+ ,{
+ "path" : "pages/phone/phone",
+ "style" :
+ {
+ "navigationBarTitleText": "修改手机号",
+ "enablePullDownRefresh": false
+ }
+ }
+ ,{
+ "path" : "pages/email/email",
+ "style" :
+ {
+ "navigationBarTitleText": "修改邮箱",
+ "enablePullDownRefresh": false
+ }
+ }
+ ],
+ "subPackages": [{
+ "root": "order",
+ "pages": [
+ {
+ "path": "orders/orders",
+ "style" :
+ {
+ "navigationBarTitleText": "订单列表",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path" : "addCourse/addCourse",
+ "style" :
+ {
+ "navigationBarTitleText": "选择产品",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path" : "orderDetail/orderDetail",
+ "style" :
+ {
+ "navigationBarTitleText": "订单详情",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "ordered/ordered",
+ "style" :
+ {
+ "navigationBarTitleText": "已订阅产品",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "editCourse/editCourse",
+ "style" :
+ {
+ "navigationBarTitleText": "编辑产品",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "curClient/curClient",
+ "style" :
+ {
+ "navigationBarTitleText": "订单记录",
+ "enablePullDownRefresh": false
+ }
+ }
+ ]
+ }],
+ "preloadRule": {
+ "order/orders/orders": {
+ "network": "all",
+ "packages": ["__APP__"]
+ }
+ },
+ "condition": { //模式配置,仅开发期间生效
+ "current": 0, //当前激活的模式(list 的索引项)
+ "list": [{
+ "name": "test", //模式名称
+ "path": "pages/login/login" //启动页面,必选
+ }]
+ },
+ "globalStyle": {
+ "navigationBarTextStyle": "white",
+ "navigationBarTitleText": "或然中台",
+ "navigationBarBackgroundColor": "#007EFF",
+ "backgroundColor": "#f5f5f5",
+ "app-plus": {
+ "background": "#efeff4"
+ }
+ },
+ "tabBar": {
+ "color": "#B8B9B8",
+ "selectedColor": "#007FFF",
+ "borderStyle": "white",
+ "backgroundColor": "#ffffff",
+ "fontSize": "16px",
+ "iconWidth": "30px",
+ "list": [{
+ "pagePath": "pages/index/index",
+ "iconPath": "static/image/tab1.png",
+ "selectedIconPath": "static/image/tab1-1.png",
+ "text": "首页"
+ }, {
+ "pagePath": "pages/teams/teams",
+ "iconPath": "static/image/tab2.png",
+ "selectedIconPath": "static/image/tab2-1.png",
+ "text": "团队"
+ }, {
+ "pagePath": "pages/person/person",
+ "iconPath": "static/image/tab3.png",
+ "selectedIconPath": "static/image/tab3-1.png",
+ "text": "我的"
+ }]
+ }
+}
diff --git a/pages/account/account.vue b/pages/account/account.vue
new file mode 100644
index 0000000..991902e
--- /dev/null
+++ b/pages/account/account.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/addStaff/addStaff.vue b/pages/addStaff/addStaff.vue
new file mode 100644
index 0000000..a48c611
--- /dev/null
+++ b/pages/addStaff/addStaff.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+ 二维码邀请
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/clientDetail/clientDetail.vue b/pages/clientDetail/clientDetail.vue
new file mode 100644
index 0000000..df4f45c
--- /dev/null
+++ b/pages/clientDetail/clientDetail.vue
@@ -0,0 +1,372 @@
+
+
+
+
+ {{ form.customerName }}
+ 客户类型:{{ customerType }}
+ 产品到期时间:{{ form.expireDate || '' }}
+
+
+
+
+ 基本信息
+
+
+ 客户名称
+ {{ form.customerName }}
+ {{ form.customerName || '请选择学校' }}
+
+
+ 省份
+ {{ form.provinceName }}
+
+
+ 城市
+ {{ form.cityName }}
+
+
+ 行业类型
+ {{ form.industryClassName }}
+
+
+
+ 行业
+ {{ form.industryName }}
+
+
+
+ 联系人姓名
+ {{ form.name }}
+
+
+
+ 手机
+ {{ form.phone }}
+
+
+
+ 账号
+ {{ form.account }}
+
+
+
+ 职务
+ {{ form.position }}
+
+
+
+ 邮箱
+ {{ form.email }}
+
+
+
+ 产品到期时间
+ {{ form.expireDate }}
+
+
+ 客户类型
+ {{ customerType }}
+
+
+
+
+
+
+
+ 编辑
+
+
+
+ 已订阅产品
+
+
+
+ 订单
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/clients/clients.vue b/pages/clients/clients.vue
new file mode 100644
index 0000000..1853502
--- /dev/null
+++ b/pages/clients/clients.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+ -
+ {{ item.customerName }}
+
+
+
+ 联系人:
+ {{ item.orderContact }}
+
+
+ 账号:
+ {{ item.account }}
+
+
+ 产品到期时间:
+ {{ item.expireDate.split(' ')[0] }}
+
+
+ 商务经理:
+ {{ item.businessManagerName }}
+
+
+
+ {{ filterData[0].data.find(e => e.value === item.customerType).title }}客户
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/email/email.vue b/pages/email/email.vue
new file mode 100644
index 0000000..64f7850
--- /dev/null
+++ b/pages/email/email.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+ {{ btnText }}
+
+
+
+
+
+
+
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
new file mode 100644
index 0000000..29eae03
--- /dev/null
+++ b/pages/index/index.vue
@@ -0,0 +1,349 @@
+
+
+
+
+
+
+
+
+
+
+ 城市合伙人招募中
+ 携手共创教育信息化新未来,合伙共享产业互联领域新红利
+
+
+
+
+ -
+
+ 客户
+
+ -
+
+ 方案
+
+ -
+
+ 订单
+
+ -
+
+ 产品
+
+
+
+
+
+
+
+ 销售进展
+
+
+
+ 本月
+
+
+
+
+
+
+ 本月新增客户
+ 0
+
+
+ 我的客户
+ 0
+
+
+
+
+ 本月新增产品试用
+ 0
+
+
+ 试用客户
+ 0
+
+
+
+
+
+
+
+
+
+
+ 年度业绩看板
+
+
+
+
+
+
+ 0
+ 成交总额
+
+
+ 0
+ 收益金额
+
+
+ 0
+ 已到账
+
+
+ 0
+ 未到账
+
+
+
+
+ 功能升级中,敬请期待...
+
+
+
+
+
+
diff --git a/pages/login/login.vue b/pages/login/login.vue
new file mode 100644
index 0000000..40ca523
--- /dev/null
+++ b/pages/login/login.vue
@@ -0,0 +1,236 @@
+
+
+
+
+ Hi,城市合伙人请登录
+
+
+
+
+ 微信授权登录
+
+
+
+ 手机账号登录
+
+
+
+
+
+ 《用户服务协议》
+ 《用户隐私协议》
+
+
+
+
+
+
+
+
diff --git a/pages/password/password.vue b/pages/password/password.vue
new file mode 100644
index 0000000..94d0c0b
--- /dev/null
+++ b/pages/password/password.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/person/person.vue b/pages/person/person.vue
new file mode 100644
index 0000000..accb003
--- /dev/null
+++ b/pages/person/person.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+ {{ my.info.userName }}
+ {{ my.info.phone }}
+
+
+
+
+
+
+ 我的项目收益
+
+ {{ my.myIncome}}元
+
+
+
+
+ 团队收益
+
+ {{ my.teamIncome}}元
+
+
+
+
+ 设置
+
+
+
+
+ 功能升级中,敬请期待...
+
+
+
+
+
+
diff --git a/pages/phone/phone.vue b/pages/phone/phone.vue
new file mode 100644
index 0000000..37c178b
--- /dev/null
+++ b/pages/phone/phone.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+ {{ btnText }}
+
+
+
+
+
+
+
+
diff --git a/pages/plans/plans.vue b/pages/plans/plans.vue
new file mode 100644
index 0000000..bdac8e1
--- /dev/null
+++ b/pages/plans/plans.vue
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+ 产品:
+
+
+ {{ item.toggle ? '收起' : '展开' }}
+
+
+
+ 更新日期:
+ {{ item.date }}
+
+
+ 适用专业:
+ {{ item.major }}
+
+
+ 下载
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/products/products.vue b/pages/products/products.vue
new file mode 100644
index 0000000..a5676df
--- /dev/null
+++ b/pages/products/products.vue
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ {{ item.productName }}
+
+
+
+ 产品简介:
+
+ {{ item.briefIntroduction }}
+ {{ item.toggle ? '收起' : '展开' }}
+
+
+
+ 产品类型:
+ {{ tabs.find(e => e.id === item.productType).name }}
+
+
+ 市场单价:
+ {{ item.marketPrice }}元/年
+
+
+ 结算方式:
+ {{ item.settlementMethod ? '比例分成' : '结算单价' }}
+
+
+ 供应厂商:
+ {{ item.supplier }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/qrcode/qrcode.vue b/pages/qrcode/qrcode.vue
new file mode 100644
index 0000000..4f9171b
--- /dev/null
+++ b/pages/qrcode/qrcode.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+ {{ userName }} 邀请你加入城市合伙人计划
+
+
+
+ {{ team.partnerClassificationName }}
+
+ 扫一扫,加入我们吧
+
+ 邀请二维码失效日期:{{ expireTime }}
+
+
+
+
+
+
+
diff --git a/pages/send/send.vue b/pages/send/send.vue
new file mode 100644
index 0000000..fe861e4
--- /dev/null
+++ b/pages/send/send.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ 我的邮箱
+
+ 绑定
+
+
+
+ 其他邮箱
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/setting/setting.vue b/pages/setting/setting.vue
new file mode 100644
index 0000000..34e99a7
--- /dev/null
+++ b/pages/setting/setting.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+ 退出登录
+
+
+
+
+
+
diff --git a/pages/teams/teams.vue b/pages/teams/teams.vue
new file mode 100644
index 0000000..3d0ac79
--- /dev/null
+++ b/pages/teams/teams.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+ -
+
+
+ {{ item.userName }}
+
+ 手机号码:
+ {{ item.phone }}
+
+
+ 加入时间:
+ {{ item.lastLoginTime.split(' ')[0] }}
+
+
+
+
+
+
+
+
+
+ 功能升级中,敬请期待...
+
+
+
+
+
+
diff --git a/static/iconfont/iconfont.css b/static/iconfont/iconfont.css
new file mode 100644
index 0000000..3a65ec5
--- /dev/null
+++ b/static/iconfont/iconfont.css
@@ -0,0 +1,32 @@
+@font-face {
+ font-family: "iconfont";
src: url('/static/iconfont/iconfont.ttf') format('truetype');
+}
+
+.iconfont {
+ font-family: "iconfont" !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-qrcode:before {
+ content: "\e7dd";
+}
+
+.icon-dingdan:before {
+ content: "\e601";
+}
+
+.icon-product:before {
+ content: "\e788";
+}
+
+.icon-edit:before {
+ content: "\e621";
+}
+
+.icon-filter:before {
+ content: "\e6b9";
+}
+
diff --git a/static/iconfont/iconfont.ttf b/static/iconfont/iconfont.ttf
new file mode 100644
index 0000000..9db285d
Binary files /dev/null and b/static/iconfont/iconfont.ttf differ
diff --git a/static/image/arrow-down.png b/static/image/arrow-down.png
new file mode 100644
index 0000000..1369211
Binary files /dev/null and b/static/image/arrow-down.png differ
diff --git a/static/image/avatar.png b/static/image/avatar.png
new file mode 100644
index 0000000..2b5ca9f
Binary files /dev/null and b/static/image/avatar.png differ
diff --git a/static/image/index/index1.png b/static/image/index/index1.png
new file mode 100644
index 0000000..bdbfa67
Binary files /dev/null and b/static/image/index/index1.png differ
diff --git a/static/image/index/index10.png b/static/image/index/index10.png
new file mode 100644
index 0000000..319f962
Binary files /dev/null and b/static/image/index/index10.png differ
diff --git a/static/image/index/index2.png b/static/image/index/index2.png
new file mode 100644
index 0000000..1f007f4
Binary files /dev/null and b/static/image/index/index2.png differ
diff --git a/static/image/index/index3.png b/static/image/index/index3.png
new file mode 100644
index 0000000..a4024d1
Binary files /dev/null and b/static/image/index/index3.png differ
diff --git a/static/image/index/index4.png b/static/image/index/index4.png
new file mode 100644
index 0000000..f7ca20f
Binary files /dev/null and b/static/image/index/index4.png differ
diff --git a/static/image/index/index5.png b/static/image/index/index5.png
new file mode 100644
index 0000000..79c9e17
Binary files /dev/null and b/static/image/index/index5.png differ
diff --git a/static/image/index/index6.png b/static/image/index/index6.png
new file mode 100644
index 0000000..25ac8e3
Binary files /dev/null and b/static/image/index/index6.png differ
diff --git a/static/image/index/index7.png b/static/image/index/index7.png
new file mode 100644
index 0000000..d311da3
Binary files /dev/null and b/static/image/index/index7.png differ
diff --git a/static/image/index/index8.png b/static/image/index/index8.png
new file mode 100644
index 0000000..287d752
Binary files /dev/null and b/static/image/index/index8.png differ
diff --git a/static/image/index/index9.png b/static/image/index/index9.png
new file mode 100644
index 0000000..ea874ec
Binary files /dev/null and b/static/image/index/index9.png differ
diff --git a/static/image/login1.png b/static/image/login1.png
new file mode 100644
index 0000000..49f7dc1
Binary files /dev/null and b/static/image/login1.png differ
diff --git a/static/image/login2.png b/static/image/login2.png
new file mode 100644
index 0000000..4ecad29
Binary files /dev/null and b/static/image/login2.png differ
diff --git a/static/image/logo.png b/static/image/logo.png
new file mode 100644
index 0000000..e212cde
Binary files /dev/null and b/static/image/logo.png differ
diff --git a/static/image/none.png b/static/image/none.png
new file mode 100644
index 0000000..66d55dd
Binary files /dev/null and b/static/image/none.png differ
diff --git a/static/image/person-bg.png b/static/image/person-bg.png
new file mode 100644
index 0000000..73c9a96
Binary files /dev/null and b/static/image/person-bg.png differ
diff --git a/static/image/person1.png b/static/image/person1.png
new file mode 100644
index 0000000..ecb9ac8
Binary files /dev/null and b/static/image/person1.png differ
diff --git a/static/image/person2.png b/static/image/person2.png
new file mode 100644
index 0000000..53f90c2
Binary files /dev/null and b/static/image/person2.png differ
diff --git a/static/image/person3.png b/static/image/person3.png
new file mode 100644
index 0000000..926aaea
Binary files /dev/null and b/static/image/person3.png differ
diff --git a/static/image/person4.png b/static/image/person4.png
new file mode 100644
index 0000000..84b1d54
Binary files /dev/null and b/static/image/person4.png differ
diff --git a/static/image/phone.png b/static/image/phone.png
new file mode 100644
index 0000000..e425841
Binary files /dev/null and b/static/image/phone.png differ
diff --git a/static/image/qrcode.png b/static/image/qrcode.png
new file mode 100644
index 0000000..8654e2c
Binary files /dev/null and b/static/image/qrcode.png differ
diff --git a/static/image/school.png b/static/image/school.png
new file mode 100644
index 0000000..93ce55d
Binary files /dev/null and b/static/image/school.png differ
diff --git a/static/image/tab1-1.png b/static/image/tab1-1.png
new file mode 100644
index 0000000..15a11f7
Binary files /dev/null and b/static/image/tab1-1.png differ
diff --git a/static/image/tab1.png b/static/image/tab1.png
new file mode 100644
index 0000000..8fe1a19
Binary files /dev/null and b/static/image/tab1.png differ
diff --git a/static/image/tab2-1.png b/static/image/tab2-1.png
new file mode 100644
index 0000000..f025de2
Binary files /dev/null and b/static/image/tab2-1.png differ
diff --git a/static/image/tab2.png b/static/image/tab2.png
new file mode 100644
index 0000000..7b4f739
Binary files /dev/null and b/static/image/tab2.png differ
diff --git a/static/image/tab3-1.png b/static/image/tab3-1.png
new file mode 100644
index 0000000..80644ff
Binary files /dev/null and b/static/image/tab3-1.png differ
diff --git a/static/image/tab3.png b/static/image/tab3.png
new file mode 100644
index 0000000..96461e7
Binary files /dev/null and b/static/image/tab3.png differ
diff --git a/static/image/trash.png b/static/image/trash.png
new file mode 100644
index 0000000..e8d109b
Binary files /dev/null and b/static/image/trash.png differ
diff --git a/static/image/wechat.png b/static/image/wechat.png
new file mode 100644
index 0000000..0527db1
Binary files /dev/null and b/static/image/wechat.png differ
diff --git a/styles/common.scss b/styles/common.scss
new file mode 100644
index 0000000..65f0dda
--- /dev/null
+++ b/styles/common.scss
@@ -0,0 +1,221 @@
+button[type=primary] {
+ background-color: #007eff;
+}
+page {
+ height: 100%;
+ background-color: #f5f5f5;
+}
+ul {
+ padding-left: 0;
+ li {
+ list-style: none;
+ }
+}
+.block {
+ padding: 0 24rpx;
+ margin: 20rpx 24rpx;
+ border-radius: 16rpx;
+ background-color: #fff;
+}
+.l-title {
+ display: flex;
+ align-items: center;
+ padding: 28rpx 0;
+ font-size: 28rpx;
+ color: #333;
+ &:before {
+ content: '';
+ width: 6rpx;
+ height: 28rpx;
+ margin-right: 12rpx;
+ vertical-align: middle;
+ background-color: #4876F9;
+ }
+}
+.filter {
+ display: flex;
+ align-items: center;
+ padding: 10rpx 30rpx 10rpx 10rpx;
+ background-color: #fff;
+ .search {
+ flex: 1;
+ }
+ .uni-searchbar__box {
+ height: 70rpx;
+ }
+ .sort {
+ margin: 0 20rpx 0 10rpx;
+ &:before {
+ content: '';
+ display: block;
+ margin-bottom: 5rpx;
+ border: 15rpx solid transparent;
+ border-bottom-color: #B9B9B9;
+ }
+ &:after {
+ content: '';
+ display: block;
+ border: 15rpx solid transparent;
+ border-top-color: #B9B9B9;
+ }
+ &.desc:before {
+ border-bottom-color: #007EFF;
+ }
+ &.asc:after {
+ border-top-color: #007EFF;
+ }
+ }
+}
+.form-list {
+ border-top: 1px solid #E6E8ED;
+ .line {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 28rpx 0;
+ border-bottom: 1px solid #E6E8ED;
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+ .ph {
+ font-size: 28rpx;
+ color: #999;
+ }
+ .name, .val, input {
+ font-size: 28rpx;
+ color: #333;
+ }
+ input {
+ flex: 1;
+ margin-left: 20rpx;
+ text-align: right;
+ }
+ .req {
+ .name:after {
+ content: '*';
+ margin-left: 6rpx;
+ color: #F53232;
+ vertical-align: middle;
+ }
+ }
+ .err {
+ .name {
+ color: #f00;
+ }
+ }
+ .inline {
+ display: inline-flex;
+ align-items: center;
+ @extend input;
+ input {
+ margin-right: 10rpx;
+ }
+ }
+}
+.picker-input .input-value-border {
+ line-height: 1;
+ border: 0;
+}
+.tab {
+ display: flex;
+ justify-content: space-around;
+ margin-bottom: 20rpx;
+ background-color: #fff;
+ li {
+ padding: 0 20rpx;
+ font-size: 28rpx;
+ line-height: 100rpx;
+ border-bottom: 3px solid transparent;
+ }
+ .active {
+ color: $uni-primary;
+ border-bottom-color: $uni-primary;
+ }
+}
+.plus {
+ position: fixed;
+ bottom: 40rpx;
+ right: 40rpx;
+}
+
+.popup-mask {
+ z-index: 9;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background-color: rgba(0, 0, 0, .5);
+}
+.popup {
+ z-index: 10;
+ position: fixed;
+ bottom: 0%;
+ width: 100%;
+ height: 90vh;
+ background-color: #fff;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+ .top {
+ text-align: center;
+ line-height: 100rpx;
+ font-size: 28rpx;
+ color: #333;
+ border-bottom: 1px solid #f1f1f1;
+ }
+ .close {
+ position: absolute;
+ top: 30rpx;
+ right: 30rpx;
+ }
+ .list {
+ max-height: calc(90vh - 206rpx);
+ padding: 0 30rpx;
+ overflow: auto;
+ .item {
+ line-height: 80rpx;
+ font-size: 24rpx;
+ }
+ }
+}
+.btn-wrap {
+ z-index: 10;
+ position: fixed;
+ bottom: env(safe-area-inset-bottom);
+ bottom: 0;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ width: 100%;
+ padding: 20rpx 24rpx 20rpx 40rpx;
+ background-color: #fff;
+ box-shadow: 0px 0px 7rpx 0px rgba(203, 203, 203, 0.55);
+ box-sizing: border-box;
+ .btn {
+ width: 100%;
+ line-height: 80rpx;
+ font-size: 30rpx;
+ text-align: center;
+ color: #fff;
+ border-radius: 10rpx;
+ background-color: #007EFF;
+ }
+}
+.per-mask {
+ z-index: 3;
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ font-size: 28rpx;
+ color: #333;
+ background-color: rgba(255, 255, 255, 0.95);
+ -webkit-user-drag: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
\ No newline at end of file
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..0bbb54a
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,3 @@
+@import '@/uni_modules/uni-scss/variables.scss';
+@import '@/styles/common.scss';
+@import '@/static/iconfont/iconfont.css';
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/changelog.md b/uni_modules/Sansnn-uQRCode/changelog.md
new file mode 100644
index 0000000..de28dde
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/changelog.md
@@ -0,0 +1,44 @@
+## 3.2.2(2022-05-12)
+3.2.2
+
+修复vue3引入js报错问题;
+增加draw可选项,可在每一阶段绘制前后扩展自定义方法,详见文档draw(options);
+其他优化。
+## 3.2.1(2022-05-09)
+3.2.1
+
+已实现导入临时文件方法`toTempFilePath`;
+已实现保存二维码到本地或相册方法`save`;
+已实现生成完成回调事件`complete`;
+文档补充。
+## 3.2.0(2022-05-07)
+3.2.0
+
+适用所有支持canvas的前端应用和Node.js服务端;
+微信小程序端切换为canvas2d;
+支持绘制背景图片和前景图片,也就是说可以绘制背景和logo了;
+支持对定位角进行样式设置;
+支持对分割图案进行样式设置;
+支持对对齐图案进行样式设置;
+支持对时序图案进行样式设置;
+支持对暗块进行样式设置;
+支持对版本信息进行样式设置;
+解决小块之间出现白线问题。
+## 3.0.1(2022-01-05)
+3.0.1 gcanvas引用目录调整。
+## 3.0.0(2022-01-04)
+3.0.0 uQRCode 3.0 全新版本来袭。
+## 2.0.4(2021-11-19)
+2.0.4 新增绘制模式;新增绘制延时、canvas导入文件延时属性。
+## 2.0.3(2021-10-18)
+2.0.3 修复在部分安卓设备生成异常;移除延迟绘制;新增批量生成示例。
+## 2.0.23(2021-08-09)
+
+## 2.0.22(2021-08-09)
+
+## 2.0.21(2021-07-28)
+
+## 2.0.2(2021-07-28)
+2.0.2 新增延迟绘制。
+## 2.0.1(2021-07-26)
+2.0.1 调整为uni_modules目录规范。
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/bridge/bridge-weex.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/bridge/bridge-weex.js
new file mode 100644
index 0000000..27086ec
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/bridge/bridge-weex.js
@@ -0,0 +1,241 @@
+const isWeex = typeof WXEnvironment !== 'undefined';
+const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
+const isWeexAndroid = isWeex && !isWeexIOS;
+
+import GLmethod from '../context-webgl/GLmethod';
+
+const GCanvasModule =
+ (typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
+ (typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};
+
+let isDebugging = false;
+
+let isComboDisabled = false;
+
+const logCommand = (function () {
+ const methodQuery = [];
+ Object.keys(GLmethod).forEach(key => {
+ methodQuery[GLmethod[key]] = key;
+ })
+ const queryMethod = (id) => {
+ return methodQuery[parseInt(id)] || 'NotFoundMethod';
+ }
+ const logCommand = (id, cmds) => {
+ const mId = cmds.split(',')[0];
+ const mName = queryMethod(mId);
+ console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
+ }
+ return logCommand;
+})();
+
+function joinArray(arr, sep) {
+ let res = '';
+ for (let i = 0; i < arr.length; i++) {
+ if (i !== 0) {
+ res += sep;
+ }
+ res += arr[i];
+ }
+ return res;
+}
+
+const commandsCache = {}
+
+const GBridge = {
+
+ callEnable: (ref, configArray) => {
+
+ commandsCache[ref] = [];
+
+ return GCanvasModule.enable({
+ componentId: ref,
+ config: configArray
+ });
+ },
+
+ callEnableDebug: () => {
+ isDebugging = true;
+ },
+
+ callEnableDisableCombo: () => {
+ isComboDisabled = true;
+ },
+
+ callSetContextType: function (componentId, context_type) {
+ GCanvasModule.setContextType(context_type, componentId);
+ },
+
+ callReset: function(id){
+ GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
+ },
+
+ render: isWeexIOS ? function (componentId) {
+ return GCanvasModule.extendCallNative({
+ contextId: componentId,
+ type: 0x60000001
+ });
+ } : function (componentId) {
+ return callGCanvasLinkNative(componentId, 0x60000001, 'render');
+ },
+
+ render2d: isWeexIOS ? function (componentId, commands, callback) {
+
+ if (isDebugging) {
+ console.log('>>> >>> render2d ===');
+ console.log('>>> commands: ' + commands);
+ }
+
+ GCanvasModule.render([commands, callback?true:false], componentId, callback);
+
+ } : function (componentId, commands,callback) {
+
+ if (isDebugging) {
+ console.log('>>> >>> render2d ===');
+ console.log('>>> commands: ' + commands);
+ }
+
+ callGCanvasLinkNative(componentId, 0x20000001, commands);
+ if(callback){
+ callback();
+ }
+ },
+
+ callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {
+
+ throw 'should not be here anymore ' + cmdArgs;
+
+ } : function (componentId, cmdArgs) {
+
+ throw 'should not be here anymore ' + cmdArgs;
+
+ },
+
+
+ flushNative: isWeexIOS ? function (componentId) {
+
+ const cmdArgs = joinArray(commandsCache[componentId], ';');
+ commandsCache[componentId] = [];
+
+ if (isDebugging) {
+ console.log('>>> >>> flush native ===');
+ console.log('>>> commands: ' + cmdArgs);
+ }
+
+ const result = GCanvasModule.extendCallNative({
+ "contextId": componentId,
+ "type": 0x60000000,
+ "args": cmdArgs
+ });
+
+ const res = result && result.result;
+
+ if (isDebugging) {
+ console.log('>>> result: ' + res);
+ }
+
+ return res;
+
+ } : function (componentId) {
+
+ const cmdArgs = joinArray(commandsCache[componentId], ';');
+ commandsCache[componentId] = [];
+
+ if (isDebugging) {
+ console.log('>>> >>> flush native ===');
+ console.log('>>> commands: ' + cmdArgs);
+ }
+
+ const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);
+
+ if (isDebugging) {
+ console.log('>>> result: ' + result);
+ }
+
+ return result;
+ },
+
+ callNative: function (componentId, cmdArgs, cache) {
+
+ if (isDebugging) {
+ logCommand(componentId, cmdArgs);
+ }
+
+ commandsCache[componentId].push(cmdArgs);
+
+ if (!cache || isComboDisabled) {
+ return GBridge.flushNative(componentId);
+ } else {
+ return undefined;
+ }
+ },
+
+ texImage2D(componentId, ...args) {
+ if (isWeexIOS) {
+ if (args.length === 6) {
+ const [target, level, internalformat, format, type, image] = args;
+ GBridge.callNative(
+ componentId,
+ GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
+ )
+ } else if (args.length === 9) {
+ const [target, level, internalformat, width, height, border, format, type, image] = args;
+ GBridge.callNative(
+ componentId,
+ GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
+ + format + ',' + type + ',' + (image ? image.src : 0)
+ )
+ }
+ } else if (isWeexAndroid) {
+ if (args.length === 6) {
+ const [target, level, internalformat, format, type, image] = args;
+ GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
+ } else if (args.length === 9) {
+ const [target, level, internalformat, width, height, border, format, type, image] = args;
+ GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
+ }
+ }
+ },
+
+ texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
+ if (isWeexIOS) {
+ if (arguments.length === 8) {
+ GBridge.callNative(
+ componentId,
+ GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
+ )
+ }
+ } else if (isWeexAndroid) {
+ GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
+ }
+ },
+
+ bindImageTexture(componentId, src, imageId) {
+ GCanvasModule.bindImageTexture([src, imageId], componentId);
+ },
+
+ perloadImage([url, id], callback) {
+ GCanvasModule.preLoadImage([url, id], function (image) {
+ image.url = url;
+ image.id = id;
+ callback(image);
+ });
+ },
+
+ measureText(text, fontStyle, componentId) {
+ return GCanvasModule.measureText([text, fontStyle], componentId);
+ },
+
+ getImageData (componentId, x, y, w, h, callback) {
+ GCanvasModule.getImageData([x, y,w,h],componentId,callback);
+ },
+
+ putImageData (componentId, data, x, y, w, h, callback) {
+ GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
+ },
+
+ toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){
+ GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
+ }
+}
+
+export default GBridge;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js
new file mode 100644
index 0000000..3e7f03a
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js
@@ -0,0 +1,18 @@
+class FillStyleLinearGradient {
+
+ constructor(x0, y0, x1, y1) {
+ this._start_pos = { _x: x0, _y: y0 };
+ this._end_pos = { _x: x1, _y: y1 };
+ this._stop_count = 0;
+ this._stops = [0, 0, 0, 0, 0];
+ }
+
+ addColorStop = function (pos, color) {
+ if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
+ this._stops[this._stop_count] = { _pos: pos, _color: color };
+ this._stop_count++;
+ }
+ }
+}
+
+export default FillStyleLinearGradient;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStylePattern.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStylePattern.js
new file mode 100644
index 0000000..6e4f646
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStylePattern.js
@@ -0,0 +1,8 @@
+class FillStylePattern {
+ constructor(img, pattern) {
+ this._style = pattern;
+ this._img = img;
+ }
+}
+
+export default FillStylePattern;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js
new file mode 100644
index 0000000..7790596
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js
@@ -0,0 +1,17 @@
+class FillStyleRadialGradient {
+ constructor(x0, y0, r0, x1, y1, r1) {
+ this._start_pos = { _x: x0, _y: y0, _r: r0 };
+ this._end_pos = { _x: x1, _y: y1, _r: r1 };
+ this._stop_count = 0;
+ this._stops = [0, 0, 0, 0, 0];
+ }
+
+ addColorStop(pos, color) {
+ if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
+ this._stops[this._stop_count] = { _pos: pos, _color: color };
+ this._stop_count++;
+ }
+ }
+}
+
+export default FillStyleRadialGradient;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/RenderingContext.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/RenderingContext.js
new file mode 100644
index 0000000..e6b8f48
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-2d/RenderingContext.js
@@ -0,0 +1,666 @@
+import FillStylePattern from './FillStylePattern';
+import FillStyleLinearGradient from './FillStyleLinearGradient';
+import FillStyleRadialGradient from './FillStyleRadialGradient';
+import GImage from '../env/image.js';
+import {
+ ArrayBufferToBase64,
+ Base64ToUint8ClampedArray
+} from '../env/tool.js';
+
+export default class CanvasRenderingContext2D {
+
+ _drawCommands = '';
+
+ _globalAlpha = 1.0;
+
+ _fillStyle = 'rgb(0,0,0)';
+ _strokeStyle = 'rgb(0,0,0)';
+
+ _lineWidth = 1;
+ _lineCap = 'butt';
+ _lineJoin = 'miter';
+
+ _miterLimit = 10;
+
+ _globalCompositeOperation = 'source-over';
+
+ _textAlign = 'start';
+ _textBaseline = 'alphabetic';
+
+ _font = '10px sans-serif';
+
+ _savedGlobalAlpha = [];
+
+ timer = null;
+ componentId = null;
+
+ _notCommitDrawImageCache = [];
+ _needRedrawImageCache = [];
+ _redrawCommands = '';
+ _autoSaveContext = true;
+ // _imageMap = new GHashMap();
+ // _textureMap = new GHashMap();
+
+ constructor() {
+ this.className = 'CanvasRenderingContext2D';
+ //this.save()
+ }
+
+ setFillStyle(value) {
+ this.fillStyle = value;
+ }
+
+ set fillStyle(value) {
+ this._fillStyle = value;
+
+ if (typeof(value) == 'string') {
+ this._drawCommands = this._drawCommands.concat("F" + value + ";");
+ } else if (value instanceof FillStylePattern) {
+ const image = value._img;
+ if (!image.complete) {
+ image.onload = () => {
+ var index = this._needRedrawImageCache.indexOf(image);
+ if (index > -1) {
+ this._needRedrawImageCache.splice(index, 1);
+ CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ this._redrawflush(true);
+ }
+ }
+ this._notCommitDrawImageCache.push(image);
+ } else {
+ CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ }
+
+ //CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
+ } else if (value instanceof FillStyleLinearGradient) {
+ var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
+ value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
+ value._stop_count;
+ for (var i = 0; i < value._stop_count; ++i) {
+ command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+ }
+ this._drawCommands = this._drawCommands.concat(command + ";");
+ } else if (value instanceof FillStyleRadialGradient) {
+ var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
+ .toFixed(2) + "," +
+ value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
+ value._stop_count;
+ for (var i = 0; i < value._stop_count; ++i) {
+ command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+ }
+ this._drawCommands = this._drawCommands.concat(command + ";");
+ }
+ }
+
+ get fillStyle() {
+ return this._fillStyle;
+ }
+
+ get globalAlpha() {
+ return this._globalAlpha;
+ }
+
+ setGlobalAlpha(value) {
+ this.globalAlpha = value;
+ }
+
+ set globalAlpha(value) {
+ this._globalAlpha = value;
+ this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
+ }
+
+
+ get strokeStyle() {
+ return this._strokeStyle;
+ }
+
+ setStrokeStyle(value) {
+ this.strokeStyle = value;
+ }
+
+ set strokeStyle(value) {
+
+ this._strokeStyle = value;
+
+ if (typeof(value) == 'string') {
+ this._drawCommands = this._drawCommands.concat("S" + value + ";");
+ } else if (value instanceof FillStylePattern) {
+ CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
+ } else if (value instanceof FillStyleLinearGradient) {
+ var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
+ value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
+ value._stop_count;
+
+ for (var i = 0; i < value._stop_count; ++i) {
+ command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+ }
+ this._drawCommands = this._drawCommands.concat(command + ";");
+ } else if (value instanceof FillStyleRadialGradient) {
+ var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
+ .toFixed(2) + "," +
+ value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
+ value._stop_count;
+
+ for (var i = 0; i < value._stop_count; ++i) {
+ command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+ }
+ this._drawCommands = this._drawCommands.concat(command + ";");
+ }
+ }
+
+ get lineWidth() {
+ return this._lineWidth;
+ }
+
+ setLineWidth(value) {
+ this.lineWidth = value;
+ }
+
+ set lineWidth(value) {
+ this._lineWidth = value;
+ this._drawCommands = this._drawCommands.concat("W" + value + ";");
+ }
+
+ get lineCap() {
+ return this._lineCap;
+ }
+
+ setLineCap(value) {
+ this.lineCap = value;
+ }
+
+ set lineCap(value) {
+ this._lineCap = value;
+ this._drawCommands = this._drawCommands.concat("C" + value + ";");
+ }
+
+ get lineJoin() {
+ return this._lineJoin;
+ }
+
+ setLineJoin(value) {
+ this.lineJoin = value
+ }
+
+ set lineJoin(value) {
+ this._lineJoin = value;
+ this._drawCommands = this._drawCommands.concat("J" + value + ";");
+ }
+
+ get miterLimit() {
+ return this._miterLimit;
+ }
+
+ setMiterLimit(value) {
+ this.miterLimit = value
+ }
+
+ set miterLimit(value) {
+ this._miterLimit = value;
+ this._drawCommands = this._drawCommands.concat("M" + value + ";");
+ }
+
+ get globalCompositeOperation() {
+ return this._globalCompositeOperation;
+ }
+
+ set globalCompositeOperation(value) {
+
+ this._globalCompositeOperation = value;
+ let mode = 0;
+ switch (value) {
+ case "source-over":
+ mode = 0;
+ break;
+ case "source-atop":
+ mode = 5;
+ break;
+ case "source-in":
+ mode = 0;
+ break;
+ case "source-out":
+ mode = 2;
+ break;
+ case "destination-over":
+ mode = 4;
+ break;
+ case "destination-atop":
+ mode = 4;
+ break;
+ case "destination-in":
+ mode = 4;
+ break;
+ case "destination-out":
+ mode = 3;
+ break;
+ case "lighter":
+ mode = 1;
+ break;
+ case "copy":
+ mode = 2;
+ break;
+ case "xor":
+ mode = 6;
+ break;
+ default:
+ mode = 0;
+ }
+
+ this._drawCommands = this._drawCommands.concat("B" + mode + ";");
+ }
+
+ get textAlign() {
+ return this._textAlign;
+ }
+
+ setTextAlign(value) {
+ this.textAlign = value
+ }
+
+ set textAlign(value) {
+
+ this._textAlign = value;
+ let Align = 0;
+ switch (value) {
+ case "start":
+ Align = 0;
+ break;
+ case "end":
+ Align = 1;
+ break;
+ case "left":
+ Align = 2;
+ break;
+ case "center":
+ Align = 3;
+ break;
+ case "right":
+ Align = 4;
+ break;
+ default:
+ Align = 0;
+ }
+
+ this._drawCommands = this._drawCommands.concat("A" + Align + ";");
+ }
+
+ get textBaseline() {
+ return this._textBaseline;
+ }
+
+ setTextBaseline(value) {
+ this.textBaseline = value
+ }
+
+ set textBaseline(value) {
+ this._textBaseline = value;
+ let baseline = 0;
+ switch (value) {
+ case "alphabetic":
+ baseline = 0;
+ break;
+ case "middle":
+ baseline = 1;
+ break;
+ case "top":
+ baseline = 2;
+ break;
+ case "hanging":
+ baseline = 3;
+ break;
+ case "bottom":
+ baseline = 4;
+ break;
+ case "ideographic":
+ baseline = 5;
+ break;
+ default:
+ baseline = 0;
+ break;
+ }
+
+ this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
+ }
+
+ get font() {
+ return this._font;
+ }
+
+ setFontSize(size) {
+ var str = this._font;
+ var strs = str.trim().split(/\s+/);
+ for (var i = 0; i < strs.length; i++) {
+ var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
+ "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
+ "normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
+ "semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
+ ];
+
+ if (-1 == values.indexOf(strs[i].trim())) {
+ if (typeof size === 'string') {
+ strs[i] = size;
+ } else if (typeof size === 'number') {
+ strs[i] = String(size) + 'px';
+ }
+ break;
+ }
+ }
+ this.font = strs.join(" ");
+ }
+
+ set font(value) {
+ this._font = value;
+ this._drawCommands = this._drawCommands.concat("j" + value + ";");
+ }
+
+ setTransform(a, b, c, d, tx, ty) {
+ this._drawCommands = this._drawCommands.concat("t" +
+ (a === 1 ? "1" : a.toFixed(2)) + "," +
+ (b === 0 ? "0" : b.toFixed(2)) + "," +
+ (c === 0 ? "0" : c.toFixed(2)) + "," +
+ (d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
+ }
+
+ transform(a, b, c, d, tx, ty) {
+ this._drawCommands = this._drawCommands.concat("f" +
+ (a === 1 ? "1" : a.toFixed(2)) + "," +
+ (b === 0 ? "0" : b.toFixed(2)) + "," +
+ (c === 0 ? "0" : c.toFixed(2)) + "," +
+ (d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
+ }
+
+ resetTransform() {
+ this._drawCommands = this._drawCommands.concat("m;");
+ }
+
+ scale(a, d) {
+ this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
+ d.toFixed(2) + ";");
+ }
+
+ rotate(angle) {
+ this._drawCommands = this._drawCommands
+ .concat("r" + angle.toFixed(6) + ";");
+ }
+
+ translate(tx, ty) {
+ this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
+ }
+
+ save() {
+ this._savedGlobalAlpha.push(this._globalAlpha);
+ this._drawCommands = this._drawCommands.concat("v;");
+ }
+
+ restore() {
+ this._drawCommands = this._drawCommands.concat("e;");
+ this._globalAlpha = this._savedGlobalAlpha.pop();
+ }
+
+ createPattern(img, pattern) {
+ if (typeof img === 'string') {
+ var imgObj = new GImage();
+ imgObj.src = img;
+ img = imgObj;
+ }
+ return new FillStylePattern(img, pattern);
+ }
+
+ createLinearGradient(x0, y0, x1, y1) {
+ return new FillStyleLinearGradient(x0, y0, x1, y1);
+ }
+
+ createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
+ return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
+ };
+
+ createCircularGradient = function(x0, y0, r0) {
+ return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
+ };
+
+ strokeRect(x, y, w, h) {
+ this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
+ }
+
+
+ clearRect(x, y, w, h) {
+ this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
+ "," + h + ";");
+ }
+
+ clip() {
+ this._drawCommands = this._drawCommands.concat("p;");
+ }
+
+ resetClip() {
+ this._drawCommands = this._drawCommands.concat("q;");
+ }
+
+ closePath() {
+ this._drawCommands = this._drawCommands.concat("o;");
+ }
+
+ moveTo(x, y) {
+ this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
+ }
+
+ lineTo(x, y) {
+ this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
+ }
+
+ quadraticCurveTo = function(cpx, cpy, x, y) {
+ this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
+ }
+
+ bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
+ this._drawCommands = this._drawCommands.concat(
+ "z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
+ x.toFixed(2) + "," + y.toFixed(2) + ";");
+ }
+
+ arcTo(x1, y1, x2, y2, radius) {
+ this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
+ }
+
+ beginPath() {
+ this._drawCommands = this._drawCommands.concat("b;");
+ }
+
+
+ fillRect(x, y, w, h) {
+ this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
+ "," + h + ";");
+ }
+
+ rect(x, y, w, h) {
+ this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
+ }
+
+ fill() {
+ this._drawCommands = this._drawCommands.concat("L;");
+ }
+
+ stroke(path) {
+ this._drawCommands = this._drawCommands.concat("x;");
+ }
+
+ arc(x, y, radius, startAngle, endAngle, anticlockwise) {
+
+ let ianticlockwise = 0;
+ if (anticlockwise) {
+ ianticlockwise = 1;
+ }
+
+ this._drawCommands = this._drawCommands.concat(
+ "y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
+ radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
+ ";"
+ );
+ }
+
+ fillText(text, x, y) {
+ let tmptext = text.replace(/!/g, "!!");
+ tmptext = tmptext.replace(/,/g, "!,");
+ tmptext = tmptext.replace(/;/g, "!;");
+ this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
+ }
+
+ strokeText = function(text, x, y) {
+ let tmptext = text.replace(/!/g, "!!");
+ tmptext = tmptext.replace(/,/g, "!,");
+ tmptext = tmptext.replace(/;/g, "!;");
+ this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
+ }
+
+ measureText(text) {
+ return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
+ }
+
+ isPointInPath = function(x, y) {
+ throw new Error('GCanvas not supported yet');
+ }
+
+ drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
+ if (typeof image === 'string') {
+ var imgObj = new GImage();
+ imgObj.src = image;
+ image = imgObj;
+ }
+ if (image instanceof GImage) {
+ if (!image.complete) {
+ imgObj.onload = () => {
+ var index = this._needRedrawImageCache.indexOf(image);
+ if (index > -1) {
+ this._needRedrawImageCache.splice(index, 1);
+ CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ this._redrawflush(true);
+ }
+ }
+ this._notCommitDrawImageCache.push(image);
+ } else {
+ CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+ }
+ var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
+ var args = [];
+ for (var arg in srcArgs) {
+ if (typeof(srcArgs[arg]) != 'undefined') {
+ args.push(srcArgs[arg]);
+ }
+ }
+ this.__drawImage.apply(this, args);
+ //this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
+ }
+ }
+
+ __drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
+ const numArgs = arguments.length;
+
+ function drawImageCommands() {
+
+ if (numArgs === 3) {
+ const x = parseFloat(sx) || 0.0;
+ const y = parseFloat(sy) || 0.0;
+
+ return ("d" + image._id + ",0,0," +
+ image.width + "," + image.height + "," +
+ x + "," + y + "," + image.width + "," + image.height + ";");
+ } else if (numArgs === 5) {
+ const x = parseFloat(sx) || 0.0;
+ const y = parseFloat(sy) || 0.0;
+ const width = parseInt(sw) || image.width;
+ const height = parseInt(sh) || image.height;
+
+ return ("d" + image._id + ",0,0," +
+ image.width + "," + image.height + "," +
+ x + "," + y + "," + width + "," + height + ";");
+ } else if (numArgs === 9) {
+ sx = parseFloat(sx) || 0.0;
+ sy = parseFloat(sy) || 0.0;
+ sw = parseInt(sw) || image.width;
+ sh = parseInt(sh) || image.height;
+ dx = parseFloat(dx) || 0.0;
+ dy = parseFloat(dy) || 0.0;
+ dw = parseInt(dw) || image.width;
+ dh = parseInt(dh) || image.height;
+
+ return ("d" + image._id + "," +
+ sx + "," + sy + "," + sw + "," + sh + "," +
+ dx + "," + dy + "," + dw + "," + dh + ";");
+ }
+ }
+ this._drawCommands += drawImageCommands();
+ }
+
+ _flush(reserve, callback) {
+ const commands = this._drawCommands;
+ this._drawCommands = '';
+ CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
+ this._needRender = false;
+ }
+
+ _redrawflush(reserve, callback) {
+ const commands = this._redrawCommands;
+ CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
+ if (this._needRedrawImageCache.length == 0) {
+ this._redrawCommands = '';
+ }
+ }
+
+ draw(reserve, callback) {
+ if (!reserve) {
+ this._globalAlpha = this._savedGlobalAlpha.pop();
+ this._savedGlobalAlpha.push(this._globalAlpha);
+ this._redrawCommands = this._drawCommands;
+ this._needRedrawImageCache = this._notCommitDrawImageCache;
+ if (this._autoSaveContext) {
+ this._drawCommands = ("v;" + this._drawCommands);
+ this._autoSaveContext = false;
+ } else {
+ this._drawCommands = ("e;X;v;" + this._drawCommands);
+ }
+ } else {
+ this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
+ this._redrawCommands += this._drawCommands;
+ if (this._autoSaveContext) {
+ this._drawCommands = ("v;" + this._drawCommands);
+ this._autoSaveContext = false;
+ }
+ }
+ this._notCommitDrawImageCache = [];
+ if (this._flush) {
+ this._flush(reserve, callback);
+ }
+ }
+
+ getImageData(x, y, w, h, callback) {
+ CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
+ res.data = Base64ToUint8ClampedArray(res.data);
+ if (typeof(callback) == 'function') {
+ callback(res);
+ }
+ });
+ }
+
+ putImageData(data, x, y, w, h, callback) {
+ if (data instanceof Uint8ClampedArray) {
+ data = ArrayBufferToBase64(data);
+ CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
+ if (typeof(callback) == 'function') {
+ callback(res);
+ }
+ });
+ }
+ }
+
+ toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
+ CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
+ fileType, quality,
+ function(res) {
+ if (typeof(callback) == 'function') {
+ callback(res);
+ }
+ });
+ }
+}
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ActiveInfo.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ActiveInfo.js
new file mode 100644
index 0000000..b495129
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ActiveInfo.js
@@ -0,0 +1,11 @@
+export default class WebGLActiveInfo {
+ className = 'WebGLActiveInfo';
+
+ constructor({
+ type, name, size
+ }) {
+ this.type = type;
+ this.name = name;
+ this.size = size;
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Buffer.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Buffer.js
new file mode 100644
index 0000000..4800f67
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Buffer.js
@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLBuffer';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLBuffer {
+ className = name;
+
+ constructor(id) {
+ this.id = id;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Framebuffer.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Framebuffer.js
new file mode 100644
index 0000000..28b46d3
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Framebuffer.js
@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLFrameBuffer';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLFramebuffer {
+ className = name;
+
+ constructor(id) {
+ this.id = id;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLenum.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLenum.js
new file mode 100644
index 0000000..ac5544d
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLenum.js
@@ -0,0 +1,298 @@
+export default {
+ "DEPTH_BUFFER_BIT": 256,
+ "STENCIL_BUFFER_BIT": 1024,
+ "COLOR_BUFFER_BIT": 16384,
+ "POINTS": 0,
+ "LINES": 1,
+ "LINE_LOOP": 2,
+ "LINE_STRIP": 3,
+ "TRIANGLES": 4,
+ "TRIANGLE_STRIP": 5,
+ "TRIANGLE_FAN": 6,
+ "ZERO": 0,
+ "ONE": 1,
+ "SRC_COLOR": 768,
+ "ONE_MINUS_SRC_COLOR": 769,
+ "SRC_ALPHA": 770,
+ "ONE_MINUS_SRC_ALPHA": 771,
+ "DST_ALPHA": 772,
+ "ONE_MINUS_DST_ALPHA": 773,
+ "DST_COLOR": 774,
+ "ONE_MINUS_DST_COLOR": 775,
+ "SRC_ALPHA_SATURATE": 776,
+ "FUNC_ADD": 32774,
+ "BLEND_EQUATION": 32777,
+ "BLEND_EQUATION_RGB": 32777,
+ "BLEND_EQUATION_ALPHA": 34877,
+ "FUNC_SUBTRACT": 32778,
+ "FUNC_REVERSE_SUBTRACT": 32779,
+ "BLEND_DST_RGB": 32968,
+ "BLEND_SRC_RGB": 32969,
+ "BLEND_DST_ALPHA": 32970,
+ "BLEND_SRC_ALPHA": 32971,
+ "CONSTANT_COLOR": 32769,
+ "ONE_MINUS_CONSTANT_COLOR": 32770,
+ "CONSTANT_ALPHA": 32771,
+ "ONE_MINUS_CONSTANT_ALPHA": 32772,
+ "BLEND_COLOR": 32773,
+ "ARRAY_BUFFER": 34962,
+ "ELEMENT_ARRAY_BUFFER": 34963,
+ "ARRAY_BUFFER_BINDING": 34964,
+ "ELEMENT_ARRAY_BUFFER_BINDING": 34965,
+ "STREAM_DRAW": 35040,
+ "STATIC_DRAW": 35044,
+ "DYNAMIC_DRAW": 35048,
+ "BUFFER_SIZE": 34660,
+ "BUFFER_USAGE": 34661,
+ "CURRENT_VERTEX_ATTRIB": 34342,
+ "FRONT": 1028,
+ "BACK": 1029,
+ "FRONT_AND_BACK": 1032,
+ "TEXTURE_2D": 3553,
+ "CULL_FACE": 2884,
+ "BLEND": 3042,
+ "DITHER": 3024,
+ "STENCIL_TEST": 2960,
+ "DEPTH_TEST": 2929,
+ "SCISSOR_TEST": 3089,
+ "POLYGON_OFFSET_FILL": 32823,
+ "SAMPLE_ALPHA_TO_COVERAGE": 32926,
+ "SAMPLE_COVERAGE": 32928,
+ "NO_ERROR": 0,
+ "INVALID_ENUM": 1280,
+ "INVALID_VALUE": 1281,
+ "INVALID_OPERATION": 1282,
+ "OUT_OF_MEMORY": 1285,
+ "CW": 2304,
+ "CCW": 2305,
+ "LINE_WIDTH": 2849,
+ "ALIASED_POINT_SIZE_RANGE": 33901,
+ "ALIASED_LINE_WIDTH_RANGE": 33902,
+ "CULL_FACE_MODE": 2885,
+ "FRONT_FACE": 2886,
+ "DEPTH_RANGE": 2928,
+ "DEPTH_WRITEMASK": 2930,
+ "DEPTH_CLEAR_VALUE": 2931,
+ "DEPTH_FUNC": 2932,
+ "STENCIL_CLEAR_VALUE": 2961,
+ "STENCIL_FUNC": 2962,
+ "STENCIL_FAIL": 2964,
+ "STENCIL_PASS_DEPTH_FAIL": 2965,
+ "STENCIL_PASS_DEPTH_PASS": 2966,
+ "STENCIL_REF": 2967,
+ "STENCIL_VALUE_MASK": 2963,
+ "STENCIL_WRITEMASK": 2968,
+ "STENCIL_BACK_FUNC": 34816,
+ "STENCIL_BACK_FAIL": 34817,
+ "STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
+ "STENCIL_BACK_PASS_DEPTH_PASS": 34819,
+ "STENCIL_BACK_REF": 36003,
+ "STENCIL_BACK_VALUE_MASK": 36004,
+ "STENCIL_BACK_WRITEMASK": 36005,
+ "VIEWPORT": 2978,
+ "SCISSOR_BOX": 3088,
+ "COLOR_CLEAR_VALUE": 3106,
+ "COLOR_WRITEMASK": 3107,
+ "UNPACK_ALIGNMENT": 3317,
+ "PACK_ALIGNMENT": 3333,
+ "MAX_TEXTURE_SIZE": 3379,
+ "MAX_VIEWPORT_DIMS": 3386,
+ "SUBPIXEL_BITS": 3408,
+ "RED_BITS": 3410,
+ "GREEN_BITS": 3411,
+ "BLUE_BITS": 3412,
+ "ALPHA_BITS": 3413,
+ "DEPTH_BITS": 3414,
+ "STENCIL_BITS": 3415,
+ "POLYGON_OFFSET_UNITS": 10752,
+ "POLYGON_OFFSET_FACTOR": 32824,
+ "TEXTURE_BINDING_2D": 32873,
+ "SAMPLE_BUFFERS": 32936,
+ "SAMPLES": 32937,
+ "SAMPLE_COVERAGE_VALUE": 32938,
+ "SAMPLE_COVERAGE_INVERT": 32939,
+ "COMPRESSED_TEXTURE_FORMATS": 34467,
+ "DONT_CARE": 4352,
+ "FASTEST": 4353,
+ "NICEST": 4354,
+ "GENERATE_MIPMAP_HINT": 33170,
+ "BYTE": 5120,
+ "UNSIGNED_BYTE": 5121,
+ "SHORT": 5122,
+ "UNSIGNED_SHORT": 5123,
+ "INT": 5124,
+ "UNSIGNED_INT": 5125,
+ "FLOAT": 5126,
+ "DEPTH_COMPONENT": 6402,
+ "ALPHA": 6406,
+ "RGB": 6407,
+ "RGBA": 6408,
+ "LUMINANCE": 6409,
+ "LUMINANCE_ALPHA": 6410,
+ "UNSIGNED_SHORT_4_4_4_4": 32819,
+ "UNSIGNED_SHORT_5_5_5_1": 32820,
+ "UNSIGNED_SHORT_5_6_5": 33635,
+ "FRAGMENT_SHADER": 35632,
+ "VERTEX_SHADER": 35633,
+ "MAX_VERTEX_ATTRIBS": 34921,
+ "MAX_VERTEX_UNIFORM_VECTORS": 36347,
+ "MAX_VARYING_VECTORS": 36348,
+ "MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
+ "MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
+ "MAX_TEXTURE_IMAGE_UNITS": 34930,
+ "MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
+ "SHADER_TYPE": 35663,
+ "DELETE_STATUS": 35712,
+ "LINK_STATUS": 35714,
+ "VALIDATE_STATUS": 35715,
+ "ATTACHED_SHADERS": 35717,
+ "ACTIVE_UNIFORMS": 35718,
+ "ACTIVE_ATTRIBUTES": 35721,
+ "SHADING_LANGUAGE_VERSION": 35724,
+ "CURRENT_PROGRAM": 35725,
+ "NEVER": 512,
+ "LESS": 513,
+ "EQUAL": 514,
+ "LEQUAL": 515,
+ "GREATER": 516,
+ "NOTEQUAL": 517,
+ "GEQUAL": 518,
+ "ALWAYS": 519,
+ "KEEP": 7680,
+ "REPLACE": 7681,
+ "INCR": 7682,
+ "DECR": 7683,
+ "INVERT": 5386,
+ "INCR_WRAP": 34055,
+ "DECR_WRAP": 34056,
+ "VENDOR": 7936,
+ "RENDERER": 7937,
+ "VERSION": 7938,
+ "NEAREST": 9728,
+ "LINEAR": 9729,
+ "NEAREST_MIPMAP_NEAREST": 9984,
+ "LINEAR_MIPMAP_NEAREST": 9985,
+ "NEAREST_MIPMAP_LINEAR": 9986,
+ "LINEAR_MIPMAP_LINEAR": 9987,
+ "TEXTURE_MAG_FILTER": 10240,
+ "TEXTURE_MIN_FILTER": 10241,
+ "TEXTURE_WRAP_S": 10242,
+ "TEXTURE_WRAP_T": 10243,
+ "TEXTURE": 5890,
+ "TEXTURE_CUBE_MAP": 34067,
+ "TEXTURE_BINDING_CUBE_MAP": 34068,
+ "TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
+ "TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
+ "TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
+ "TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
+ "TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
+ "TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
+ "MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
+ "TEXTURE0": 33984,
+ "TEXTURE1": 33985,
+ "TEXTURE2": 33986,
+ "TEXTURE3": 33987,
+ "TEXTURE4": 33988,
+ "TEXTURE5": 33989,
+ "TEXTURE6": 33990,
+ "TEXTURE7": 33991,
+ "TEXTURE8": 33992,
+ "TEXTURE9": 33993,
+ "TEXTURE10": 33994,
+ "TEXTURE11": 33995,
+ "TEXTURE12": 33996,
+ "TEXTURE13": 33997,
+ "TEXTURE14": 33998,
+ "TEXTURE15": 33999,
+ "TEXTURE16": 34000,
+ "TEXTURE17": 34001,
+ "TEXTURE18": 34002,
+ "TEXTURE19": 34003,
+ "TEXTURE20": 34004,
+ "TEXTURE21": 34005,
+ "TEXTURE22": 34006,
+ "TEXTURE23": 34007,
+ "TEXTURE24": 34008,
+ "TEXTURE25": 34009,
+ "TEXTURE26": 34010,
+ "TEXTURE27": 34011,
+ "TEXTURE28": 34012,
+ "TEXTURE29": 34013,
+ "TEXTURE30": 34014,
+ "TEXTURE31": 34015,
+ "ACTIVE_TEXTURE": 34016,
+ "REPEAT": 10497,
+ "CLAMP_TO_EDGE": 33071,
+ "MIRRORED_REPEAT": 33648,
+ "FLOAT_VEC2": 35664,
+ "FLOAT_VEC3": 35665,
+ "FLOAT_VEC4": 35666,
+ "INT_VEC2": 35667,
+ "INT_VEC3": 35668,
+ "INT_VEC4": 35669,
+ "BOOL": 35670,
+ "BOOL_VEC2": 35671,
+ "BOOL_VEC3": 35672,
+ "BOOL_VEC4": 35673,
+ "FLOAT_MAT2": 35674,
+ "FLOAT_MAT3": 35675,
+ "FLOAT_MAT4": 35676,
+ "SAMPLER_2D": 35678,
+ "SAMPLER_CUBE": 35680,
+ "VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
+ "VERTEX_ATTRIB_ARRAY_SIZE": 34339,
+ "VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
+ "VERTEX_ATTRIB_ARRAY_TYPE": 34341,
+ "VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
+ "VERTEX_ATTRIB_ARRAY_POINTER": 34373,
+ "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
+ "IMPLEMENTATION_COLOR_READ_TYPE": 35738,
+ "IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
+ "COMPILE_STATUS": 35713,
+ "LOW_FLOAT": 36336,
+ "MEDIUM_FLOAT": 36337,
+ "HIGH_FLOAT": 36338,
+ "LOW_INT": 36339,
+ "MEDIUM_INT": 36340,
+ "HIGH_INT": 36341,
+ "FRAMEBUFFER": 36160,
+ "RENDERBUFFER": 36161,
+ "RGBA4": 32854,
+ "RGB5_A1": 32855,
+ "RGB565": 36194,
+ "DEPTH_COMPONENT16": 33189,
+ "STENCIL_INDEX8": 36168,
+ "DEPTH_STENCIL": 34041,
+ "RENDERBUFFER_WIDTH": 36162,
+ "RENDERBUFFER_HEIGHT": 36163,
+ "RENDERBUFFER_INTERNAL_FORMAT": 36164,
+ "RENDERBUFFER_RED_SIZE": 36176,
+ "RENDERBUFFER_GREEN_SIZE": 36177,
+ "RENDERBUFFER_BLUE_SIZE": 36178,
+ "RENDERBUFFER_ALPHA_SIZE": 36179,
+ "RENDERBUFFER_DEPTH_SIZE": 36180,
+ "RENDERBUFFER_STENCIL_SIZE": 36181,
+ "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
+ "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
+ "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
+ "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
+ "COLOR_ATTACHMENT0": 36064,
+ "DEPTH_ATTACHMENT": 36096,
+ "STENCIL_ATTACHMENT": 36128,
+ "DEPTH_STENCIL_ATTACHMENT": 33306,
+ "NONE": 0,
+ "FRAMEBUFFER_COMPLETE": 36053,
+ "FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
+ "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
+ "FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
+ "FRAMEBUFFER_UNSUPPORTED": 36061,
+ "FRAMEBUFFER_BINDING": 36006,
+ "RENDERBUFFER_BINDING": 36007,
+ "MAX_RENDERBUFFER_SIZE": 34024,
+ "INVALID_FRAMEBUFFER_OPERATION": 1286,
+ "UNPACK_FLIP_Y_WEBGL": 37440,
+ "UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
+ "CONTEXT_LOST_WEBGL": 37442,
+ "UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
+ "BROWSER_DEFAULT_WEBGL": 37444
+};
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLmethod.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLmethod.js
new file mode 100644
index 0000000..f2659be
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLmethod.js
@@ -0,0 +1,142 @@
+let i = 1;
+
+const GLmethod = {};
+
+GLmethod.activeTexture = i++; //1
+GLmethod.attachShader = i++;
+GLmethod.bindAttribLocation = i++;
+GLmethod.bindBuffer = i++;
+GLmethod.bindFramebuffer = i++;
+GLmethod.bindRenderbuffer = i++;
+GLmethod.bindTexture = i++;
+GLmethod.blendColor = i++;
+GLmethod.blendEquation = i++;
+GLmethod.blendEquationSeparate = i++; //10
+GLmethod.blendFunc = i++;
+GLmethod.blendFuncSeparate = i++;
+GLmethod.bufferData = i++;
+GLmethod.bufferSubData = i++;
+GLmethod.checkFramebufferStatus = i++;
+GLmethod.clear = i++;
+GLmethod.clearColor = i++;
+GLmethod.clearDepth = i++;
+GLmethod.clearStencil = i++;
+GLmethod.colorMask = i++; //20
+GLmethod.compileShader = i++;
+GLmethod.compressedTexImage2D = i++;
+GLmethod.compressedTexSubImage2D = i++;
+GLmethod.copyTexImage2D = i++;
+GLmethod.copyTexSubImage2D = i++;
+GLmethod.createBuffer = i++;
+GLmethod.createFramebuffer = i++;
+GLmethod.createProgram = i++;
+GLmethod.createRenderbuffer = i++;
+GLmethod.createShader = i++; //30
+GLmethod.createTexture = i++;
+GLmethod.cullFace = i++;
+GLmethod.deleteBuffer = i++;
+GLmethod.deleteFramebuffer = i++;
+GLmethod.deleteProgram = i++;
+GLmethod.deleteRenderbuffer = i++;
+GLmethod.deleteShader = i++;
+GLmethod.deleteTexture = i++;
+GLmethod.depthFunc = i++;
+GLmethod.depthMask = i++; //40
+GLmethod.depthRange = i++;
+GLmethod.detachShader = i++;
+GLmethod.disable = i++;
+GLmethod.disableVertexAttribArray = i++;
+GLmethod.drawArrays = i++;
+GLmethod.drawArraysInstancedANGLE = i++;
+GLmethod.drawElements = i++;
+GLmethod.drawElementsInstancedANGLE = i++;
+GLmethod.enable = i++;
+GLmethod.enableVertexAttribArray = i++; //50
+GLmethod.flush = i++;
+GLmethod.framebufferRenderbuffer = i++;
+GLmethod.framebufferTexture2D = i++;
+GLmethod.frontFace = i++;
+GLmethod.generateMipmap = i++;
+GLmethod.getActiveAttrib = i++;
+GLmethod.getActiveUniform = i++;
+GLmethod.getAttachedShaders = i++;
+GLmethod.getAttribLocation = i++;
+GLmethod.getBufferParameter = i++; //60
+GLmethod.getContextAttributes = i++;
+GLmethod.getError = i++;
+GLmethod.getExtension = i++;
+GLmethod.getFramebufferAttachmentParameter = i++;
+GLmethod.getParameter = i++;
+GLmethod.getProgramInfoLog = i++;
+GLmethod.getProgramParameter = i++;
+GLmethod.getRenderbufferParameter = i++;
+GLmethod.getShaderInfoLog = i++;
+GLmethod.getShaderParameter = i++; //70
+GLmethod.getShaderPrecisionFormat = i++;
+GLmethod.getShaderSource = i++;
+GLmethod.getSupportedExtensions = i++;
+GLmethod.getTexParameter = i++;
+GLmethod.getUniform = i++;
+GLmethod.getUniformLocation = i++;
+GLmethod.getVertexAttrib = i++;
+GLmethod.getVertexAttribOffset = i++;
+GLmethod.isBuffer = i++;
+GLmethod.isContextLost = i++; //80
+GLmethod.isEnabled = i++;
+GLmethod.isFramebuffer = i++;
+GLmethod.isProgram = i++;
+GLmethod.isRenderbuffer = i++;
+GLmethod.isShader = i++;
+GLmethod.isTexture = i++;
+GLmethod.lineWidth = i++;
+GLmethod.linkProgram = i++;
+GLmethod.pixelStorei = i++;
+GLmethod.polygonOffset = i++; //90
+GLmethod.readPixels = i++;
+GLmethod.renderbufferStorage = i++;
+GLmethod.sampleCoverage = i++;
+GLmethod.scissor = i++;
+GLmethod.shaderSource = i++;
+GLmethod.stencilFunc = i++;
+GLmethod.stencilFuncSeparate = i++;
+GLmethod.stencilMask = i++;
+GLmethod.stencilMaskSeparate = i++;
+GLmethod.stencilOp = i++; //100
+GLmethod.stencilOpSeparate = i++;
+GLmethod.texImage2D = i++;
+GLmethod.texParameterf = i++;
+GLmethod.texParameteri = i++;
+GLmethod.texSubImage2D = i++;
+GLmethod.uniform1f = i++;
+GLmethod.uniform1fv = i++;
+GLmethod.uniform1i = i++;
+GLmethod.uniform1iv = i++;
+GLmethod.uniform2f = i++; //110
+GLmethod.uniform2fv = i++;
+GLmethod.uniform2i = i++;
+GLmethod.uniform2iv = i++;
+GLmethod.uniform3f = i++;
+GLmethod.uniform3fv = i++;
+GLmethod.uniform3i = i++;
+GLmethod.uniform3iv = i++;
+GLmethod.uniform4f = i++;
+GLmethod.uniform4fv = i++;
+GLmethod.uniform4i = i++; //120
+GLmethod.uniform4iv = i++;
+GLmethod.uniformMatrix2fv = i++;
+GLmethod.uniformMatrix3fv = i++;
+GLmethod.uniformMatrix4fv = i++;
+GLmethod.useProgram = i++;
+GLmethod.validateProgram = i++;
+GLmethod.vertexAttrib1f = i++; //new
+GLmethod.vertexAttrib2f = i++; //new
+GLmethod.vertexAttrib3f = i++; //new
+GLmethod.vertexAttrib4f = i++; //new //130
+GLmethod.vertexAttrib1fv = i++; //new
+GLmethod.vertexAttrib2fv = i++; //new
+GLmethod.vertexAttrib3fv = i++; //new
+GLmethod.vertexAttrib4fv = i++; //new
+GLmethod.vertexAttribPointer = i++;
+GLmethod.viewport = i++;
+
+export default GLmethod;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLtype.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLtype.js
new file mode 100644
index 0000000..695abcb
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/GLtype.js
@@ -0,0 +1,23 @@
+const GLtype = {};
+
+[
+ "GLbitfield",
+ "GLboolean",
+ "GLbyte",
+ "GLclampf",
+ "GLenum",
+ "GLfloat",
+ "GLint",
+ "GLintptr",
+ "GLsizei",
+ "GLsizeiptr",
+ "GLshort",
+ "GLubyte",
+ "GLuint",
+ "GLushort"
+].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));
+
+export default GLtype;
+
+
+
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Program.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Program.js
new file mode 100644
index 0000000..6f5691c
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Program.js
@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLProgram';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLProgram {
+ className = name;
+
+ constructor(id) {
+ this.id = id;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Renderbuffer.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Renderbuffer.js
new file mode 100644
index 0000000..d3182ae
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Renderbuffer.js
@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLRenderBuffer';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLRenderbuffer {
+ className = name;
+
+ constructor(id) {
+ this.id = id;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/RenderingContext.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/RenderingContext.js
new file mode 100644
index 0000000..5f9608f
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/RenderingContext.js
@@ -0,0 +1,1191 @@
+import GLenum from './GLenum';
+import ActiveInfo from './ActiveInfo';
+import Buffer from './Buffer';
+import Framebuffer from './Framebuffer';
+import Renderbuffer from './Renderbuffer';
+import Texture from './Texture';
+import Program from './Program';
+import Shader from './Shader';
+import ShaderPrecisionFormat from './ShaderPrecisionFormat';
+import UniformLocation from './UniformLocation';
+import GLmethod from './GLmethod';
+
+const processArray = (array, checkArrayType = false) => {
+
+ function joinArray(arr, sep) {
+ let res = '';
+ for (let i = 0; i < arr.length; i++) {
+ if (i !== 0) {
+ res += sep;
+ }
+ res += arr[i];
+ }
+ return res;
+ }
+
+ let type = 'Float32Array';
+ if (checkArrayType) {
+ if (array instanceof Uint8Array) {
+ type = 'Uint8Array'
+ } else if (array instanceof Uint16Array) {
+ type = 'Uint16Array';
+ } else if (array instanceof Uint32Array) {
+ type = 'Uint32Array';
+ } else if (array instanceof Float32Array) {
+ type = 'Float32Array';
+ } else {
+ throw new Error('Check array type failed. Array type is ' + typeof array);
+ }
+ }
+
+ const ArrayTypes = {
+ Uint8Array: 1,
+ Uint16Array: 2,
+ Uint32Array: 4,
+ Float32Array: 14
+ };
+ return ArrayTypes[type] + ',' + btoa(joinArray(array, ','))
+}
+
+export default class WebGLRenderingContext {
+
+ // static GBridge = null;
+
+ className = 'WebGLRenderingContext';
+
+ constructor(canvas, type, attrs) {
+ this._canvas = canvas;
+ this._type = type;
+ this._version = 'WebGL 1.0';
+ this._attrs = attrs;
+ this._map = new Map();
+
+ Object.keys(GLenum)
+ .forEach(name => Object.defineProperty(this, name, {
+ value: GLenum[name]
+ }));
+ }
+
+ get canvas() {
+ return this._canvas;
+ }
+
+ activeTexture = function (textureUnit) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.activeTexture + ',' + textureUnit,
+ true
+ );
+ }
+
+ attachShader = function (progarm, shader) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.attachShader + ',' + progarm.id + ',' + shader.id,
+ true
+ );
+ }
+
+ bindAttribLocation = function (program, index, name) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bindAttribLocation + ',' + program.id + ',' + index + ',' + name,
+ true
+ )
+ }
+
+ bindBuffer = function (target, buffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bindBuffer + ',' + target + ',' + (buffer ? buffer.id : 0),
+ true
+ );
+ }
+
+ bindFramebuffer = function (target, framebuffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bindFramebuffer + ',' + target + ',' + (framebuffer ? framebuffer.id : 0),
+ true
+ )
+ }
+
+ bindRenderbuffer = function (target, renderBuffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bindRenderbuffer + ',' + target + ',' + (renderBuffer ? renderBuffer.id : 0),
+ true
+ )
+ }
+
+ bindTexture = function (target, texture) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bindTexture + ',' + target + ',' + (texture ? texture.id : 0),
+ true
+ )
+ }
+
+ blendColor = function (r, g, b, a) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.blendColor + ',' + target + ',' + r + ',' + g + ',' + b + ',' + a,
+ true
+ )
+ }
+
+ blendEquation = function (mode) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.blendEquation + ',' + mode,
+ true
+ )
+ }
+
+ blendEquationSeparate = function (modeRGB, modeAlpha) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.blendEquationSeparate + ',' + modeRGB + ',' + modeAlpha,
+ true
+ )
+ }
+
+
+ blendFunc = function (sfactor, dfactor) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.blendFunc + ',' + sfactor + ',' + dfactor,
+ true
+ );
+ }
+
+ blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.blendFuncSeparate + ',' + srcRGB + ',' + dstRGB + ',' + srcAlpha + ',' + dstAlpha,
+ true
+ );
+ }
+
+ bufferData = function (target, data, usage) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bufferData + ',' + target + ',' + processArray(data, true) + ',' + usage,
+ true
+ )
+ }
+
+ bufferSubData = function (target, offset, data) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.bufferSubData + ',' + target + ',' + offset + ',' + processArray(data, true),
+ true
+ )
+ }
+
+ checkFramebufferStatus = function (target) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.checkFramebufferStatus + ',' + target
+ );
+ return Number(result);
+ }
+
+ clear = function (mask) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.clear + ',' + mask
+ );
+ this._canvas._needRender = true;
+ }
+
+ clearColor = function (r, g, b, a) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.clearColor + ',' + r + ',' + g + ',' + b,
+ true
+ )
+ }
+
+ clearDepth = function (depth) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.clearDepth + ',' + depth,
+ true
+ )
+ }
+
+ clearStencil = function (s) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.clearStencil + ',' + s
+ );
+ }
+
+ colorMask = function (r, g, b, a) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.colorMask + ',' + r + ',' + g + ',' + b + ',' + a
+ )
+ }
+
+ compileShader = function (shader) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.compileShader + ',' + shader.id,
+ true
+ )
+ }
+
+ compressedTexImage2D = function (target, level, internalformat, width, height, border, pixels) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.compressedTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' +
+ width + ',' + height + ',' + border + ',' + processArray(pixels),
+ true
+ )
+ }
+
+ compressedTexSubImage2D = function (target, level, xoffset, yoffset, width, height, format, pixels) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.compressedTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' +
+ width + ',' + height + ',' + format + ',' + processArray(pixels),
+ true
+ )
+ }
+
+
+ copyTexImage2D = function (target, level, internalformat, x, y, width, height, border) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.copyTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + x + ',' + y + ',' +
+ width + ',' + height + ',' + border,
+ true
+ );
+ }
+
+ copyTexSubImage2D = function (target, level, xoffset, yoffset, x, y, width, height) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.copyTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + x + ',' + y + ',' +
+ width + ',' + height
+ );
+ }
+
+ createBuffer = function () {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createBuffer + ''
+ );
+ const buffer = new Buffer(result);
+ this._map.set(buffer.uuid(), buffer);
+ return buffer;
+ }
+
+ createFramebuffer = function () {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createFramebuffer + ''
+ );
+ const framebuffer = new Framebuffer(result);
+ this._map.set(framebuffer.uuid(), framebuffer);
+ return framebuffer;
+ }
+
+
+ createProgram = function () {
+ const id = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createProgram + ''
+ );
+ const program = new Program(id);
+ this._map.set(program.uuid(), program);
+ return program;
+ }
+
+ createRenderbuffer = function () {
+ const id = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createRenderbuffer + ''
+ )
+ const renderBuffer = new Renderbuffer(id);
+ this._map.set(renderBuffer.uuid(), renderBuffer);
+ return renderBuffer;
+ }
+
+ createShader = function (type) {
+ const id = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createShader + ',' + type
+ )
+ const shader = new Shader(id, type);
+ this._map.set(shader.uuid(), shader);
+ return shader;
+ }
+
+ createTexture = function () {
+ const id = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.createTexture + ''
+ );
+ const texture = new Texture(id);
+ this._map.set(texture.uuid(), texture);
+ return texture;
+ }
+
+ cullFace = function (mode) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.cullFace + ',' + mode,
+ true
+ )
+ }
+
+
+ deleteBuffer = function (buffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteBuffer + ',' + buffer.id,
+ true
+ )
+ }
+
+ deleteFramebuffer = function (framebuffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteFramebuffer + ',' + framebuffer.id,
+ true
+ )
+ }
+
+ deleteProgram = function (program) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteProgram + ',' + program.id,
+ true
+ )
+ }
+
+ deleteRenderbuffer = function (renderbuffer) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteRenderbuffer + ',' + renderbuffer.id,
+ true
+ )
+ }
+
+ deleteShader = function (shader) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteShader + ',' + shader.id,
+ true
+ )
+ }
+
+ deleteTexture = function (texture) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.deleteTexture + ',' + texture.id,
+ true
+ )
+ }
+
+ depthFunc = function (func) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.depthFunc + ',' + func
+ )
+ }
+
+ depthMask = function (flag) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.depthMask + ',' + Number(flag),
+ true
+ )
+ }
+
+ depthRange = function (zNear, zFar) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.depthRange + ',' + zNear + ',' + zFar,
+ true
+ )
+ }
+
+ detachShader = function (program, shader) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.detachShader + ',' + program.id + ',' + shader.id,
+ true
+ )
+ }
+
+ disable = function (cap) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.disable + ',' + cap,
+ true
+ )
+ }
+
+ disableVertexAttribArray = function (index) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.disableVertexAttribArray + ',' + index,
+ true
+ );
+ }
+
+ drawArrays = function (mode, first, count) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.drawArrays + ',' + mode + ',' + first + ',' + count
+ )
+ this._canvas._needRender = true;
+ }
+
+ drawElements = function (mode, count, type, offset) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.drawElements + ',' + mode + ',' + count + ',' + type + ',' + offset + ';'
+ );
+ this._canvas._needRender = true;
+ }
+
+ enable = function (cap) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.enable + ',' + cap,
+ true
+ );
+ }
+
+ enableVertexAttribArray = function (index) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.enableVertexAttribArray + ',' + index,
+ true
+ )
+ }
+
+
+ flush = function () {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.flush + ''
+ )
+ }
+
+ framebufferRenderbuffer = function (target, attachment, textarget, texture, level) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.framebufferRenderbuffer + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
+ true
+ )
+ }
+
+ framebufferTexture2D = function (target, attachment, textarget, texture, level) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.framebufferTexture2D + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
+ true
+ )
+ }
+
+ frontFace = function (mode) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.frontFace + ',' + mode,
+ true
+ )
+ }
+
+ generateMipmap = function (target) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.generateMipmap + ',' + target,
+ true
+ )
+ }
+
+ getActiveAttrib = function (progarm, index) {
+ const resultString = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getActiveAttrib + ',' + progarm.id + ',' + index
+ )
+ const [type, size, name] = resultString.split(',');
+ return new ActiveInfo({
+ type: Number(type),
+ size: Number(size),
+ name
+ });
+ }
+
+ getActiveUniform = function (progarm, index) {
+ const resultString = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getActiveUniform + ',' + progarm.id + ',' + index
+ );
+ const [type, size, name] = resultString.split(',');
+ return new ActiveInfo({
+ type: Number(type),
+ size: Number(size),
+ name
+ })
+ }
+
+ getAttachedShaders = function (progarm) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getAttachedShaders + ',' + progarm.id
+ );
+ const [type, ...ids] = result;
+ return ids.map(id => this._map.get(Shader.uuid(id)));
+ }
+
+ getAttribLocation = function (progarm, name) {
+ return WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getAttribLocation + ',' + progarm.id + ',' + name
+ )
+ }
+
+ getBufferParameter = function (target, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getBufferParameter + ',' + target + ',' + pname
+ );
+ const [type, res] = getBufferParameter;
+ return res;
+ }
+
+ getError = function () {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getError + ''
+ )
+ return result;
+ }
+
+ getExtension = function (name) {
+ return null;
+ }
+
+ getFramebufferAttachmentParameter = function (target, attachment, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getFramebufferAttachmentParameter + ',' + target + ',' + attachment + ',' + pname
+ )
+ switch (pname) {
+ case GLenum.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return this._map.get(Renderbuffer.uuid(result)) || this._map.get(Texture.uuid(result)) || null;
+ default:
+ return result;
+ }
+ }
+
+ getParameter = function (pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getParameter + ',' + pname
+ )
+ switch (pname) {
+ case GLenum.VERSION:
+ return this._version;
+ case GLenum.ARRAY_BUFFER_BINDING: // buffer
+ case GLenum.ELEMENT_ARRAY_BUFFER_BINDING: // buffer
+ return this._map.get(Buffer.uuid(result)) || null;
+ case GLenum.CURRENT_PROGRAM: // program
+ return this._map.get(Program.uuid(result)) || null;
+ case GLenum.FRAMEBUFFER_BINDING: // framebuffer
+ return this._map.get(Framebuffer.uuid(result)) || null;
+ case GLenum.RENDERBUFFER_BINDING: // renderbuffer
+ return this._map.get(Renderbuffer.uuid(result)) || null;
+ case GLenum.TEXTURE_BINDING_2D: // texture
+ case GLenum.TEXTURE_BINDING_CUBE_MAP: // texture
+ return this._map.get(Texture.uuid(result)) || null;
+ case GLenum.ALIASED_LINE_WIDTH_RANGE: // Float32Array
+ case GLenum.ALIASED_POINT_SIZE_RANGE: // Float32Array
+ case GLenum.BLEND_COLOR: // Float32Array
+ case GLenum.COLOR_CLEAR_VALUE: // Float32Array
+ case GLenum.DEPTH_RANGE: // Float32Array
+ case GLenum.MAX_VIEWPORT_DIMS: // Int32Array
+ case GLenum.SCISSOR_BOX: // Int32Array
+ case GLenum.VIEWPORT: // Int32Array
+ case GLenum.COMPRESSED_TEXTURE_FORMATS: // Uint32Array
+ default:
+ const [type, ...res] = result.split(',');
+ if (res.length === 1) {
+ return Number(res[0]);
+ } else {
+ return res.map(Number);
+ }
+ }
+ }
+
+ getProgramInfoLog = function (progarm) {
+ return WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getProgramInfoLog + ',' + progarm.id
+ )
+ }
+
+ getProgramParameter = function (program, pname) {
+ const res = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getProgramParameter + ',' + program.id + ',' + pname
+ );
+
+ const [type, result] = res.split(',').map(i => parseInt(i));
+
+ if (type === 1) {
+ return Boolean(result);
+ } else if (type === 2) {
+ return result;
+ } else {
+ throw new Error('Unrecongized program paramater ' + res + ', type: ' + typeof res);
+ }
+ }
+
+
+ getRenderbufferParameter = function (target, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getRenderbufferParameter + ',' + target + ',' + pname
+ )
+ return result;
+ }
+
+
+ getShaderInfoLog = function (shader) {
+ return WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getShaderInfoLog + ',' + shader.id
+ );
+ }
+
+ getShaderParameter = function (shader, pname) {
+ return WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getShaderParameter + ',' + shader.id + ',' + pname
+ )
+ }
+
+ getShaderPrecisionFormat = function (shaderType, precisionType) {
+ const [rangeMin, rangeMax, precision] = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getShaderPrecisionFormat + ',' + shaderType + ',' + precisionType
+ );
+ const shaderPrecisionFormat = new ShaderPrecisionFormat({
+ rangeMin: Number(rangeMin),
+ rangeMax: Number(rangeMax),
+ precision: Number(precision)
+ });
+ return shaderPrecisionFormat;
+ }
+
+ getShaderSource = function (shader) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getShaderSource + ',' + shader.id
+ );
+ return result;
+ }
+
+ getSupportedExtensions = function () {
+ return Object.keys({});
+ }
+
+ getTexParameter = function (target, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getTexParameter + ',' + target + ',' + pname
+ )
+ return result;
+ }
+
+ getUniformLocation = function (program, name) {
+ const id = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getUniformLocation + ',' + program.id + ',' + name
+ );
+ if (id === -1) {
+ return null;
+ } else {
+ return new UniformLocation(Number(id));
+ }
+ }
+
+ getVertexAttrib = function (index, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getVertexAttrib + ',' + index + ',' + pname
+ );
+ switch (pname) {
+ case GLenum.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ return this._map.get(Buffer.uuid(result)) || null;
+ case GLenum.CURRENT_VERTEX_ATTRIB: // Float32Array
+ default:
+ return result;
+ }
+ }
+
+ getVertexAttribOffset = function (index, pname) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.getVertexAttribOffset + ',' + index + ',' + pname
+ )
+ return Number(result);
+ }
+
+ isBuffer = function (buffer) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isBuffer + ',' + buffer.id
+ )
+ return Boolean(result);
+ }
+
+ isContextLost = function () {
+ return false;
+ }
+
+ isEnabled = function (cap) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isEnabled + ',' + cap
+ )
+ return Boolean(result);
+ }
+
+ isFramebuffer = function (framebuffer) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isFramebuffer + ',' + framebuffer.id
+ )
+ return Boolean(result);
+ }
+
+ isProgram = function (program) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isProgram + ',' + program.id
+ )
+ return Boolean(result);
+ }
+
+ isRenderbuffer = function (renderBuffer) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isRenderbuffer + ',' + renderbuffer.id
+ )
+ return Boolean(result);
+ }
+
+ isShader = function (shader) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isShader + ',' + shader.id
+ )
+ return Boolean(result);
+ }
+
+ isTexture = function (texture) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.isTexture + ',' + texture.id
+ );
+ return Boolean(result);
+ }
+
+ lineWidth = function (width) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.lineWidth + ',' + width,
+ true
+ )
+ }
+
+ linkProgram = function (program) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.linkProgram + ',' + program.id,
+ true
+ );
+ }
+
+
+ pixelStorei = function (pname, param) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.pixelStorei + ',' + pname + ',' + Number(param)
+ )
+ }
+
+ polygonOffset = function (factor, units) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.polygonOffset + ',' + factor + ',' + units
+ )
+ }
+
+ readPixels = function (x, y, width, height, format, type, pixels) {
+ const result = WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.readPixels + ',' + x + ',' + y + ',' + width + ',' + height + ',' + format + ',' + type
+ )
+ return result;
+ }
+
+ renderbufferStorage = function (target, internalFormat, width, height) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.renderbufferStorage + ',' + target + ',' + internalFormat + ',' + width + ',' + height,
+ true
+ )
+ }
+
+ sampleCoverage = function (value, invert) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.sampleCoverage + ',' + value + ',' + Number(invert),
+ true
+ )
+ }
+
+ scissor = function (x, y, width, height) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.scissor + ',' + x + ',' + y + ',' + width + ',' + height,
+ true
+ )
+ }
+
+ shaderSource = function (shader, source) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.shaderSource + ',' + shader.id + ',' + source
+ )
+ }
+
+ stencilFunc = function (func, ref, mask) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilFunc + ',' + func + ',' + ref + ',' + mask,
+ true
+ )
+ }
+
+ stencilFuncSeparate = function (face, func, ref, mask) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilFuncSeparate + ',' + face + ',' + func + ',' + ref + ',' + mask,
+ true
+ )
+ }
+
+ stencilMask = function (mask) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilMask + ',' + mask,
+ true
+ )
+ }
+
+ stencilMaskSeparate = function (face, mask) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilMaskSeparate + ',' + face + ',' + mask,
+ true
+ )
+ }
+
+ stencilOp = function (fail, zfail, zpass) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilOp + ',' + fail + ',' + zfail + ',' + zpass
+ )
+ }
+
+ stencilOpSeparate = function (face, fail, zfail, zpass) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.stencilOp + ',' + face + ',' + fail + ',' + zfail + ',' + zpass,
+ true
+ )
+ }
+
+ texImage2D = function (...args) {
+ WebGLRenderingContext.GBridge.texImage2D(this._canvas.id, ...args);
+ }
+
+
+ texParameterf = function (target, pname, param) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.texParameterf + ',' + target + ',' + pname + ',' + param,
+ true
+ )
+ }
+
+ texParameteri = function (target, pname, param) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.texParameteri + ',' + target + ',' + pname + ',' + param
+ )
+ }
+
+ texSubImage2D = function (...args) {
+ WebGLRenderingContext.GBridge.texSubImage2D(this._canvas.id, ...args);
+ }
+
+ uniform1f = function (location, v0) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform1f + ',' + location.id + ',' + v0
+ )
+ }
+
+ uniform1fv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform1fv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform1i = function (location, v0) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform1i + ',' + location.id + ',' + v0,
+ // true
+ )
+ }
+
+ uniform1iv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform1iv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform2f = function (location, v0, v1) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform2f + ',' + location.id + ',' + v0 + ',' + v1,
+ true
+ )
+ }
+
+ uniform2fv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform2fv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform2i = function (location, v0, v1) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform2i + ',' + location.id + ',' + v0 + ',' + v1,
+ true
+ )
+ }
+
+ uniform2iv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform2iv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform3f = function (location, v0, v1, v2) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform3f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
+ true
+ )
+ }
+
+ uniform3fv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform3fv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform3i = function (location, v0, v1, v2) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform3i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
+ true
+ )
+ }
+
+ uniform3iv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform3iv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform4f = function (location, v0, v1, v2, v3) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform4f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+ true
+ )
+ }
+
+ uniform4fv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform4fv + ',' + location.id + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniform4i = function (location, v0, v1, v2, v3) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform4i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+ true
+ )
+ }
+
+ uniform4iv = function (location, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniform4iv + ',' + location.id + ',' + processArray(value, true),
+ true
+ )
+ }
+
+ uniformMatrix2fv = function (location, transpose, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniformMatrix2fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniformMatrix3fv = function (location, transpose, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniformMatrix3fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+ true
+ )
+ }
+
+ uniformMatrix4fv = function (location, transpose, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.uniformMatrix4fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+ true
+ );
+ }
+
+ useProgram = function (progarm) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.useProgram + ',' + progarm.id + '',
+ true
+ )
+ }
+
+
+ validateProgram = function (program) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.validateProgram + ',' + program.id,
+ true
+ )
+ }
+
+ vertexAttrib1f = function (index, v0) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib1f + ',' + index + ',' + v0,
+ true
+ )
+ }
+
+ vertexAttrib2f = function (index, v0, v1) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib2f + ',' + index + ',' + v0 + ',' + v1,
+ true
+ )
+ }
+
+ vertexAttrib3f = function (index, v0, v1, v2) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib3f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2,
+ true
+ )
+ }
+
+ vertexAttrib4f = function (index, v0, v1, v2, v3) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib4f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+ true
+ )
+ }
+
+ vertexAttrib1fv = function (index, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib1fv + ',' + index + ',' + processArray(value),
+ true
+ )
+ }
+
+ vertexAttrib2fv = function (index, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib2fv + ',' + index + ',' + processArray(value),
+ true
+ )
+ }
+
+ vertexAttrib3fv = function (index, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib3fv + ',' + index + ',' + processArray(value),
+ true
+ )
+ }
+
+ vertexAttrib4fv = function (index, value) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttrib4fv + ',' + index + ',' + processArray(value),
+ true
+ )
+ }
+
+ vertexAttribPointer = function (index, size, type, normalized, stride, offset) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.vertexAttribPointer + ',' + index + ',' + size + ',' + type + ',' + Number(normalized) + ',' + stride + ',' + offset,
+ true
+ )
+ }
+
+ viewport = function (x, y, width, height) {
+ WebGLRenderingContext.GBridge.callNative(
+ this._canvas.id,
+ GLmethod.viewport + ',' + x + ',' + y + ',' + width + ',' + height,
+ true
+ )
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Shader.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Shader.js
new file mode 100644
index 0000000..a763886
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Shader.js
@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLShader';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLShader {
+ className = name;
+
+ constructor(id, type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js
new file mode 100644
index 0000000..208d6c1
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js
@@ -0,0 +1,11 @@
+export default class WebGLShaderPrecisionFormat {
+ className = 'WebGLShaderPrecisionFormat';
+
+ constructor({
+ rangeMin, rangeMax, precision
+ }) {
+ this.rangeMin = rangeMin;
+ this.rangeMax = rangeMax;
+ this.precision = precision;
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Texture.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Texture.js
new file mode 100644
index 0000000..de4d806
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/Texture.js
@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLTexture';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLTexture {
+ className = name;
+
+ constructor(id, type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/UniformLocation.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/UniformLocation.js
new file mode 100644
index 0000000..f5e99dc
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/UniformLocation.js
@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLUniformLocation';
+
+function uuid(id) {
+ return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLUniformLocation {
+ className = name;
+
+ constructor(id, type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ static uuid = uuid;
+
+ uuid() {
+ return uuid(this.id);
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/classUtils.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/classUtils.js
new file mode 100644
index 0000000..88716be
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/context-webgl/classUtils.js
@@ -0,0 +1,3 @@
+export function getTransferedObjectUUID(name, id) {
+ return `${name.toLowerCase()}-${id}`;
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/canvas.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/canvas.js
new file mode 100644
index 0000000..a8d9bb9
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/canvas.js
@@ -0,0 +1,74 @@
+import GContext2D from '../context-2d/RenderingContext';
+import GContextWebGL from '../context-webgl/RenderingContext';
+
+export default class GCanvas {
+
+ // static GBridge = null;
+
+ id = null;
+
+ _needRender = true;
+
+ constructor(id, { disableAutoSwap }) {
+ this.id = id;
+
+ this._disableAutoSwap = disableAutoSwap;
+ if (disableAutoSwap) {
+ this._swapBuffers = () => {
+ GCanvas.GBridge.render(this.id);
+ }
+ }
+ }
+
+ getContext(type) {
+
+ let context = null;
+
+ if (type.match(/webgl/i)) {
+ context = new GContextWebGL(this);
+
+ context.componentId = this.id;
+
+ if (!this._disableAutoSwap) {
+ const render = () => {
+ if (this._needRender) {
+ GCanvas.GBridge.render(this.id);
+ this._needRender = false;
+ }
+ }
+ setInterval(render, 16);
+ }
+
+ GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
+ } else if (type.match(/2d/i)) {
+ context = new GContext2D(this);
+
+ context.componentId = this.id;
+
+// const render = ( callback ) => {
+//
+// const commands = context._drawCommands;
+// context._drawCommands = '';
+//
+// GCanvas.GBridge.render2d(this.id, commands, callback);
+// this._needRender = false;
+// }
+// //draw方法触发
+// context._flush = render;
+// //setInterval(render, 16);
+
+ GCanvas.GBridge.callSetContextType(this.id, 0);
+ } else {
+ throw new Error('not supported context ' + type);
+ }
+
+ return context;
+
+ }
+
+ reset() {
+ GCanvas.GBridge.callReset(this.id);
+ }
+
+
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/image.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/image.js
new file mode 100644
index 0000000..9499a51
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/image.js
@@ -0,0 +1,96 @@
+let incId = 1;
+
+const noop = function () { };
+
+class GImage {
+
+ static GBridge = null;
+
+ constructor() {
+ this._id = incId++;
+ this._width = 0;
+ this._height = 0;
+ this._src = undefined;
+ this._onload = noop;
+ this._onerror = noop;
+ this.complete = false;
+ }
+
+ get width() {
+ return this._width;
+ }
+ set width(v) {
+ this._width = v;
+ }
+
+ get height() {
+ return this._height;
+ }
+
+ set height(v) {
+ this._height = v;
+ }
+
+ get src() {
+ return this._src;
+ }
+
+ set src(v) {
+
+ if (v.startsWith('//')) {
+ v = 'http:' + v;
+ }
+
+ this._src = v;
+
+ GImage.GBridge.perloadImage([this._src, this._id], (data) => {
+ if (typeof data === 'string') {
+ data = JSON.parse(data);
+ }
+ if (data.error) {
+ var evt = { type: 'error', target: this };
+ this.onerror(evt);
+ } else {
+ this.complete = true;
+ this.width = typeof data.width === 'number' ? data.width : 0;
+ this.height = typeof data.height === 'number' ? data.height : 0;
+ var evt = { type: 'load', target: this };
+ this.onload(evt);
+ }
+ });
+ }
+
+ addEventListener(name, listener) {
+ if (name === 'load') {
+ this.onload = listener;
+ } else if (name === 'error') {
+ this.onerror = listener;
+ }
+ }
+
+ removeEventListener(name, listener) {
+ if (name === 'load') {
+ this.onload = noop;
+ } else if (name === 'error') {
+ this.onerror = noop;
+ }
+ }
+
+ get onload() {
+ return this._onload;
+ }
+
+ set onload(v) {
+ this._onload = v;
+ }
+
+ get onerror() {
+ return this._onerror;
+ }
+
+ set onerror(v) {
+ this._onerror = v;
+ }
+}
+
+export default GImage;
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/tool.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/tool.js
new file mode 100644
index 0000000..d3fb398
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/env/tool.js
@@ -0,0 +1,24 @@
+
+export function ArrayBufferToBase64 (buffer) {
+ var binary = '';
+ var bytes = new Uint8ClampedArray(buffer);
+ for (var len = bytes.byteLength, i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return btoa(binary);
+}
+
+export function Base64ToUint8ClampedArray(base64String) {
+ const padding = '='.repeat((4 - base64String.length % 4) % 4);
+ const base64 = (base64String + padding)
+ .replace(/\-/g, '+')
+ .replace(/_/g, '/');
+
+ const rawData = atob(base64);
+ const outputArray = new Uint8ClampedArray(rawData.length);
+
+ for (let i = 0; i < rawData.length; ++i) {
+ outputArray[i] = rawData.charCodeAt(i);
+ }
+ return outputArray;
+}
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/index.js b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/index.js
new file mode 100644
index 0000000..a34ad58
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/gcanvas/index.js
@@ -0,0 +1,39 @@
+import GCanvas from './env/canvas';
+import GImage from './env/image';
+
+import GWebGLRenderingContext from './context-webgl/RenderingContext';
+import GContext2D from './context-2d/RenderingContext';
+
+import GBridgeWeex from './bridge/bridge-weex';
+
+export let Image = GImage;
+
+export let WeexBridge = GBridgeWeex;
+
+export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {
+
+ const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;
+
+ GBridge.callEnable(el.ref, [
+ 0, // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
+ -1, // hybridLayerType: 0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
+ false, // supportScroll
+ false, // newCanvasMode
+ 1, // compatible
+ 'white',// clearColor
+ false // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
+ ]);
+
+ if (debug === true) {
+ GBridge.callEnableDebug();
+ }
+ if (disableComboCommands) {
+ GBridge.callEnableDisableCombo();
+ }
+
+ var canvas = new GCanvas(el.ref, { disableAutoSwap });
+ canvas.width = el.style.width;
+ canvas.height = el.style.height;
+
+ return canvas;
+};
\ No newline at end of file
diff --git a/uni_modules/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue b/uni_modules/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue
new file mode 100644
index 0000000..d9e7ad2
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue
@@ -0,0 +1,684 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 若保存失败,请长按二维码进行保存
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Error, see console.
+
+
+
+
+
+
+
+
diff --git a/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/license.md b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/license.md
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/license.md
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/module.js b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/module.js
new file mode 100644
index 0000000..a3cbfca
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/module.js
@@ -0,0 +1,2285 @@
+//---------------------------------------------------------------------
+// uQRCode 二维码生成插件 v3.2.2
+//
+// uQRCode 是一款使用方式简单,高扩展的二维码生成插件。支持全端生成,支持canvas的地方就可以使用uQRCode。
+//
+// Copyright (c) Sansnn uQRCode All rights reserved.
+// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// 复制使用请保留本段注释,感谢支持开源!
+//
+// 开源地址:
+// https://github.com/Sansnn/uQRCode
+//
+// uni-app插件市场地址:
+// https://ext.dcloud.net.cn/plugin?id=1287
+//---------------------------------------------------------------------
+
+"use strict";
+
+function uQRCode(options, canvasContext, loadImage) {
+ this.options = uQRCode.getOptions(options);
+ this.canvasContext = uQRCode.getCanvasContext(canvasContext);
+ this.loadImage = uQRCode.getLoadImage(loadImage);
+}
+
+(function() {
+ //---------------------------------------------------------------------
+ // QRCode for JavaScript
+ //
+ // Copyright (c) 2009 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word "QR Code" is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ //---------------------------------------------------------------------
+ // QR8bitByte
+ //---------------------------------------------------------------------
+
+ function QR8bitByte(data) {
+ this.mode = QRMode.MODE_8BIT_BYTE;
+ this.data = data;
+ }
+
+ QR8bitByte.prototype = {
+
+ getLength: function(buffer) {
+ return this.data.length;
+ },
+
+ write: function(buffer) {
+ for (var i = 0; i < this.data.length; i++) {
+ // not JIS ...
+ buffer.put(this.data.charCodeAt(i), 8);
+ }
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRCode
+ //---------------------------------------------------------------------
+
+ function QRCode(typeNumber, errorCorrectLevel) {
+ this.typeNumber = typeNumber;
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.modules = null;
+ this.moduleCount = 0;
+ this.dataCache = null;
+ this.dataList = new Array();
+ }
+
+ QRCode.prototype = {
+
+ addData: function(data) {
+ var newData = new QR8bitByte(data);
+ this.dataList.push(newData);
+ this.dataCache = null;
+ },
+
+ isDark: function(row, col) {
+ if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+ throw new Error(row + "," + col);
+ }
+ return this.modules[row][col];
+ },
+
+ getModuleCount: function() {
+ return this.moduleCount;
+ },
+
+ make: function() {
+ // Calculate automatically typeNumber if provided is < 1
+ if (this.typeNumber < 1) {
+ var typeNumber = 1;
+ for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ for (var i = 0; i < this.dataList.length; i++) {
+ var data = this.dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+ if (buffer.getLengthInBits() <= totalDataCount * 8)
+ break;
+ }
+ this.typeNumber = typeNumber;
+ }
+ this.makeImpl(false, this.getBestMaskPattern());
+ },
+
+ makeImpl: function(test, maskPattern) {
+
+ this.moduleCount = this.typeNumber * 4 + 17;
+ this.modules = new Array(this.moduleCount);
+
+ for (var row = 0; row < this.moduleCount; row++) {
+
+ this.modules[row] = new Array(this.moduleCount);
+
+ for (var col = 0; col < this.moduleCount; col++) {
+ this.modules[row][col] = null; //(col + row) % 3;
+ }
+ }
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this.typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this.dataCache == null) {
+ this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+ }
+
+ this.mapData(this.dataCache, maskPattern);
+ },
+
+ setupPositionProbePattern: function(row, col) {
+
+ for (var r = -1; r <= 7; r++) {
+
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c++) {
+
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ },
+
+ getBestMaskPattern: function() {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i++) {
+
+ this.makeImpl(true, i);
+
+ var lostPoint = QRUtil.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ },
+
+ createMovieClip: function(target_mc, instance_name, depth) {
+
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+ var cs = 1;
+
+ this.make();
+
+ for (var row = 0; row < this.modules.length; row++) {
+
+ var y = row * cs;
+
+ for (var col = 0; col < this.modules[row].length; col++) {
+
+ var x = col * cs;
+ var dark = this.modules[row][col];
+
+ if (dark) {
+ qr_mc.beginFill(0, 100);
+ qr_mc.moveTo(x, y);
+ qr_mc.lineTo(x + cs, y);
+ qr_mc.lineTo(x + cs, y + cs);
+ qr_mc.lineTo(x, y + cs);
+ qr_mc.endFill();
+ }
+ }
+ }
+
+ return qr_mc;
+ },
+
+ setupTimingPattern: function() {
+
+ for (var r = 8; r < this.moduleCount - 8; r++) {
+ if (this.modules[r][6] != null) {
+ continue;
+ }
+ this.modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < this.moduleCount - 8; c++) {
+ if (this.modules[6][c] != null) {
+ continue;
+ }
+ this.modules[6][c] = (c % 2 == 0);
+ }
+ },
+
+ setupPositionAdjustPattern: function() {
+
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+ for (var i = 0; i < pos.length; i++) {
+
+ for (var j = 0; j < pos.length; j++) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (this.modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r++) {
+
+ for (var c = -2; c <= 2; c++) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2 ||
+ (r == 0 && c == 0)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ },
+
+ setupTypeNumber: function(test) {
+
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ },
+
+ setupTypeInfo: function(test, maskPattern) {
+
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
+ var bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ this.modules[i][8] = mod;
+ } else if (i < 8) {
+ this.modules[i + 1][8] = mod;
+ } else {
+ this.modules[this.moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ this.modules[8][this.moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this.modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this.modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this.modules[this.moduleCount - 8][8] = (!test);
+
+ },
+
+ mapData: function(data, maskPattern) {
+
+ var inc = -1;
+ var row = this.moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col--;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c++) {
+
+ if (this.modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this.modules[row][col - c] = dark;
+ bitIndex--;
+
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this.moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+
+ }
+
+ };
+
+ QRCode.PAD0 = 0xEC;
+ QRCode.PAD1 = 0x11;
+
+ QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+
+ for (var i = 0; i < dataList.length; i++) {
+ var data = dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error("code length overflow. (" +
+ buffer.getLengthInBits() +
+ ">" +
+ totalDataCount * 8 +
+ ")");
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD1, 8);
+ }
+
+ return QRCode.createBytes(buffer, rsBlocks);
+ }
+
+ QRCode.createBytes = function(buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r++) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i++) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = dcdata[r][i];
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+
+ }
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+
+ var QRMode = {
+ MODE_NUMBER: 1 << 0,
+ MODE_ALPHA_NUM: 1 << 1,
+ MODE_8BIT_BYTE: 1 << 2,
+ MODE_KANJI: 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+
+ var QRErrorCorrectLevel = {
+ L: 1,
+ M: 0,
+ Q: 3,
+ H: 2
+ };
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+
+ var QRMaskPattern = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ var QRUtil = {
+
+ PATTERN_POSITION_TABLE: [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ],
+
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+ getBCHTypeInfo: function(data) {
+ var d = data << 10;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+ d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+ }
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
+ },
+
+ getBCHTypeNumber: function(data) {
+ var d = data << 12;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+ d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+ }
+ return (data << 12) | d;
+ },
+
+ getBCHDigit: function(data) {
+
+ var digit = 0;
+
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+
+ return digit;
+ },
+
+ getPatternPosition: function(typeNumber) {
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+ },
+
+ getMask: function(maskPattern, i, j) {
+
+ switch (maskPattern) {
+
+ case QRMaskPattern.PATTERN000:
+ return (i + j) % 2 == 0;
+ case QRMaskPattern.PATTERN001:
+ return i % 2 == 0;
+ case QRMaskPattern.PATTERN010:
+ return j % 3 == 0;
+ case QRMaskPattern.PATTERN011:
+ return (i + j) % 3 == 0;
+ case QRMaskPattern.PATTERN100:
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+ case QRMaskPattern.PATTERN101:
+ return (i * j) % 2 + (i * j) % 3 == 0;
+ case QRMaskPattern.PATTERN110:
+ return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case QRMaskPattern.PATTERN111:
+ return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default:
+ throw new Error("bad maskPattern:" + maskPattern);
+ }
+ },
+
+ getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+ var a = new QRPolynomial([1], 0);
+
+ for (var i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+ }
+
+ return a;
+ },
+
+ getLengthInBits: function(mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 10;
+ case QRMode.MODE_ALPHA_NUM:
+ return 9;
+ case QRMode.MODE_8BIT_BYTE:
+ return 8;
+ case QRMode.MODE_KANJI:
+ return 8;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 12;
+ case QRMode.MODE_ALPHA_NUM:
+ return 11;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 10;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 14;
+ case QRMode.MODE_ALPHA_NUM:
+ return 13;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 12;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else {
+ throw new Error("type:" + type);
+ }
+ },
+
+ getLostPoint: function(qrCode) {
+
+ var moduleCount = qrCode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row++) {
+
+ for (var col = 0; col < moduleCount; col++) {
+
+ var sameCount = 0;
+ var dark = qrCode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r++) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c++) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row++) {
+ for (var col = 0; col < moduleCount - 1; col++) {
+ var count = 0;
+ if (qrCode.isDark(row, col)) count++;
+ if (qrCode.isDark(row + 1, col)) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row++) {
+ for (var col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row, col + 1) &&
+ qrCode.isDark(row, col + 2) &&
+ qrCode.isDark(row, col + 3) &&
+ qrCode.isDark(row, col + 4) &&
+ !qrCode.isDark(row, col + 5) &&
+ qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row + 1, col) &&
+ qrCode.isDark(row + 2, col) &&
+ qrCode.isDark(row + 3, col) &&
+ qrCode.isDark(row + 4, col) &&
+ !qrCode.isDark(row + 5, col) &&
+ qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ var QRMath = {
+
+ glog: function(n) {
+
+ if (n < 1) {
+ throw new Error("glog(" + n + ")");
+ }
+
+ return QRMath.LOG_TABLE[n];
+ },
+
+ gexp: function(n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return QRMath.EXP_TABLE[n];
+ },
+
+ EXP_TABLE: new Array(256),
+
+ LOG_TABLE: new Array(256)
+
+ };
+
+ for (var i = 0; i < 8; i++) {
+ QRMath.EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i++) {
+ QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+ QRMath.EXP_TABLE[i - 5] ^
+ QRMath.EXP_TABLE[i - 6] ^
+ QRMath.EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i++) {
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+ }
+
+ //---------------------------------------------------------------------
+ // QRPolynomial
+ //---------------------------------------------------------------------
+
+ function QRPolynomial(num, shift) {
+
+ if (num.length == undefined) {
+ throw new Error(num.length + "/" + shift);
+ }
+
+ var offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i++) {
+ this.num[i] = num[i + offset];
+ }
+ }
+
+ QRPolynomial.prototype = {
+
+ get: function(index) {
+ return this.num[index];
+ },
+
+ getLength: function() {
+ return this.num.length;
+ },
+
+ multiply: function(e) {
+
+ var num = new Array(this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < this.getLength(); i++) {
+ for (var j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+ }
+ }
+
+ return new QRPolynomial(num, 0);
+ },
+
+ mod: function(e) {
+
+ if (this.getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+ var num = new Array(this.getLength());
+
+ for (var i = 0; i < this.getLength(); i++) {
+ num[i] = this.get(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+ }
+
+ // recursive call
+ return new QRPolynomial(num, 0).mod(e);
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ function QRRSBlock(totalCount, dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ QRRSBlock.RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16],
+
+ // 11
+ [4, 101, 81],
+ [1, 80, 50, 4, 81, 51],
+ [4, 50, 22, 4, 51, 23],
+ [3, 36, 12, 8, 37, 13],
+
+ // 12
+ [2, 116, 92, 2, 117, 93],
+ [6, 58, 36, 2, 59, 37],
+ [4, 46, 20, 6, 47, 21],
+ [7, 42, 14, 4, 43, 15],
+
+ // 13
+ [4, 133, 107],
+ [8, 59, 37, 1, 60, 38],
+ [8, 44, 20, 4, 45, 21],
+ [12, 33, 11, 4, 34, 12],
+
+ // 14
+ [3, 145, 115, 1, 146, 116],
+ [4, 64, 40, 5, 65, 41],
+ [11, 36, 16, 5, 37, 17],
+ [11, 36, 12, 5, 37, 13],
+
+ // 15
+ [5, 109, 87, 1, 110, 88],
+ [5, 65, 41, 5, 66, 42],
+ [5, 54, 24, 7, 55, 25],
+ [11, 36, 12],
+
+ // 16
+ [5, 122, 98, 1, 123, 99],
+ [7, 73, 45, 3, 74, 46],
+ [15, 43, 19, 2, 44, 20],
+ [3, 45, 15, 13, 46, 16],
+
+ // 17
+ [1, 135, 107, 5, 136, 108],
+ [10, 74, 46, 1, 75, 47],
+ [1, 50, 22, 15, 51, 23],
+ [2, 42, 14, 17, 43, 15],
+
+ // 18
+ [5, 150, 120, 1, 151, 121],
+ [9, 69, 43, 4, 70, 44],
+ [17, 50, 22, 1, 51, 23],
+ [2, 42, 14, 19, 43, 15],
+
+ // 19
+ [3, 141, 113, 4, 142, 114],
+ [3, 70, 44, 11, 71, 45],
+ [17, 47, 21, 4, 48, 22],
+ [9, 39, 13, 16, 40, 14],
+
+ // 20
+ [3, 135, 107, 5, 136, 108],
+ [3, 67, 41, 13, 68, 42],
+ [15, 54, 24, 5, 55, 25],
+ [15, 43, 15, 10, 44, 16],
+
+ // 21
+ [4, 144, 116, 4, 145, 117],
+ [17, 68, 42],
+ [17, 50, 22, 6, 51, 23],
+ [19, 46, 16, 6, 47, 17],
+
+ // 22
+ [2, 139, 111, 7, 140, 112],
+ [17, 74, 46],
+ [7, 54, 24, 16, 55, 25],
+ [34, 37, 13],
+
+ // 23
+ [4, 151, 121, 5, 152, 122],
+ [4, 75, 47, 14, 76, 48],
+ [11, 54, 24, 14, 55, 25],
+ [16, 45, 15, 14, 46, 16],
+
+ // 24
+ [6, 147, 117, 4, 148, 118],
+ [6, 73, 45, 14, 74, 46],
+ [11, 54, 24, 16, 55, 25],
+ [30, 46, 16, 2, 47, 17],
+
+ // 25
+ [8, 132, 106, 4, 133, 107],
+ [8, 75, 47, 13, 76, 48],
+ [7, 54, 24, 22, 55, 25],
+ [22, 45, 15, 13, 46, 16],
+
+ // 26
+ [10, 142, 114, 2, 143, 115],
+ [19, 74, 46, 4, 75, 47],
+ [28, 50, 22, 6, 51, 23],
+ [33, 46, 16, 4, 47, 17],
+
+ // 27
+ [8, 152, 122, 4, 153, 123],
+ [22, 73, 45, 3, 74, 46],
+ [8, 53, 23, 26, 54, 24],
+ [12, 45, 15, 28, 46, 16],
+
+ // 28
+ [3, 147, 117, 10, 148, 118],
+ [3, 73, 45, 23, 74, 46],
+ [4, 54, 24, 31, 55, 25],
+ [11, 45, 15, 31, 46, 16],
+
+ // 29
+ [7, 146, 116, 7, 147, 117],
+ [21, 73, 45, 7, 74, 46],
+ [1, 53, 23, 37, 54, 24],
+ [19, 45, 15, 26, 46, 16],
+
+ // 30
+ [5, 145, 115, 10, 146, 116],
+ [19, 75, 47, 10, 76, 48],
+ [15, 54, 24, 25, 55, 25],
+ [23, 45, 15, 25, 46, 16],
+
+ // 31
+ [13, 145, 115, 3, 146, 116],
+ [2, 74, 46, 29, 75, 47],
+ [42, 54, 24, 1, 55, 25],
+ [23, 45, 15, 28, 46, 16],
+
+ // 32
+ [17, 145, 115],
+ [10, 74, 46, 23, 75, 47],
+ [10, 54, 24, 35, 55, 25],
+ [19, 45, 15, 35, 46, 16],
+
+ // 33
+ [17, 145, 115, 1, 146, 116],
+ [14, 74, 46, 21, 75, 47],
+ [29, 54, 24, 19, 55, 25],
+ [11, 45, 15, 46, 46, 16],
+
+ // 34
+ [13, 145, 115, 6, 146, 116],
+ [14, 74, 46, 23, 75, 47],
+ [44, 54, 24, 7, 55, 25],
+ [59, 46, 16, 1, 47, 17],
+
+ // 35
+ [12, 151, 121, 7, 152, 122],
+ [12, 75, 47, 26, 76, 48],
+ [39, 54, 24, 14, 55, 25],
+ [22, 45, 15, 41, 46, 16],
+
+ // 36
+ [6, 151, 121, 14, 152, 122],
+ [6, 75, 47, 34, 76, 48],
+ [46, 54, 24, 10, 55, 25],
+ [2, 45, 15, 64, 46, 16],
+
+ // 37
+ [17, 152, 122, 4, 153, 123],
+ [29, 74, 46, 14, 75, 47],
+ [49, 54, 24, 10, 55, 25],
+ [24, 45, 15, 46, 46, 16],
+
+ // 38
+ [4, 152, 122, 18, 153, 123],
+ [13, 74, 46, 32, 75, 47],
+ [48, 54, 24, 14, 55, 25],
+ [42, 45, 15, 32, 46, 16],
+
+ // 39
+ [20, 147, 117, 4, 148, 118],
+ [40, 75, 47, 7, 76, 48],
+ [43, 54, 24, 22, 55, 25],
+ [10, 45, 15, 67, 46, 16],
+
+ // 40
+ [19, 148, 118, 6, 149, 119],
+ [18, 75, 47, 31, 76, 48],
+ [34, 54, 24, 34, 55, 25],
+ [20, 45, 15, 61, 46, 16]
+ ];
+
+ QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+ var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (rsBlock == undefined) {
+ throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" +
+ errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i++) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j++) {
+ list.push(new QRRSBlock(totalCount, dataCount));
+ }
+ }
+
+ return list;
+ }
+
+ QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+ switch (errorCorrectLevel) {
+ case QRErrorCorrectLevel.L:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRErrorCorrectLevel.M:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRErrorCorrectLevel.Q:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRErrorCorrectLevel.H:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default:
+ return undefined;
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // QRBitBuffer
+ //---------------------------------------------------------------------
+
+ function QRBitBuffer() {
+ this.buffer = new Array();
+ this.length = 0;
+ }
+
+ QRBitBuffer.prototype = {
+
+ get: function(index) {
+ var bufIndex = Math.floor(index / 8);
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+ },
+
+ put: function(num, length) {
+ for (var i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+ }
+ },
+
+ getLengthInBits: function() {
+ return this.length;
+ },
+
+ putBit: function(bit) {
+
+ var bufIndex = Math.floor(this.length / 8);
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0);
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+ }
+
+ this.length++;
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // Support Chinese 字符编码支持中文
+ // 使用mode 4 8bit
+ //---------------------------------------------------------------------
+ function utf16To8(text) {
+ var result = '';
+ var c;
+ for (var i = 0; i < text.length; i++) {
+ c = text.charCodeAt(i);
+ if (c >= 0x0001 && c <= 0x007F) {
+ result += text.charAt(i);
+ } else if (c > 0x07FF) {
+ result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+ result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ } else {
+ result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 队列
+ */
+ class Queue {
+ constructor() {
+ let waitingQueue = [];
+ let isRunning = false; //记录是否有未完成的任务
+ function execute(task, resolve, reject) {
+ task()
+ .then((data) => {
+ resolve(data);
+ })
+ .catch((e) => {
+ reject(e);
+ })
+ .finally(() => {
+ //等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
+ if (waitingQueue.length) {
+ const next = waitingQueue.shift();
+ execute(next.task, next.resolve, next.reject);
+ } else {
+ isRunning = false;
+ }
+ });
+ }
+ return function(task) {
+ return new Promise((resolve, reject) => {
+ if (isRunning) {
+ waitingQueue.push({
+ task,
+ resolve,
+ reject
+ });
+ } else {
+ isRunning = true;
+ execute(task, resolve, reject);
+ }
+ });
+ };
+ }
+ }
+ // const queue = new Queue();
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task1');
+ // }, 1000);
+ // })).then(data => console.log(data));
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task2');
+ // }, 100);
+ // })).then(data => console.log(data));
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task3');
+ // }, 300);
+ // })).then(data => console.log(data));
+
+ /**
+ * 纠错等级
+ */
+ uQRCode.errorCorrectLevel = QRErrorCorrectLevel;
+
+ /**
+ * 预设默认值(基本,不包含各部分和艺术码参数)
+ */
+ uQRCode.defaults = {
+ typeNumber: -1, // 版本,-1为自动计算,字符越多,版本越高
+ errorCorrectLevel: QRErrorCorrectLevel.H, // 纠错等级
+ text: '', // 二维码内容
+ size: 354, // 大小
+ useDynamicSize: false, // 使用动态尺寸,可以去掉方块小数点,绘制出来后没有白色细线
+ margin: 0, // 边距
+ background: {
+ color: '#FFFFFF' // 背景色
+ },
+ foreground: {
+ color: '#000000' // 前景色
+ }
+ }
+
+ /**
+ * 对象属性深度替换
+ * @param {Object} o 原始对象/默认对象/被替换的对象
+ * @param {Object} r 从这个对象里取值替换到o对象里
+ * @return {Object} 替换后的新对象
+ */
+ uQRCode.deepReplace = function(o = {}, r = {}) {
+ let obj = {
+ ...o
+ }
+ for (let k in r) {
+ var vr = r[k];
+ if (vr.constructor == Object) {
+ obj[k] = this.deepReplace(obj[k], vr);
+ } else if (vr.constructor == String && !vr) {
+ obj[k] = obj[k];
+ } else {
+ obj[k] = vr;
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * 获取选项值
+ */
+ uQRCode.getOptions = function(options) {
+ options = uQRCode.deepReplace(uQRCode.defaults, options);
+
+ /* 背景 */
+ options.background = uQRCode.deepReplace({
+ color: options.background.color, // 背景色
+ image: {
+ src: '',
+ width: 1, // 图片宽
+ height: 1, // 图片高
+ align: ['center', 'center'], // 图片对齐方式水平,垂直
+ anchor: [0, 0], // 图片位置,X坐标,Y坐标
+ alpha: 1 // 透明度
+ }
+ }, options.background);
+ /* 前景 */
+ options.foreground = uQRCode.deepReplace({
+ color: options.foreground.color, // 前景色
+ image: {
+ src: '',
+ width: 1 / 4, // 图片宽
+ height: 1 / 4, // 图片高
+ align: ['center', 'center'], // 图片对齐方式水平,垂直
+ anchor: [0, 0] // 图片位置,X坐标,Y坐标
+ }
+ }, options.foreground);
+ /* 定位角 */
+ options.positionDetection = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 定位角区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 定位角小块颜色,默认值跟随前景色
+ }, options.positionDetection);
+ /* 分割图案 */
+ options.separator = uQRCode.deepReplace({
+ color: options.background.color // 分割区域颜色,默认值跟随背景色
+ }, options.separator);
+ /* 对齐图案 */
+ options.alignment = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 对齐区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 对齐小块颜色,默认值跟随前景色
+ }, options.alignment);
+ /* 时序图案 */
+ options.timing = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 时序区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 时序小块颜色,默认值跟随前景色
+ }, options.timing);
+ /* 暗块 */
+ options.darkBlock = uQRCode.deepReplace({
+ color: options.foreground.color // 暗块颜色
+ }, options.darkBlock);
+ /* 版本信息 */
+ options.versionInformation = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 版本信息区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 版本信息小块颜色,默认值跟随前景色
+ }, options.versionInformation);
+
+ return options;
+ }
+
+ /**
+ * 获取canvas实例
+ */
+ uQRCode.getCanvasContext = function(ctx) {
+ /* 兼容setFillStyle写法,主要在uni-app nvue gcanvas */
+ ctx.setFillStyle = ctx.setFillStyle || function(color) {
+ ctx.fillStyle = color;
+ }
+ /* 兼容setFontSize写法,主要在微信小程序canvas2d */
+ ctx.setFontSize = ctx.setFontSize || function(fontSize) {
+ ctx.font = `${fontSize}px`;
+ }
+ /* 兼容setTextAlign写法,主要在微信小程序canvas2d */
+ ctx.setTextAlign = ctx.setTextAlign || function(align) {
+ ctx.textAlign = align;
+ }
+ /* 兼容setTextBaseline写法,主要在微信小程序canvas2d */
+ ctx.setTextBaseline = ctx.setTextBaseline || function(textBaseline) {
+ ctx.textBaseline = textBaseline;
+ }
+ /* 若实例不包含draw方法则创建一个 */
+ ctx.draw = ctx.draw || function(reserve, callback) {
+ callback && callback();
+ }
+ return ctx;
+ }
+
+ /* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */
+ uQRCode.Queue = new Queue();
+ uQRCode.QueueLoadImage = new Queue();
+
+ /* 缓存loadImage图片 */
+ uQRCode.loadImageCache = [];
+
+ /**
+ * 获取加载图片方法
+ */
+ uQRCode.getLoadImage = function(loadImage) {
+ if (typeof loadImage == 'function') {
+ return function(src) {
+ /* 解决iOS APP||NVUE同时绘制多个二维码导致图片丢失需使用队列 */
+ return uQRCode.QueueLoadImage(() => new Promise((resolve, reject) => {
+ setTimeout(() => {
+ const cache = uQRCode.loadImageCache.find(x => x.src == src);
+ if (cache) {
+ resolve(cache.img);
+ } else {
+ loadImage(src).then(img => {
+ uQRCode.loadImageCache.push({
+ src,
+ img
+ });
+ resolve(img);
+ });
+ }
+ }, 150);
+ }));
+ }
+ } else {
+ return function(src) {
+ return Promise.resolve(src);
+ }
+ }
+ }
+
+ uQRCode.prototype = {
+ /**
+ * 实例化传入的选项值
+ */
+ options: {},
+
+ /**
+ * 画布实例
+ */
+ canvasContext: {},
+
+ /**
+ * 制作二维码全部数据
+ */
+ makeData: {},
+
+ /**
+ * 制作二维码主要模块数据,基于makeData的modules但数据格式不一致,这里的modules是定制过的
+ */
+ modules: [],
+
+ /**
+ * 模块数量
+ */
+ moduleCount: 0,
+
+ /**
+ * 获取制作二维码数据
+ */
+ getMakeData() {
+ let {
+ typeNumber,
+ errorCorrectLevel,
+ text
+ } = this.options;
+ var qrcode = new QRCode(typeNumber, errorCorrectLevel);
+ qrcode.addData(utf16To8(text.toString()));
+ qrcode.make();
+ return qrcode;
+ },
+
+ /**
+ * 制作二维码方法
+ */
+ make() {
+ let makeData = this.makeData = this.getMakeData();
+ this.modules = JSON.parse(JSON.stringify(makeData.modules));
+ this.moduleCount = makeData.moduleCount;
+ this.options.typeNumber = makeData.typeNumber;
+
+ /* 数据码 data */
+ this.paintData();
+ /* 定位图案 position detection */
+ this.paintPositionDetection();
+ /* 分隔图案 separator */
+ this.paintSeparator();
+ /* 对齐图案 alignment */
+ this.paintAlignment();
+ /* 时序图案 timing */
+ this.paintTiming();
+ /* 暗块 darkBlock */
+ this.paintDarkBlock();
+ /* 预留版本信息 version information */
+ this.paintVersionInformation();
+ },
+
+ paintData() {
+ let modules = this.modules;
+ let moduleCount = this.moduleCount;
+ let {
+ size,
+ margin,
+ background,
+ foreground,
+ useDynamicSize
+ } = this.options;
+
+ /* dynamicSize自动计算出最适合绘制的尺寸,并按这个尺寸去绘制,可以解决canvas绘制小块间产生白线的问题(其实就是小数点精度问题),useDynamicSize=false可以取消这个设定 */
+ // let dynamicSize = this.options.dynamicSize = Math.floor((size - margin * 2) / moduleCount) * moduleCount + margin * 2; // Math.floor向下取整缩放会模糊
+ let dynamicSize = this.options.dynamicSize = Math.ceil((size - margin * 2) / moduleCount) * moduleCount + margin * 2; // Math.ceil向上取整缩放效果比floor清晰
+ if (!useDynamicSize) {
+ dynamicSize = this.options.dynamicSize = size;
+ }
+ let tileSize = (dynamicSize - margin * 2) / moduleCount;
+
+ for (var rowI = 0; rowI < modules.length; rowI++) {
+ for (var colI = 0; colI < modules.length; colI++) {
+ var tile = modules[rowI][colI];
+ if (tile) {
+ modules[rowI][colI] = {
+ size: tileSize,
+ x: colI * tileSize + margin,
+ y: rowI * tileSize + margin,
+ type: ['foreground'],
+ color: foreground.color,
+ isBlack: true,
+ isDrawn: false
+ };
+ } else {
+ modules[rowI][colI] = {
+ size: tileSize,
+ x: colI * tileSize + margin,
+ y: rowI * tileSize + margin,
+ type: ['background'],
+ color: background.color,
+ isBlack: false,
+ isDrawn: false
+ };
+ }
+ }
+ }
+ },
+
+ paintPositionDetection() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ positionDetection
+ } = this.options;
+
+ //1) 定义基础图形索引(左上角)x ,y,v
+ let basePart = [
+ [0, 0, 1],
+ [1, 0, 1],
+ [2, 0, 1],
+ [3, 0, 1],
+ [4, 0, 1],
+ [5, 0, 1],
+ [6, 0, 1],
+ [0, 1, 1],
+ [1, 1, 0],
+ [2, 1, 0],
+ [3, 1, 0],
+ [4, 1, 0],
+ [5, 1, 0],
+ [6, 1, 1],
+ [0, 2, 1],
+ [1, 2, 0],
+ [2, 2, 1],
+ [3, 2, 1],
+ [4, 2, 1],
+ [5, 2, 0],
+ [6, 2, 1],
+ [0, 3, 1],
+ [1, 3, 0],
+ [2, 3, 1],
+ [3, 3, 1],
+ [4, 3, 1],
+ [5, 3, 0],
+ [6, 3, 1],
+ [0, 4, 1],
+ [1, 4, 0],
+ [2, 4, 1],
+ [3, 4, 1],
+ [4, 4, 1],
+ [5, 4, 0],
+ [6, 4, 1],
+ [0, 5, 1],
+ [1, 5, 0],
+ [2, 5, 0],
+ [3, 5, 0],
+ [4, 5, 0],
+ [5, 5, 0],
+ [6, 5, 1],
+ [0, 6, 1],
+ [1, 6, 1],
+ [2, 6, 1],
+ [3, 6, 1],
+ [4, 6, 1],
+ [5, 6, 1],
+ [6, 6, 1]
+ ];
+ let disc = size - 7; //size -7
+ basePart.forEach(d => {
+ var ltItem = modules[d[0]][d[1]];
+ var rtItem = modules[d[0] + disc][d[1]];
+ var lbItem = modules[d[0]][d[1] + disc];
+ lbItem.type.push('positionDetection');
+ rtItem.type.push('positionDetection');
+ ltItem.type.push('positionDetection');
+ //绘制左上角
+ ltItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ //绘制右
+ rtItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ //绘制左
+ lbItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ });
+ },
+
+ paintSeparator() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ separator
+ } = this.options;
+
+ //1) 定义基础图形索引(左上角)
+ [
+ [7, 0],
+ [7, 1],
+ [7, 2],
+ [7, 3],
+ [7, 4],
+ [7, 5],
+ [7, 6],
+ [7, 7],
+ [0, 7],
+ [1, 7],
+ [2, 7],
+ [3, 7],
+ [4, 7],
+ [5, 7],
+ [6, 7]
+ ].forEach(d => {
+ var ltItem = modules[d[0]][d[1]];
+ var rtItem = modules[size - d[0] - 1][d[1]];
+ var lbItem = modules[d[0]][size - d[1] - 1];
+ lbItem.type.push('separator');
+ rtItem.type.push('separator');
+ ltItem.type.push('separator');
+ //绘制左上
+ ltItem.color = separator.color;
+ //绘制右
+ rtItem.color = separator.color;
+ //绘制左
+ lbItem.color = separator.color;
+ });
+ },
+
+ paintAlignment() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ alignment,
+ typeNumber
+ } = this.options;
+
+ //不同版本的对齐图案组合位置
+ const ALIGNMENT_OF_VERSION = [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ];
+ // 对齐图案数量和中心位置根据版本定义
+ const alignments = ALIGNMENT_OF_VERSION[typeNumber - 1];
+ if (alignments) {
+ const calcMatrix = [
+ [-2, -2, 1],
+ [-1, -2, 1],
+ [0, -2, 1],
+ [1, -2, 1],
+ [2, -2, 1],
+ [-2, -1, 1],
+ [-1, -1, 0],
+ [0, -1, 0],
+ [1, -1, 0],
+ [2, -1, 1],
+ [-2, 0, 1],
+ [-1, 0, 0],
+ [0, 0, 1],
+ [1, 0, 0],
+ [2, 0, 1],
+ [-2, 1, 1],
+ [-1, 1, 0],
+ [0, 1, 0],
+ [1, 1, 0],
+ [2, 1, 1],
+ [-2, 2, 1],
+ [-1, 2, 1],
+ [0, 2, 1],
+ [1, 2, 1],
+ [2, 2, 1]
+ ];
+ const group_len = alignments.length;
+ for (let i = 0; i < group_len; i++) {
+ for (let j = 0; j < group_len; j++) {
+ //对齐图案不能污染 定位器和分隔器
+ let {
+ x,
+ y
+ } = {
+ x: alignments[i],
+ y: alignments[j]
+ };
+ if (!((x < 9 && y < 9) || (x > size - 9 - 1 && y < 9) || (y > size - 9 - 1 && x < 9))) {
+ calcMatrix.forEach(d => {
+ var alignmentItem = modules[x + d[0]][y + d[1]];
+ alignmentItem.type.push('alignment');
+ alignmentItem.color = d[2] == 1 ? alignment.foregroundColor : alignment.backgroundColor;
+ });
+ }
+ }
+ }
+ }
+ },
+
+ paintTiming() {
+ let modules = this.modules;
+ let {
+ timing
+ } = this.options;
+
+ let timingPartLen = modules.length - 16;
+ for (let i = 0; i < timingPartLen; i++) {
+ var xItem = modules[6][8 + i];
+ var yItem = modules[8 + i][6];
+ xItem.type.push('timing');
+ yItem.type.push('timing');
+ xItem.color = (1 & i) ^ 1 ? timing.foregroundColor : timing.backgroundColor;
+ yItem.color = (1 & i) ^ 1 ? timing.foregroundColor : timing.backgroundColor;
+ }
+ },
+
+ paintDarkBlock() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ darkBlock
+ } = this.options;
+
+ //创建暗模块
+ var darkBlockItem = modules[size - 7 - 1][8];
+ darkBlockItem.type.push('darkBlock');
+ darkBlockItem.color = darkBlock.color;
+ },
+
+ paintVersionInformation() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ versionInformation,
+ typeNumber: version
+ } = this.options;
+
+ if (version < 7) {
+ return modules;
+ }
+ //预留版本信息 0 为补位,预留版本信息 是从索引7开始
+ const VERSIONS = [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ '000111110010010100',
+ '001000010110111100',
+ '001001101010011001',
+ '001010010011010011',
+ '001011101111110110',
+ '001100011101100010',
+ '001101100001000111',
+ '001110011000001101',
+ '001111100100101000',
+ '010000101101111000',
+ '010001010001011101',
+ '010010101000010111',
+ '010011010100110010',
+ '010100100110100110',
+ '010101011010000011',
+ '010110100011001001',
+ '010111011111101100',
+ '011000111011000100',
+ '011001000111100001',
+ '011010111110101011',
+ '011011000010001110',
+ '011100110000011010',
+ '011101001100111111',
+ '011110110101110101',
+ '011111001001010000',
+ '100000100111010101',
+ '100001011011110000',
+ '100010100010111010',
+ '100011011110011111',
+ '100100101100001011',
+ '100101010000101110',
+ '100110101001100100',
+ '100111010101000001',
+ '101000110001101001'
+ ];
+
+ //两种方式获取预留格式信息,临时计算或者查字典
+ //let version_codes = _v.correctVersionData(_v.version);
+ let version_codes = VERSIONS[version] + VERSIONS[version];
+ //创建预留版本信息
+ let disc = [size - 11, size - 10, size - 9];
+ // 左+右
+ let version_cells = [
+ //左
+ [5, disc[2]],
+ [5, disc[1]],
+ [5, disc[0]],
+ [4, disc[2]],
+ [4, disc[1]],
+ [4, disc[0]],
+ [3, disc[2]],
+ [3, disc[1]],
+ [3, disc[0]],
+ [2, disc[2]],
+ [2, disc[1]],
+ [2, disc[0]],
+ [1, disc[2]],
+ [1, disc[1]],
+ [1, disc[0]],
+ [0, disc[2]],
+ [0, disc[1]],
+ [0, disc[0]],
+ //右
+ [disc[2], 5],
+ [disc[1], 5],
+ [disc[0], 5],
+ [disc[2], 4],
+ [disc[1], 4],
+ [disc[0], 4],
+ [disc[2], 3],
+ [disc[1], 3],
+ [disc[0], 3],
+ [disc[2], 2],
+ [disc[1], 2],
+ [disc[0], 2],
+ [disc[2], 1],
+ [disc[1], 1],
+ [disc[0], 1],
+ [disc[2], 0],
+ [disc[1], 0],
+ [disc[0], 0]
+ ];
+ version_cells.forEach((d, index) => {
+ var versionInformationItem = modules[d[0]][d[1]];
+ versionInformationItem.type.push('versionInformation');
+ versionInformationItem.color = version_codes[index] == '1' ? versionInformation.foregroundColor : versionInformation.backgroundColor;
+ });
+ },
+
+ /**
+ * 绘制二维码方法
+ */
+ draw(options) {
+ options = uQRCode.deepReplace({
+ drawBackground: {
+ before: () => {},
+ after: () => {}
+ },
+ drawBackgroundImage: {
+ before: () => {},
+ after: () => {}
+ },
+ drawForeground: {
+ before: () => {},
+ after: () => {}
+ },
+ drawForegroundImage: {
+ before: () => {},
+ after: () => {}
+ }
+ }, options);
+
+ /* 绘制层级关系,最底层背景 -> 背景图片 -> 前景 -> 最顶层前景图片 */
+ return new Promise((resolve, reject) => {
+ let ctx = this.canvasContext;
+
+ const startup = () => {
+ /* 同时绘制多个二维码时使用队列绘制,防止内部方法冲突导致绘制失败 */
+ return uQRCode.Queue(() => new Promise((queueResolve, queueReject) => {
+ setTimeout(() => {
+ ctx.draw(false); // 第一个draw false可以清空画布
+ queueResolve();
+ }, 150);
+ }));
+ }
+ startup()
+ .then(() => {
+ /* 绘制背景 */
+ return this.drawBackground({
+ before: options.drawBackground.before,
+ after: options.drawBackground.after
+ });
+ })
+ .then(() => {
+ /* 绘制背景图片 */
+ return this.drawBackgroundImage({
+ before: options.drawBackgroundImage.before,
+ after: options.drawBackgroundImage.after
+ });
+ })
+ .then(() => {
+ /* 绘制前景 */
+ return this.drawForeground({
+ before: options.drawForeground.before,
+ after: options.drawForeground.after
+ });
+ })
+ .then(() => {
+ /* 绘制前景图片 */
+ return this.drawForegroundImage({
+ before: options.drawForegroundImage.before,
+ after: options.drawForegroundImage.after
+ });
+ })
+ .then(() => {
+ /* 完成绘制 */
+ resolve();
+ });
+ });
+ },
+
+ drawBackground({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ background
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ ctx.save();
+ /* 填充背景色 */
+ ctx.setFillStyle(background.color);
+ ctx.fillRect(0, 0, size, size);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawBackgroundImage({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ background
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ if (background.image.src) {
+ ctx.save();
+
+ let x = 0;
+ let y = 0;
+
+ let w = background.image.width * size;
+ let h = background.image.height * size;
+ let align = background.image.align;
+ let anchor = background.image.anchor;
+ let alpha = background.image.alpha;
+
+ switch (align[0]) {
+ case 'left':
+ x = 0;
+ break;
+ case 'center':
+ x = size / 2 - w / 2;
+ break;
+ case 'right':
+ x = size - w;
+ break;
+ }
+ x += Number(anchor[0]);
+
+ switch (align[1]) {
+ case 'top':
+ y = 0;
+ break;
+ case 'center':
+ y = size / 2 - h / 2;
+ break;
+ case 'bottom':
+ y = size - h;
+ break;
+ }
+ y += Number(anchor[1]);
+
+ /* 设置透明度 */
+ ctx.globalAlpha = alpha;
+
+ /* 绘制图片 */
+ const img = await this.loadImage(background.image.src);
+ ctx.drawImage(img, x, y, w, h);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+ }
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawForeground({
+ before,
+ after
+ }) {
+ let {
+ background
+ } = this.options;
+ let modules = this.modules;
+ let moduleCount = this.moduleCount;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ ctx.save();
+ for (var rowI = 0; rowI < moduleCount; rowI++) {
+ for (var colI = 0; colI < moduleCount; colI++) {
+ var tile = modules[rowI][colI];
+ if (!tile.isDrawn && tile.color != background.color) { // 颜色不能与背景色一致,否则可能发生颜色重叠
+ var color = tile.color;
+ ctx.setFillStyle(color);
+ ctx.fillRect(tile.x, tile.y, tile.size, tile.size);
+ tile.isDrawn = true;
+ }
+ }
+ }
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawForegroundImage({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ foreground
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ if (foreground.image.src) {
+ ctx.save();
+
+ // 绘制前景图
+ let x = 0;
+ let y = 0;
+
+ let w = foreground.image.width * size;
+ let h = foreground.image.height * size;
+ let align = foreground.image.align;
+ let anchor = foreground.image.anchor;
+ let alpha = foreground.image.alpha;
+ let shadow = foreground.image.shadow;
+ let border = foreground.image.border;
+
+ switch (align[0]) {
+ case 'left':
+ x = 0;
+ break;
+ case 'center':
+ x = size / 2 - w / 2;
+ break;
+ case 'right':
+ x = size - w;
+ break;
+ }
+ x += Number(anchor[0]);
+
+ switch (align[1]) {
+ case 'top':
+ y = 0;
+ break;
+ case 'center':
+ y = size / 2 - h / 2;
+ break;
+ case 'bottom':
+ y = size - h;
+ break;
+ }
+ y += Number(anchor[1]);
+
+ /* 绘制图片 */
+ const img = await this.loadImage(foreground.image.src);
+ ctx.drawImage(img, x, y, w, h);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+ }
+
+ await after(this);
+ resolve();
+ })();
+ });
+ }
+
+ }
+
+})();
+
+module.exports = uQRCode;
diff --git a/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/package.json b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/package.json
new file mode 100644
index 0000000..86328da
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "u-qrcode",
+ "version": "3.2.2",
+ "description": "uQRCode 二维码生成插件",
+ "main": "u-qrcode.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Sansnn/uQRCode.git"
+ },
+ "keywords": [
+ "QR",
+ "QRCode",
+ "uQRCode"
+ ],
+ "author": "Sansnn",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/Sansnn/uQRCode/issues"
+ },
+ "homepage": "https://github.com/Sansnn/uQRCode#readme"
+}
diff --git a/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/readme.md b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/readme.md
new file mode 100644
index 0000000..e5935be
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/readme.md
@@ -0,0 +1,274 @@
+# uQRCode
+
+**点击群号加入群聊【uQRCode交流群】:[695070434](https://jq.qq.com/?_wv=1027&k=JRjzDqiw)**
+
+uQRCode 生成方式简单,可扩展性高,适用所有前端应用和Node.js服务端,可运行到所有支持canvas的平台。支持NVUE(NVUE中使用GCanvas)。
+
+支持自定义二维码渲染规则,可通过uQRCode API得到矩阵信息后,自行实现canvas或view+css渲染二维码,如随机颜色、圆点、方块、块与块之间的间距等,详情参考示例项目。
+
+### 插件市场
+[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
+
+### github
+[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode)
+
+### npm
+[https://www.npmjs.com/package/u-qrcode](https://www.npmjs.com/package/u-qrcode)
+
+### 示例预览
+[https://static-c15f4b57-ef97-4d2b-b939-f580f910d7e2.bspapp.com](https://static-c15f4b57-ef97-4d2b-b939-f580f910d7e2.bspapp.com)
+
+### 二维码
+**什么是QR码**
+
+QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。
+
+**QR码的特点**
+
+一是高速读取(QR就是取自“Quick Response”的首字母),通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;
+
+二是高容量、高密度,理论上内容经过压缩处理后可以存7089个数字,4296个字母和数字混合字符,2953个8位字节数据,1817个汉字;
+
+三是支持纠错处理,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:
+- level L : 最大 7% 的错误能够被纠正;
+- level M : 最大 15% 的错误能够被纠正;
+- level Q : 最大 25% 的错误能够被纠正;
+- level H : 最大 30% 的错误能够被纠正;
+
+四是结构化,看似无规则的图形,其实对区域有严格的定义。
+
+更多二维码介绍及原理:[https://blog.csdn.net/jason_ldh/article/details/11801355](https://blog.csdn.net/jason_ldh/article/details/11801355)
+
+### 组件使用
+
+导入`u-qrcode`组件后,在 `template` 中创建 `` 组件
+
+```html
+
+```
+
+### 属性说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|canvasId |String |- |- |是 |组件标识/canvasId |
+|value |String |- |- |是 |二维码内容 |
+|size |Number |- |354 |否 |二维码大小,默认单位px,rpx需要使用uni.upx2px()转换|
+|options |Object |- |- |否 |参数可选项,详见下方options说明 |
+
+### 事件说明
+|事件名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|click |- |void |点击事件 |
+|complete |- |Object |生成完成事件,返回值success: true表示生成成功,false生成失败 |
+
+### 方法说明
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|remake |- |void |重新生成 |
+|toTempFilePath |Object:callback|void |导出临时路径 |
+|save |Object:callback|void |保存 |
+
+#### options说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|typeNumber |Number |- |-1 |否 |二维码版本 |
+|errorCorrectLevel |String/Number|L/M/Q/H/1/0/3/2|H |否 |纠错等级L/M/Q/H分别对应1/0/3/2 |
+|useDynamicSize |Boolean |- |false |否 |是否使用动态尺寸,可以去除二维码小块白色细线 |
+|margin |Number |- |0 |否 |填充边距,默认单位px |
+|background |Object |- |- |否 |背景设置,详见下方options.background说明 |
+|foreground |Object |- |- |否 |前景设置,详见下方options.foreground说明 |
+|positionDetection |Object |- |- |否 |定位角设置,详见下方options.positionDetection说明 |
+|separator |Object |- |- |否 |分割图案设置,详见下方options.separator说明 |
+|alignment |Object |- |- |否 |对齐图案设置,详见下方options.alignment说明 |
+|timing |Object |- |- |否 |时序图案设置,详见下方options.timing说明 |
+|darkBlock |Object |- |- |否 |暗块设置,详见下方options.darkBlock说明 |
+|versionInformation |Object |- |- |否 |版本信息设置,详见下方options.versionInformation说明 |
+
+#### options.background说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |#FFFFFF|否 |背景色,若需要透明背景可设置为rgba(0,0,0,0)|
+|image |Object |- |- |否 |背景图片设置,详见下方options.background.image说明|
+
+#### options.background.image说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|src |String |- |- |否 |背景图片路径 |
+|width |Number |- |1 |否 |指定背景图片宽度,1为二维码size的100% |
+|height |Number |- |1 |否 |指定背景图片高度,1为二维码size的100% |
+|align |Array|['left'/'center'/'right', 'top'/'center'/'bottom'] |['center', 'center'] |否 |指定背景图片对齐方式,[0]为水平方位,[1]为垂直方位 |
+|anchor |Array|- |[0, 0] |否 |指定背景图片锚点,[0]为X轴偏移量,[1]为Y轴偏移量 |
+|alpha |Number |0-1 |1 |否 |指定背景图片透明度 |
+
+#### options.foreground说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |#FFFFFF|否 |前景色 |
+|image |Object |- |- |否 |前景图片设置,详见下方options.foreground.image说明 |
+
+#### options.foreground.image说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|src |String |- |- |否 |前景图片路径 |
+|width |Number |- |1/4 |否 |指定前景图片宽度,1为二维码size的100% |
+|height |Number |- |1/4 |否 |指定前景图片高度,1为二维码size的100% |
+|align |Array|['left'/'center'/'right', 'top'/'center'/'bottom'] |['center', 'center'] |否 |指定前景图片对齐方式,[0]为水平方位,[1]为垂直方位 |
+|anchor |Array|- |[0, 0] |否 |指定前景图片锚点,[0]为X轴偏移量,[1]为Y轴偏移量 |
+
+#### options.positionDetection说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |定位角区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |定位角小块颜色,默认值跟随前景色 |
+
+#### options.separator说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |options.background.color |否 |分割区域颜色,默认值跟随背景色 |
+
+#### options.alignment说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |对齐区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |对齐小块颜色,默认值跟随前景色 |
+
+#### options.timing说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |时序区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |时序小块颜色,默认值跟随前景色 |
+
+#### options.darkBlock说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |options.foreground.color |否 |暗块颜色,默认值跟随前景色 |
+
+#### options.versionInformation说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |版本信息区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |版本信息小块颜色,默认值跟随前景色 |
+
+### u-qrcode.js使用
+
+引入u-qrcode.js
+
+``` javascript
+import uQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode';
+```
+
+或者使用npm安装
+
+> npm i u-qrcode
+
+``` javascript
+import uQRCode from 'u-qrcode';
+```
+
+nodejs引入
+
+``` javascript
+import uQRCode from 'u-qrcode/module';
+```
+
+在 `template` 中创建 `` 组件并设置 `id`,画布宽高
+
+```html
+
+```
+
+在 `script` 中调用生成方法
+
+```javascript
+import uQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode';
+
+export default {
+ data() {
+ return {
+ text: 'uQRCode',
+ size: 256
+ }
+ },
+ onReady() {
+ const ctx = uni.createCanvasContext('qrcode');
+ const uqrcode = new uQRCode(
+ {
+ text: this.text,
+ size: this.size
+ },
+ ctx
+ );
+ uqrcode.make();
+ uqrcode.draw();
+ }
+}
+```
+
+### new uQRCode(options, canvasContext, loadImage)说明
+
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|options |Object |- |- |是 |包含组件属性中的options的所有属性,详见下方options说明 |
+|canvasContext|Object |- |- |是 |canvas绘画上下文 |
+|loadImage |Promise|- |- |否 |绘制图片时,某些平台必传,例如微信小程序2d绘图需要创建Image对象,不能直接使用路径,这时就需要传入canvas.createImage给loadImage方法,否则无法绘制图片 |
+
+#### options说明,包含组件属性中的options的所有属性,下方仅列举未包含的属性,其余属性请移步到组件属性options说明查看
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|text |String |- |- |是 |二维码内容 |
+|size |Number |- |354 |否 |二维码大小 |
+
+### uQRCode实例属性
+|属性名 |类型 |说明 |
+|--- |--- |:--- |
+|options |Object |实例化传入的选项值 |
+|canvasContext|Object |画布实例 |
+|makeData |Object |制作二维码全部数据 |
+|modules |Array |制作二维码主要模块数据 |
+|moduleCount |Number |模块数量 |
+
+### uQRCode实例方法
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|make |- |void |制作二维码方法 |
+|draw |options|Promise|绘制二维码方法,绘制层级关系,最底层背景 -> 背景图片 -> 前景 -> 最顶层前景图片,options见下方说明 |
+
+#### draw(options)说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|drawBackground |Object: {before, after}|- |- |否 |绘制背景前后可执行自定义方法before,after |
+|drawBackgroundImage|Object: {before, after}|- |- |否 |绘制背景图前后可执行自定义方法before,after|
+|drawForeground |Object: {before, after}|- |- |否 |绘制前景前后可执行自定义方法before,after |
+|drawForegroundImage|Object: {before, after}|- |- |否 |绘制前景图前后可执行自定义方法before,after|
+
+### uQRCode静态属性
+|属性名 |类型 |说明 |
+|--- |--- |:--- |
+|errorCorrectLevel|Object |纠错等级 |
+|defaults |Object |预设默认值 |
+
+### uQRCode静态方法
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|deepReplace|o, r |替换后的新对象 |对象属性深度替换 |
+
+### 常见问题
+
+**如何扫码跳转指定网页**
+
+二维码内容直接放入完整的网页地址即可,例如:`https://ext.dcloud.net.cn/plugin?id=1287`。微信客户端不能是ip地址。
+
+**nvue打包后生成失败**
+
+Canvas是作为独立的模块,打包时需要选择使用Canvas模块才能正常使用相关的功能。 需要在manifest.json的代码视图中配置如下(暂时还不支持可视化界面操作):
+```javascript
+"app-plus" : {
+ /* 模块配置 */
+ "modules" : {
+ "Canvas" : "nvue canvas" //使用Canvas模块
+ },
+ //...
+},
+//...
+```
+保存好提交云端打包。
diff --git a/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/u-qrcode.js b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/u-qrcode.js
new file mode 100644
index 0000000..fa67ceb
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode/u-qrcode.js
@@ -0,0 +1,2285 @@
+//---------------------------------------------------------------------
+// uQRCode 二维码生成插件 v3.2.2
+//
+// uQRCode 是一款使用方式简单,高扩展的二维码生成插件。支持全端生成,支持canvas的地方就可以使用uQRCode。
+//
+// Copyright (c) Sansnn uQRCode All rights reserved.
+// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// 复制使用请保留本段注释,感谢支持开源!
+//
+// 开源地址:
+// https://github.com/Sansnn/uQRCode
+//
+// uni-app插件市场地址:
+// https://ext.dcloud.net.cn/plugin?id=1287
+//---------------------------------------------------------------------
+
+"use strict";
+
+function uQRCode(options, canvasContext, loadImage) {
+ this.options = uQRCode.getOptions(options);
+ this.canvasContext = uQRCode.getCanvasContext(canvasContext);
+ this.loadImage = uQRCode.getLoadImage(loadImage);
+}
+
+(function() {
+ //---------------------------------------------------------------------
+ // QRCode for JavaScript
+ //
+ // Copyright (c) 2009 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word "QR Code" is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ //---------------------------------------------------------------------
+ // QR8bitByte
+ //---------------------------------------------------------------------
+
+ function QR8bitByte(data) {
+ this.mode = QRMode.MODE_8BIT_BYTE;
+ this.data = data;
+ }
+
+ QR8bitByte.prototype = {
+
+ getLength: function(buffer) {
+ return this.data.length;
+ },
+
+ write: function(buffer) {
+ for (var i = 0; i < this.data.length; i++) {
+ // not JIS ...
+ buffer.put(this.data.charCodeAt(i), 8);
+ }
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRCode
+ //---------------------------------------------------------------------
+
+ function QRCode(typeNumber, errorCorrectLevel) {
+ this.typeNumber = typeNumber;
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.modules = null;
+ this.moduleCount = 0;
+ this.dataCache = null;
+ this.dataList = new Array();
+ }
+
+ QRCode.prototype = {
+
+ addData: function(data) {
+ var newData = new QR8bitByte(data);
+ this.dataList.push(newData);
+ this.dataCache = null;
+ },
+
+ isDark: function(row, col) {
+ if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+ throw new Error(row + "," + col);
+ }
+ return this.modules[row][col];
+ },
+
+ getModuleCount: function() {
+ return this.moduleCount;
+ },
+
+ make: function() {
+ // Calculate automatically typeNumber if provided is < 1
+ if (this.typeNumber < 1) {
+ var typeNumber = 1;
+ for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ for (var i = 0; i < this.dataList.length; i++) {
+ var data = this.dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+ if (buffer.getLengthInBits() <= totalDataCount * 8)
+ break;
+ }
+ this.typeNumber = typeNumber;
+ }
+ this.makeImpl(false, this.getBestMaskPattern());
+ },
+
+ makeImpl: function(test, maskPattern) {
+
+ this.moduleCount = this.typeNumber * 4 + 17;
+ this.modules = new Array(this.moduleCount);
+
+ for (var row = 0; row < this.moduleCount; row++) {
+
+ this.modules[row] = new Array(this.moduleCount);
+
+ for (var col = 0; col < this.moduleCount; col++) {
+ this.modules[row][col] = null; //(col + row) % 3;
+ }
+ }
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this.typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this.dataCache == null) {
+ this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+ }
+
+ this.mapData(this.dataCache, maskPattern);
+ },
+
+ setupPositionProbePattern: function(row, col) {
+
+ for (var r = -1; r <= 7; r++) {
+
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c++) {
+
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ },
+
+ getBestMaskPattern: function() {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i++) {
+
+ this.makeImpl(true, i);
+
+ var lostPoint = QRUtil.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ },
+
+ createMovieClip: function(target_mc, instance_name, depth) {
+
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+ var cs = 1;
+
+ this.make();
+
+ for (var row = 0; row < this.modules.length; row++) {
+
+ var y = row * cs;
+
+ for (var col = 0; col < this.modules[row].length; col++) {
+
+ var x = col * cs;
+ var dark = this.modules[row][col];
+
+ if (dark) {
+ qr_mc.beginFill(0, 100);
+ qr_mc.moveTo(x, y);
+ qr_mc.lineTo(x + cs, y);
+ qr_mc.lineTo(x + cs, y + cs);
+ qr_mc.lineTo(x, y + cs);
+ qr_mc.endFill();
+ }
+ }
+ }
+
+ return qr_mc;
+ },
+
+ setupTimingPattern: function() {
+
+ for (var r = 8; r < this.moduleCount - 8; r++) {
+ if (this.modules[r][6] != null) {
+ continue;
+ }
+ this.modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < this.moduleCount - 8; c++) {
+ if (this.modules[6][c] != null) {
+ continue;
+ }
+ this.modules[6][c] = (c % 2 == 0);
+ }
+ },
+
+ setupPositionAdjustPattern: function() {
+
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+ for (var i = 0; i < pos.length; i++) {
+
+ for (var j = 0; j < pos.length; j++) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (this.modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r++) {
+
+ for (var c = -2; c <= 2; c++) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2 ||
+ (r == 0 && c == 0)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ },
+
+ setupTypeNumber: function(test) {
+
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ },
+
+ setupTypeInfo: function(test, maskPattern) {
+
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
+ var bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ this.modules[i][8] = mod;
+ } else if (i < 8) {
+ this.modules[i + 1][8] = mod;
+ } else {
+ this.modules[this.moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ this.modules[8][this.moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this.modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this.modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this.modules[this.moduleCount - 8][8] = (!test);
+
+ },
+
+ mapData: function(data, maskPattern) {
+
+ var inc = -1;
+ var row = this.moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col--;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c++) {
+
+ if (this.modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this.modules[row][col - c] = dark;
+ bitIndex--;
+
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this.moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+
+ }
+
+ };
+
+ QRCode.PAD0 = 0xEC;
+ QRCode.PAD1 = 0x11;
+
+ QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+
+ for (var i = 0; i < dataList.length; i++) {
+ var data = dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error("code length overflow. (" +
+ buffer.getLengthInBits() +
+ ">" +
+ totalDataCount * 8 +
+ ")");
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD1, 8);
+ }
+
+ return QRCode.createBytes(buffer, rsBlocks);
+ }
+
+ QRCode.createBytes = function(buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r++) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i++) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = dcdata[r][i];
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+
+ }
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+
+ var QRMode = {
+ MODE_NUMBER: 1 << 0,
+ MODE_ALPHA_NUM: 1 << 1,
+ MODE_8BIT_BYTE: 1 << 2,
+ MODE_KANJI: 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+
+ var QRErrorCorrectLevel = {
+ L: 1,
+ M: 0,
+ Q: 3,
+ H: 2
+ };
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+
+ var QRMaskPattern = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ var QRUtil = {
+
+ PATTERN_POSITION_TABLE: [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ],
+
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+ getBCHTypeInfo: function(data) {
+ var d = data << 10;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+ d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+ }
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
+ },
+
+ getBCHTypeNumber: function(data) {
+ var d = data << 12;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+ d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+ }
+ return (data << 12) | d;
+ },
+
+ getBCHDigit: function(data) {
+
+ var digit = 0;
+
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+
+ return digit;
+ },
+
+ getPatternPosition: function(typeNumber) {
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+ },
+
+ getMask: function(maskPattern, i, j) {
+
+ switch (maskPattern) {
+
+ case QRMaskPattern.PATTERN000:
+ return (i + j) % 2 == 0;
+ case QRMaskPattern.PATTERN001:
+ return i % 2 == 0;
+ case QRMaskPattern.PATTERN010:
+ return j % 3 == 0;
+ case QRMaskPattern.PATTERN011:
+ return (i + j) % 3 == 0;
+ case QRMaskPattern.PATTERN100:
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+ case QRMaskPattern.PATTERN101:
+ return (i * j) % 2 + (i * j) % 3 == 0;
+ case QRMaskPattern.PATTERN110:
+ return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case QRMaskPattern.PATTERN111:
+ return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default:
+ throw new Error("bad maskPattern:" + maskPattern);
+ }
+ },
+
+ getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+ var a = new QRPolynomial([1], 0);
+
+ for (var i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+ }
+
+ return a;
+ },
+
+ getLengthInBits: function(mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 10;
+ case QRMode.MODE_ALPHA_NUM:
+ return 9;
+ case QRMode.MODE_8BIT_BYTE:
+ return 8;
+ case QRMode.MODE_KANJI:
+ return 8;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 12;
+ case QRMode.MODE_ALPHA_NUM:
+ return 11;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 10;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 14;
+ case QRMode.MODE_ALPHA_NUM:
+ return 13;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 12;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else {
+ throw new Error("type:" + type);
+ }
+ },
+
+ getLostPoint: function(qrCode) {
+
+ var moduleCount = qrCode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row++) {
+
+ for (var col = 0; col < moduleCount; col++) {
+
+ var sameCount = 0;
+ var dark = qrCode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r++) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c++) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row++) {
+ for (var col = 0; col < moduleCount - 1; col++) {
+ var count = 0;
+ if (qrCode.isDark(row, col)) count++;
+ if (qrCode.isDark(row + 1, col)) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row++) {
+ for (var col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row, col + 1) &&
+ qrCode.isDark(row, col + 2) &&
+ qrCode.isDark(row, col + 3) &&
+ qrCode.isDark(row, col + 4) &&
+ !qrCode.isDark(row, col + 5) &&
+ qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row + 1, col) &&
+ qrCode.isDark(row + 2, col) &&
+ qrCode.isDark(row + 3, col) &&
+ qrCode.isDark(row + 4, col) &&
+ !qrCode.isDark(row + 5, col) &&
+ qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ var QRMath = {
+
+ glog: function(n) {
+
+ if (n < 1) {
+ throw new Error("glog(" + n + ")");
+ }
+
+ return QRMath.LOG_TABLE[n];
+ },
+
+ gexp: function(n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return QRMath.EXP_TABLE[n];
+ },
+
+ EXP_TABLE: new Array(256),
+
+ LOG_TABLE: new Array(256)
+
+ };
+
+ for (var i = 0; i < 8; i++) {
+ QRMath.EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i++) {
+ QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+ QRMath.EXP_TABLE[i - 5] ^
+ QRMath.EXP_TABLE[i - 6] ^
+ QRMath.EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i++) {
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+ }
+
+ //---------------------------------------------------------------------
+ // QRPolynomial
+ //---------------------------------------------------------------------
+
+ function QRPolynomial(num, shift) {
+
+ if (num.length == undefined) {
+ throw new Error(num.length + "/" + shift);
+ }
+
+ var offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i++) {
+ this.num[i] = num[i + offset];
+ }
+ }
+
+ QRPolynomial.prototype = {
+
+ get: function(index) {
+ return this.num[index];
+ },
+
+ getLength: function() {
+ return this.num.length;
+ },
+
+ multiply: function(e) {
+
+ var num = new Array(this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < this.getLength(); i++) {
+ for (var j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+ }
+ }
+
+ return new QRPolynomial(num, 0);
+ },
+
+ mod: function(e) {
+
+ if (this.getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+ var num = new Array(this.getLength());
+
+ for (var i = 0; i < this.getLength(); i++) {
+ num[i] = this.get(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+ }
+
+ // recursive call
+ return new QRPolynomial(num, 0).mod(e);
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ function QRRSBlock(totalCount, dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ QRRSBlock.RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16],
+
+ // 11
+ [4, 101, 81],
+ [1, 80, 50, 4, 81, 51],
+ [4, 50, 22, 4, 51, 23],
+ [3, 36, 12, 8, 37, 13],
+
+ // 12
+ [2, 116, 92, 2, 117, 93],
+ [6, 58, 36, 2, 59, 37],
+ [4, 46, 20, 6, 47, 21],
+ [7, 42, 14, 4, 43, 15],
+
+ // 13
+ [4, 133, 107],
+ [8, 59, 37, 1, 60, 38],
+ [8, 44, 20, 4, 45, 21],
+ [12, 33, 11, 4, 34, 12],
+
+ // 14
+ [3, 145, 115, 1, 146, 116],
+ [4, 64, 40, 5, 65, 41],
+ [11, 36, 16, 5, 37, 17],
+ [11, 36, 12, 5, 37, 13],
+
+ // 15
+ [5, 109, 87, 1, 110, 88],
+ [5, 65, 41, 5, 66, 42],
+ [5, 54, 24, 7, 55, 25],
+ [11, 36, 12],
+
+ // 16
+ [5, 122, 98, 1, 123, 99],
+ [7, 73, 45, 3, 74, 46],
+ [15, 43, 19, 2, 44, 20],
+ [3, 45, 15, 13, 46, 16],
+
+ // 17
+ [1, 135, 107, 5, 136, 108],
+ [10, 74, 46, 1, 75, 47],
+ [1, 50, 22, 15, 51, 23],
+ [2, 42, 14, 17, 43, 15],
+
+ // 18
+ [5, 150, 120, 1, 151, 121],
+ [9, 69, 43, 4, 70, 44],
+ [17, 50, 22, 1, 51, 23],
+ [2, 42, 14, 19, 43, 15],
+
+ // 19
+ [3, 141, 113, 4, 142, 114],
+ [3, 70, 44, 11, 71, 45],
+ [17, 47, 21, 4, 48, 22],
+ [9, 39, 13, 16, 40, 14],
+
+ // 20
+ [3, 135, 107, 5, 136, 108],
+ [3, 67, 41, 13, 68, 42],
+ [15, 54, 24, 5, 55, 25],
+ [15, 43, 15, 10, 44, 16],
+
+ // 21
+ [4, 144, 116, 4, 145, 117],
+ [17, 68, 42],
+ [17, 50, 22, 6, 51, 23],
+ [19, 46, 16, 6, 47, 17],
+
+ // 22
+ [2, 139, 111, 7, 140, 112],
+ [17, 74, 46],
+ [7, 54, 24, 16, 55, 25],
+ [34, 37, 13],
+
+ // 23
+ [4, 151, 121, 5, 152, 122],
+ [4, 75, 47, 14, 76, 48],
+ [11, 54, 24, 14, 55, 25],
+ [16, 45, 15, 14, 46, 16],
+
+ // 24
+ [6, 147, 117, 4, 148, 118],
+ [6, 73, 45, 14, 74, 46],
+ [11, 54, 24, 16, 55, 25],
+ [30, 46, 16, 2, 47, 17],
+
+ // 25
+ [8, 132, 106, 4, 133, 107],
+ [8, 75, 47, 13, 76, 48],
+ [7, 54, 24, 22, 55, 25],
+ [22, 45, 15, 13, 46, 16],
+
+ // 26
+ [10, 142, 114, 2, 143, 115],
+ [19, 74, 46, 4, 75, 47],
+ [28, 50, 22, 6, 51, 23],
+ [33, 46, 16, 4, 47, 17],
+
+ // 27
+ [8, 152, 122, 4, 153, 123],
+ [22, 73, 45, 3, 74, 46],
+ [8, 53, 23, 26, 54, 24],
+ [12, 45, 15, 28, 46, 16],
+
+ // 28
+ [3, 147, 117, 10, 148, 118],
+ [3, 73, 45, 23, 74, 46],
+ [4, 54, 24, 31, 55, 25],
+ [11, 45, 15, 31, 46, 16],
+
+ // 29
+ [7, 146, 116, 7, 147, 117],
+ [21, 73, 45, 7, 74, 46],
+ [1, 53, 23, 37, 54, 24],
+ [19, 45, 15, 26, 46, 16],
+
+ // 30
+ [5, 145, 115, 10, 146, 116],
+ [19, 75, 47, 10, 76, 48],
+ [15, 54, 24, 25, 55, 25],
+ [23, 45, 15, 25, 46, 16],
+
+ // 31
+ [13, 145, 115, 3, 146, 116],
+ [2, 74, 46, 29, 75, 47],
+ [42, 54, 24, 1, 55, 25],
+ [23, 45, 15, 28, 46, 16],
+
+ // 32
+ [17, 145, 115],
+ [10, 74, 46, 23, 75, 47],
+ [10, 54, 24, 35, 55, 25],
+ [19, 45, 15, 35, 46, 16],
+
+ // 33
+ [17, 145, 115, 1, 146, 116],
+ [14, 74, 46, 21, 75, 47],
+ [29, 54, 24, 19, 55, 25],
+ [11, 45, 15, 46, 46, 16],
+
+ // 34
+ [13, 145, 115, 6, 146, 116],
+ [14, 74, 46, 23, 75, 47],
+ [44, 54, 24, 7, 55, 25],
+ [59, 46, 16, 1, 47, 17],
+
+ // 35
+ [12, 151, 121, 7, 152, 122],
+ [12, 75, 47, 26, 76, 48],
+ [39, 54, 24, 14, 55, 25],
+ [22, 45, 15, 41, 46, 16],
+
+ // 36
+ [6, 151, 121, 14, 152, 122],
+ [6, 75, 47, 34, 76, 48],
+ [46, 54, 24, 10, 55, 25],
+ [2, 45, 15, 64, 46, 16],
+
+ // 37
+ [17, 152, 122, 4, 153, 123],
+ [29, 74, 46, 14, 75, 47],
+ [49, 54, 24, 10, 55, 25],
+ [24, 45, 15, 46, 46, 16],
+
+ // 38
+ [4, 152, 122, 18, 153, 123],
+ [13, 74, 46, 32, 75, 47],
+ [48, 54, 24, 14, 55, 25],
+ [42, 45, 15, 32, 46, 16],
+
+ // 39
+ [20, 147, 117, 4, 148, 118],
+ [40, 75, 47, 7, 76, 48],
+ [43, 54, 24, 22, 55, 25],
+ [10, 45, 15, 67, 46, 16],
+
+ // 40
+ [19, 148, 118, 6, 149, 119],
+ [18, 75, 47, 31, 76, 48],
+ [34, 54, 24, 34, 55, 25],
+ [20, 45, 15, 61, 46, 16]
+ ];
+
+ QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+ var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (rsBlock == undefined) {
+ throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" +
+ errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i++) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j++) {
+ list.push(new QRRSBlock(totalCount, dataCount));
+ }
+ }
+
+ return list;
+ }
+
+ QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+ switch (errorCorrectLevel) {
+ case QRErrorCorrectLevel.L:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRErrorCorrectLevel.M:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRErrorCorrectLevel.Q:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRErrorCorrectLevel.H:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default:
+ return undefined;
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // QRBitBuffer
+ //---------------------------------------------------------------------
+
+ function QRBitBuffer() {
+ this.buffer = new Array();
+ this.length = 0;
+ }
+
+ QRBitBuffer.prototype = {
+
+ get: function(index) {
+ var bufIndex = Math.floor(index / 8);
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+ },
+
+ put: function(num, length) {
+ for (var i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+ }
+ },
+
+ getLengthInBits: function() {
+ return this.length;
+ },
+
+ putBit: function(bit) {
+
+ var bufIndex = Math.floor(this.length / 8);
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0);
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+ }
+
+ this.length++;
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // Support Chinese 字符编码支持中文
+ // 使用mode 4 8bit
+ //---------------------------------------------------------------------
+ function utf16To8(text) {
+ var result = '';
+ var c;
+ for (var i = 0; i < text.length; i++) {
+ c = text.charCodeAt(i);
+ if (c >= 0x0001 && c <= 0x007F) {
+ result += text.charAt(i);
+ } else if (c > 0x07FF) {
+ result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+ result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ } else {
+ result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 队列
+ */
+ class Queue {
+ constructor() {
+ let waitingQueue = [];
+ let isRunning = false; //记录是否有未完成的任务
+ function execute(task, resolve, reject) {
+ task()
+ .then((data) => {
+ resolve(data);
+ })
+ .catch((e) => {
+ reject(e);
+ })
+ .finally(() => {
+ //等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
+ if (waitingQueue.length) {
+ const next = waitingQueue.shift();
+ execute(next.task, next.resolve, next.reject);
+ } else {
+ isRunning = false;
+ }
+ });
+ }
+ return function(task) {
+ return new Promise((resolve, reject) => {
+ if (isRunning) {
+ waitingQueue.push({
+ task,
+ resolve,
+ reject
+ });
+ } else {
+ isRunning = true;
+ execute(task, resolve, reject);
+ }
+ });
+ };
+ }
+ }
+ // const queue = new Queue();
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task1');
+ // }, 1000);
+ // })).then(data => console.log(data));
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task2');
+ // }, 100);
+ // })).then(data => console.log(data));
+ // queue(() => new Promise((resolve, reject) => {
+ // setTimeout(() => {
+ // resolve('task3');
+ // }, 300);
+ // })).then(data => console.log(data));
+
+ /**
+ * 纠错等级
+ */
+ uQRCode.errorCorrectLevel = QRErrorCorrectLevel;
+
+ /**
+ * 预设默认值(基本,不包含各部分和艺术码参数)
+ */
+ uQRCode.defaults = {
+ typeNumber: -1, // 版本,-1为自动计算,字符越多,版本越高
+ errorCorrectLevel: QRErrorCorrectLevel.H, // 纠错等级
+ text: '', // 二维码内容
+ size: 354, // 大小
+ useDynamicSize: false, // 使用动态尺寸,可以去掉方块小数点,绘制出来后没有白色细线
+ margin: 0, // 边距
+ background: {
+ color: '#FFFFFF' // 背景色
+ },
+ foreground: {
+ color: '#000000' // 前景色
+ }
+ }
+
+ /**
+ * 对象属性深度替换
+ * @param {Object} o 原始对象/默认对象/被替换的对象
+ * @param {Object} r 从这个对象里取值替换到o对象里
+ * @return {Object} 替换后的新对象
+ */
+ uQRCode.deepReplace = function(o = {}, r = {}) {
+ let obj = {
+ ...o
+ }
+ for (let k in r) {
+ var vr = r[k];
+ if (vr.constructor == Object) {
+ obj[k] = this.deepReplace(obj[k], vr);
+ } else if (vr.constructor == String && !vr) {
+ obj[k] = obj[k];
+ } else {
+ obj[k] = vr;
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * 获取选项值
+ */
+ uQRCode.getOptions = function(options) {
+ options = uQRCode.deepReplace(uQRCode.defaults, options);
+
+ /* 背景 */
+ options.background = uQRCode.deepReplace({
+ color: options.background.color, // 背景色
+ image: {
+ src: '',
+ width: 1, // 图片宽
+ height: 1, // 图片高
+ align: ['center', 'center'], // 图片对齐方式水平,垂直
+ anchor: [0, 0], // 图片位置,X坐标,Y坐标
+ alpha: 1 // 透明度
+ }
+ }, options.background);
+ /* 前景 */
+ options.foreground = uQRCode.deepReplace({
+ color: options.foreground.color, // 前景色
+ image: {
+ src: '',
+ width: 1 / 4, // 图片宽
+ height: 1 / 4, // 图片高
+ align: ['center', 'center'], // 图片对齐方式水平,垂直
+ anchor: [0, 0] // 图片位置,X坐标,Y坐标
+ }
+ }, options.foreground);
+ /* 定位角 */
+ options.positionDetection = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 定位角区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 定位角小块颜色,默认值跟随前景色
+ }, options.positionDetection);
+ /* 分割图案 */
+ options.separator = uQRCode.deepReplace({
+ color: options.background.color // 分割区域颜色,默认值跟随背景色
+ }, options.separator);
+ /* 对齐图案 */
+ options.alignment = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 对齐区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 对齐小块颜色,默认值跟随前景色
+ }, options.alignment);
+ /* 时序图案 */
+ options.timing = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 时序区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 时序小块颜色,默认值跟随前景色
+ }, options.timing);
+ /* 暗块 */
+ options.darkBlock = uQRCode.deepReplace({
+ color: options.foreground.color // 暗块颜色
+ }, options.darkBlock);
+ /* 版本信息 */
+ options.versionInformation = uQRCode.deepReplace({
+ backgroundColor: options.background.color, // 版本信息区域背景色,默认值跟随背景色
+ foregroundColor: options.foreground.color // 版本信息小块颜色,默认值跟随前景色
+ }, options.versionInformation);
+
+ return options;
+ }
+
+ /**
+ * 获取canvas实例
+ */
+ uQRCode.getCanvasContext = function(ctx) {
+ /* 兼容setFillStyle写法,主要在uni-app nvue gcanvas */
+ ctx.setFillStyle = ctx.setFillStyle || function(color) {
+ ctx.fillStyle = color;
+ }
+ /* 兼容setFontSize写法,主要在微信小程序canvas2d */
+ ctx.setFontSize = ctx.setFontSize || function(fontSize) {
+ ctx.font = `${fontSize}px`;
+ }
+ /* 兼容setTextAlign写法,主要在微信小程序canvas2d */
+ ctx.setTextAlign = ctx.setTextAlign || function(align) {
+ ctx.textAlign = align;
+ }
+ /* 兼容setTextBaseline写法,主要在微信小程序canvas2d */
+ ctx.setTextBaseline = ctx.setTextBaseline || function(textBaseline) {
+ ctx.textBaseline = textBaseline;
+ }
+ /* 若实例不包含draw方法则创建一个 */
+ ctx.draw = ctx.draw || function(reserve, callback) {
+ callback && callback();
+ }
+ return ctx;
+ }
+
+ /* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */
+ uQRCode.Queue = new Queue();
+ uQRCode.QueueLoadImage = new Queue();
+
+ /* 缓存loadImage图片 */
+ uQRCode.loadImageCache = [];
+
+ /**
+ * 获取加载图片方法
+ */
+ uQRCode.getLoadImage = function(loadImage) {
+ if (typeof loadImage == 'function') {
+ return function(src) {
+ /* 解决iOS APP||NVUE同时绘制多个二维码导致图片丢失需使用队列 */
+ return uQRCode.QueueLoadImage(() => new Promise((resolve, reject) => {
+ setTimeout(() => {
+ const cache = uQRCode.loadImageCache.find(x => x.src == src);
+ if (cache) {
+ resolve(cache.img);
+ } else {
+ loadImage(src).then(img => {
+ uQRCode.loadImageCache.push({
+ src,
+ img
+ });
+ resolve(img);
+ });
+ }
+ }, 150);
+ }));
+ }
+ } else {
+ return function(src) {
+ return Promise.resolve(src);
+ }
+ }
+ }
+
+ uQRCode.prototype = {
+ /**
+ * 实例化传入的选项值
+ */
+ options: {},
+
+ /**
+ * 画布实例
+ */
+ canvasContext: {},
+
+ /**
+ * 制作二维码全部数据
+ */
+ makeData: {},
+
+ /**
+ * 制作二维码主要模块数据,基于makeData的modules但数据格式不一致,这里的modules是定制过的
+ */
+ modules: [],
+
+ /**
+ * 模块数量
+ */
+ moduleCount: 0,
+
+ /**
+ * 获取制作二维码数据
+ */
+ getMakeData() {
+ let {
+ typeNumber,
+ errorCorrectLevel,
+ text
+ } = this.options;
+ var qrcode = new QRCode(typeNumber, errorCorrectLevel);
+ qrcode.addData(utf16To8(text.toString()));
+ qrcode.make();
+ return qrcode;
+ },
+
+ /**
+ * 制作二维码方法
+ */
+ make() {
+ let makeData = this.makeData = this.getMakeData();
+ this.modules = JSON.parse(JSON.stringify(makeData.modules));
+ this.moduleCount = makeData.moduleCount;
+ this.options.typeNumber = makeData.typeNumber;
+
+ /* 数据码 data */
+ this.paintData();
+ /* 定位图案 position detection */
+ this.paintPositionDetection();
+ /* 分隔图案 separator */
+ this.paintSeparator();
+ /* 对齐图案 alignment */
+ this.paintAlignment();
+ /* 时序图案 timing */
+ this.paintTiming();
+ /* 暗块 darkBlock */
+ this.paintDarkBlock();
+ /* 预留版本信息 version information */
+ this.paintVersionInformation();
+ },
+
+ paintData() {
+ let modules = this.modules;
+ let moduleCount = this.moduleCount;
+ let {
+ size,
+ margin,
+ background,
+ foreground,
+ useDynamicSize
+ } = this.options;
+
+ /* dynamicSize自动计算出最适合绘制的尺寸,并按这个尺寸去绘制,可以解决canvas绘制小块间产生白线的问题(其实就是小数点精度问题),useDynamicSize=false可以取消这个设定 */
+ // let dynamicSize = this.options.dynamicSize = Math.floor((size - margin * 2) / moduleCount) * moduleCount + margin * 2; // Math.floor向下取整缩放会模糊
+ let dynamicSize = this.options.dynamicSize = Math.ceil((size - margin * 2) / moduleCount) * moduleCount + margin * 2; // Math.ceil向上取整缩放效果比floor清晰
+ if (!useDynamicSize) {
+ dynamicSize = this.options.dynamicSize = size;
+ }
+ let tileSize = (dynamicSize - margin * 2) / moduleCount;
+
+ for (var rowI = 0; rowI < modules.length; rowI++) {
+ for (var colI = 0; colI < modules.length; colI++) {
+ var tile = modules[rowI][colI];
+ if (tile) {
+ modules[rowI][colI] = {
+ size: tileSize,
+ x: colI * tileSize + margin,
+ y: rowI * tileSize + margin,
+ type: ['foreground'],
+ color: foreground.color,
+ isBlack: true,
+ isDrawn: false
+ };
+ } else {
+ modules[rowI][colI] = {
+ size: tileSize,
+ x: colI * tileSize + margin,
+ y: rowI * tileSize + margin,
+ type: ['background'],
+ color: background.color,
+ isBlack: false,
+ isDrawn: false
+ };
+ }
+ }
+ }
+ },
+
+ paintPositionDetection() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ positionDetection
+ } = this.options;
+
+ //1) 定义基础图形索引(左上角)x ,y,v
+ let basePart = [
+ [0, 0, 1],
+ [1, 0, 1],
+ [2, 0, 1],
+ [3, 0, 1],
+ [4, 0, 1],
+ [5, 0, 1],
+ [6, 0, 1],
+ [0, 1, 1],
+ [1, 1, 0],
+ [2, 1, 0],
+ [3, 1, 0],
+ [4, 1, 0],
+ [5, 1, 0],
+ [6, 1, 1],
+ [0, 2, 1],
+ [1, 2, 0],
+ [2, 2, 1],
+ [3, 2, 1],
+ [4, 2, 1],
+ [5, 2, 0],
+ [6, 2, 1],
+ [0, 3, 1],
+ [1, 3, 0],
+ [2, 3, 1],
+ [3, 3, 1],
+ [4, 3, 1],
+ [5, 3, 0],
+ [6, 3, 1],
+ [0, 4, 1],
+ [1, 4, 0],
+ [2, 4, 1],
+ [3, 4, 1],
+ [4, 4, 1],
+ [5, 4, 0],
+ [6, 4, 1],
+ [0, 5, 1],
+ [1, 5, 0],
+ [2, 5, 0],
+ [3, 5, 0],
+ [4, 5, 0],
+ [5, 5, 0],
+ [6, 5, 1],
+ [0, 6, 1],
+ [1, 6, 1],
+ [2, 6, 1],
+ [3, 6, 1],
+ [4, 6, 1],
+ [5, 6, 1],
+ [6, 6, 1]
+ ];
+ let disc = size - 7; //size -7
+ basePart.forEach(d => {
+ var ltItem = modules[d[0]][d[1]];
+ var rtItem = modules[d[0] + disc][d[1]];
+ var lbItem = modules[d[0]][d[1] + disc];
+ lbItem.type.push('positionDetection');
+ rtItem.type.push('positionDetection');
+ ltItem.type.push('positionDetection');
+ //绘制左上角
+ ltItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ //绘制右
+ rtItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ //绘制左
+ lbItem.color = d[2] == 1 ? positionDetection.foregroundColor : positionDetection.backgroundColor;
+ });
+ },
+
+ paintSeparator() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ separator
+ } = this.options;
+
+ //1) 定义基础图形索引(左上角)
+ [
+ [7, 0],
+ [7, 1],
+ [7, 2],
+ [7, 3],
+ [7, 4],
+ [7, 5],
+ [7, 6],
+ [7, 7],
+ [0, 7],
+ [1, 7],
+ [2, 7],
+ [3, 7],
+ [4, 7],
+ [5, 7],
+ [6, 7]
+ ].forEach(d => {
+ var ltItem = modules[d[0]][d[1]];
+ var rtItem = modules[size - d[0] - 1][d[1]];
+ var lbItem = modules[d[0]][size - d[1] - 1];
+ lbItem.type.push('separator');
+ rtItem.type.push('separator');
+ ltItem.type.push('separator');
+ //绘制左上
+ ltItem.color = separator.color;
+ //绘制右
+ rtItem.color = separator.color;
+ //绘制左
+ lbItem.color = separator.color;
+ });
+ },
+
+ paintAlignment() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ alignment,
+ typeNumber
+ } = this.options;
+
+ //不同版本的对齐图案组合位置
+ const ALIGNMENT_OF_VERSION = [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ];
+ // 对齐图案数量和中心位置根据版本定义
+ const alignments = ALIGNMENT_OF_VERSION[typeNumber - 1];
+ if (alignments) {
+ const calcMatrix = [
+ [-2, -2, 1],
+ [-1, -2, 1],
+ [0, -2, 1],
+ [1, -2, 1],
+ [2, -2, 1],
+ [-2, -1, 1],
+ [-1, -1, 0],
+ [0, -1, 0],
+ [1, -1, 0],
+ [2, -1, 1],
+ [-2, 0, 1],
+ [-1, 0, 0],
+ [0, 0, 1],
+ [1, 0, 0],
+ [2, 0, 1],
+ [-2, 1, 1],
+ [-1, 1, 0],
+ [0, 1, 0],
+ [1, 1, 0],
+ [2, 1, 1],
+ [-2, 2, 1],
+ [-1, 2, 1],
+ [0, 2, 1],
+ [1, 2, 1],
+ [2, 2, 1]
+ ];
+ const group_len = alignments.length;
+ for (let i = 0; i < group_len; i++) {
+ for (let j = 0; j < group_len; j++) {
+ //对齐图案不能污染 定位器和分隔器
+ let {
+ x,
+ y
+ } = {
+ x: alignments[i],
+ y: alignments[j]
+ };
+ if (!((x < 9 && y < 9) || (x > size - 9 - 1 && y < 9) || (y > size - 9 - 1 && x < 9))) {
+ calcMatrix.forEach(d => {
+ var alignmentItem = modules[x + d[0]][y + d[1]];
+ alignmentItem.type.push('alignment');
+ alignmentItem.color = d[2] == 1 ? alignment.foregroundColor : alignment.backgroundColor;
+ });
+ }
+ }
+ }
+ }
+ },
+
+ paintTiming() {
+ let modules = this.modules;
+ let {
+ timing
+ } = this.options;
+
+ let timingPartLen = modules.length - 16;
+ for (let i = 0; i < timingPartLen; i++) {
+ var xItem = modules[6][8 + i];
+ var yItem = modules[8 + i][6];
+ xItem.type.push('timing');
+ yItem.type.push('timing');
+ xItem.color = (1 & i) ^ 1 ? timing.foregroundColor : timing.backgroundColor;
+ yItem.color = (1 & i) ^ 1 ? timing.foregroundColor : timing.backgroundColor;
+ }
+ },
+
+ paintDarkBlock() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ darkBlock
+ } = this.options;
+
+ //创建暗模块
+ var darkBlockItem = modules[size - 7 - 1][8];
+ darkBlockItem.type.push('darkBlock');
+ darkBlockItem.color = darkBlock.color;
+ },
+
+ paintVersionInformation() {
+ let modules = this.modules;
+ let size = this.moduleCount;
+ let {
+ versionInformation,
+ typeNumber: version
+ } = this.options;
+
+ if (version < 7) {
+ return modules;
+ }
+ //预留版本信息 0 为补位,预留版本信息 是从索引7开始
+ const VERSIONS = [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ '000111110010010100',
+ '001000010110111100',
+ '001001101010011001',
+ '001010010011010011',
+ '001011101111110110',
+ '001100011101100010',
+ '001101100001000111',
+ '001110011000001101',
+ '001111100100101000',
+ '010000101101111000',
+ '010001010001011101',
+ '010010101000010111',
+ '010011010100110010',
+ '010100100110100110',
+ '010101011010000011',
+ '010110100011001001',
+ '010111011111101100',
+ '011000111011000100',
+ '011001000111100001',
+ '011010111110101011',
+ '011011000010001110',
+ '011100110000011010',
+ '011101001100111111',
+ '011110110101110101',
+ '011111001001010000',
+ '100000100111010101',
+ '100001011011110000',
+ '100010100010111010',
+ '100011011110011111',
+ '100100101100001011',
+ '100101010000101110',
+ '100110101001100100',
+ '100111010101000001',
+ '101000110001101001'
+ ];
+
+ //两种方式获取预留格式信息,临时计算或者查字典
+ //let version_codes = _v.correctVersionData(_v.version);
+ let version_codes = VERSIONS[version] + VERSIONS[version];
+ //创建预留版本信息
+ let disc = [size - 11, size - 10, size - 9];
+ // 左+右
+ let version_cells = [
+ //左
+ [5, disc[2]],
+ [5, disc[1]],
+ [5, disc[0]],
+ [4, disc[2]],
+ [4, disc[1]],
+ [4, disc[0]],
+ [3, disc[2]],
+ [3, disc[1]],
+ [3, disc[0]],
+ [2, disc[2]],
+ [2, disc[1]],
+ [2, disc[0]],
+ [1, disc[2]],
+ [1, disc[1]],
+ [1, disc[0]],
+ [0, disc[2]],
+ [0, disc[1]],
+ [0, disc[0]],
+ //右
+ [disc[2], 5],
+ [disc[1], 5],
+ [disc[0], 5],
+ [disc[2], 4],
+ [disc[1], 4],
+ [disc[0], 4],
+ [disc[2], 3],
+ [disc[1], 3],
+ [disc[0], 3],
+ [disc[2], 2],
+ [disc[1], 2],
+ [disc[0], 2],
+ [disc[2], 1],
+ [disc[1], 1],
+ [disc[0], 1],
+ [disc[2], 0],
+ [disc[1], 0],
+ [disc[0], 0]
+ ];
+ version_cells.forEach((d, index) => {
+ var versionInformationItem = modules[d[0]][d[1]];
+ versionInformationItem.type.push('versionInformation');
+ versionInformationItem.color = version_codes[index] == '1' ? versionInformation.foregroundColor : versionInformation.backgroundColor;
+ });
+ },
+
+ /**
+ * 绘制二维码方法
+ */
+ draw(options) {
+ options = uQRCode.deepReplace({
+ drawBackground: {
+ before: () => {},
+ after: () => {}
+ },
+ drawBackgroundImage: {
+ before: () => {},
+ after: () => {}
+ },
+ drawForeground: {
+ before: () => {},
+ after: () => {}
+ },
+ drawForegroundImage: {
+ before: () => {},
+ after: () => {}
+ }
+ }, options);
+
+ /* 绘制层级关系,最底层背景 -> 背景图片 -> 前景 -> 最顶层前景图片 */
+ return new Promise((resolve, reject) => {
+ let ctx = this.canvasContext;
+
+ const startup = () => {
+ /* 同时绘制多个二维码时使用队列绘制,防止内部方法冲突导致绘制失败 */
+ return uQRCode.Queue(() => new Promise((queueResolve, queueReject) => {
+ setTimeout(() => {
+ ctx.draw(false); // 第一个draw false可以清空画布
+ queueResolve();
+ }, 150);
+ }));
+ }
+ startup()
+ .then(() => {
+ /* 绘制背景 */
+ return this.drawBackground({
+ before: options.drawBackground.before,
+ after: options.drawBackground.after
+ });
+ })
+ .then(() => {
+ /* 绘制背景图片 */
+ return this.drawBackgroundImage({
+ before: options.drawBackgroundImage.before,
+ after: options.drawBackgroundImage.after
+ });
+ })
+ .then(() => {
+ /* 绘制前景 */
+ return this.drawForeground({
+ before: options.drawForeground.before,
+ after: options.drawForeground.after
+ });
+ })
+ .then(() => {
+ /* 绘制前景图片 */
+ return this.drawForegroundImage({
+ before: options.drawForegroundImage.before,
+ after: options.drawForegroundImage.after
+ });
+ })
+ .then(() => {
+ /* 完成绘制 */
+ resolve();
+ });
+ });
+ },
+
+ drawBackground({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ background
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ ctx.save();
+ /* 填充背景色 */
+ ctx.setFillStyle(background.color);
+ ctx.fillRect(0, 0, size, size);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawBackgroundImage({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ background
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ if (background.image.src) {
+ ctx.save();
+
+ let x = 0;
+ let y = 0;
+
+ let w = background.image.width * size;
+ let h = background.image.height * size;
+ let align = background.image.align;
+ let anchor = background.image.anchor;
+ let alpha = background.image.alpha;
+
+ switch (align[0]) {
+ case 'left':
+ x = 0;
+ break;
+ case 'center':
+ x = size / 2 - w / 2;
+ break;
+ case 'right':
+ x = size - w;
+ break;
+ }
+ x += Number(anchor[0]);
+
+ switch (align[1]) {
+ case 'top':
+ y = 0;
+ break;
+ case 'center':
+ y = size / 2 - h / 2;
+ break;
+ case 'bottom':
+ y = size - h;
+ break;
+ }
+ y += Number(anchor[1]);
+
+ /* 设置透明度 */
+ ctx.globalAlpha = alpha;
+
+ /* 绘制图片 */
+ const img = await this.loadImage(background.image.src);
+ ctx.drawImage(img, x, y, w, h);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+ }
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawForeground({
+ before,
+ after
+ }) {
+ let {
+ background
+ } = this.options;
+ let modules = this.modules;
+ let moduleCount = this.moduleCount;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ ctx.save();
+ for (var rowI = 0; rowI < moduleCount; rowI++) {
+ for (var colI = 0; colI < moduleCount; colI++) {
+ var tile = modules[rowI][colI];
+ if (!tile.isDrawn && tile.color != background.color) { // 颜色不能与背景色一致,否则可能发生颜色重叠
+ var color = tile.color;
+ ctx.setFillStyle(color);
+ ctx.fillRect(tile.x, tile.y, tile.size, tile.size);
+ tile.isDrawn = true;
+ }
+ }
+ }
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+
+ await after(this);
+ resolve();
+ })();
+ });
+ },
+
+ drawForegroundImage({
+ before,
+ after
+ }) {
+ let {
+ dynamicSize: size,
+ foreground
+ } = this.options;
+ let ctx = this.canvasContext;
+
+ return new Promise((resolve, reject) => {
+ (async () => {
+ await before(this);
+
+ if (foreground.image.src) {
+ ctx.save();
+
+ // 绘制前景图
+ let x = 0;
+ let y = 0;
+
+ let w = foreground.image.width * size;
+ let h = foreground.image.height * size;
+ let align = foreground.image.align;
+ let anchor = foreground.image.anchor;
+ let alpha = foreground.image.alpha;
+ let shadow = foreground.image.shadow;
+ let border = foreground.image.border;
+
+ switch (align[0]) {
+ case 'left':
+ x = 0;
+ break;
+ case 'center':
+ x = size / 2 - w / 2;
+ break;
+ case 'right':
+ x = size - w;
+ break;
+ }
+ x += Number(anchor[0]);
+
+ switch (align[1]) {
+ case 'top':
+ y = 0;
+ break;
+ case 'center':
+ y = size / 2 - h / 2;
+ break;
+ case 'bottom':
+ y = size - h;
+ break;
+ }
+ y += Number(anchor[1]);
+
+ /* 绘制图片 */
+ const img = await this.loadImage(foreground.image.src);
+ ctx.drawImage(img, x, y, w, h);
+ ctx.restore();
+ ctx.draw(true); // gcanvas需要每一阶段都draw一下,否则重绘有问题,例如uni-app nvue绘制图片会失败
+ }
+
+ await after(this);
+ resolve();
+ })();
+ });
+ }
+
+ }
+
+})();
+
+export default uQRCode;
diff --git a/uni_modules/Sansnn-uQRCode/package.json b/uni_modules/Sansnn-uQRCode/package.json
new file mode 100644
index 0000000..5966ddd
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/package.json
@@ -0,0 +1,83 @@
+{
+ "id": "Sansnn-uQRCode",
+ "displayName": "uQRCode 二维码生成插件 支持nvue 支持nodejs服务端",
+ "version": "3.2.2",
+ "description": "uQRCode 是一款使用方式简单,高扩展的二维码生成插件。支持全端生成,支持canvas的地方就可以使用uQRCode。",
+ "keywords": [
+ "uQRCode",
+ "二维码",
+ "qrcode",
+ "qr"
+],
+ "repository": "https://github.com/Sansnn/uQRCode",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "JS SDK",
+ "通用 SDK"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/u-qrcode"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/Sansnn-uQRCode/readme.md b/uni_modules/Sansnn-uQRCode/readme.md
new file mode 100644
index 0000000..e5935be
--- /dev/null
+++ b/uni_modules/Sansnn-uQRCode/readme.md
@@ -0,0 +1,274 @@
+# uQRCode
+
+**点击群号加入群聊【uQRCode交流群】:[695070434](https://jq.qq.com/?_wv=1027&k=JRjzDqiw)**
+
+uQRCode 生成方式简单,可扩展性高,适用所有前端应用和Node.js服务端,可运行到所有支持canvas的平台。支持NVUE(NVUE中使用GCanvas)。
+
+支持自定义二维码渲染规则,可通过uQRCode API得到矩阵信息后,自行实现canvas或view+css渲染二维码,如随机颜色、圆点、方块、块与块之间的间距等,详情参考示例项目。
+
+### 插件市场
+[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
+
+### github
+[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode)
+
+### npm
+[https://www.npmjs.com/package/u-qrcode](https://www.npmjs.com/package/u-qrcode)
+
+### 示例预览
+[https://static-c15f4b57-ef97-4d2b-b939-f580f910d7e2.bspapp.com](https://static-c15f4b57-ef97-4d2b-b939-f580f910d7e2.bspapp.com)
+
+### 二维码
+**什么是QR码**
+
+QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。
+
+**QR码的特点**
+
+一是高速读取(QR就是取自“Quick Response”的首字母),通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;
+
+二是高容量、高密度,理论上内容经过压缩处理后可以存7089个数字,4296个字母和数字混合字符,2953个8位字节数据,1817个汉字;
+
+三是支持纠错处理,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:
+- level L : 最大 7% 的错误能够被纠正;
+- level M : 最大 15% 的错误能够被纠正;
+- level Q : 最大 25% 的错误能够被纠正;
+- level H : 最大 30% 的错误能够被纠正;
+
+四是结构化,看似无规则的图形,其实对区域有严格的定义。
+
+更多二维码介绍及原理:[https://blog.csdn.net/jason_ldh/article/details/11801355](https://blog.csdn.net/jason_ldh/article/details/11801355)
+
+### 组件使用
+
+导入`u-qrcode`组件后,在 `template` 中创建 `` 组件
+
+```html
+
+```
+
+### 属性说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|canvasId |String |- |- |是 |组件标识/canvasId |
+|value |String |- |- |是 |二维码内容 |
+|size |Number |- |354 |否 |二维码大小,默认单位px,rpx需要使用uni.upx2px()转换|
+|options |Object |- |- |否 |参数可选项,详见下方options说明 |
+
+### 事件说明
+|事件名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|click |- |void |点击事件 |
+|complete |- |Object |生成完成事件,返回值success: true表示生成成功,false生成失败 |
+
+### 方法说明
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|remake |- |void |重新生成 |
+|toTempFilePath |Object:callback|void |导出临时路径 |
+|save |Object:callback|void |保存 |
+
+#### options说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|typeNumber |Number |- |-1 |否 |二维码版本 |
+|errorCorrectLevel |String/Number|L/M/Q/H/1/0/3/2|H |否 |纠错等级L/M/Q/H分别对应1/0/3/2 |
+|useDynamicSize |Boolean |- |false |否 |是否使用动态尺寸,可以去除二维码小块白色细线 |
+|margin |Number |- |0 |否 |填充边距,默认单位px |
+|background |Object |- |- |否 |背景设置,详见下方options.background说明 |
+|foreground |Object |- |- |否 |前景设置,详见下方options.foreground说明 |
+|positionDetection |Object |- |- |否 |定位角设置,详见下方options.positionDetection说明 |
+|separator |Object |- |- |否 |分割图案设置,详见下方options.separator说明 |
+|alignment |Object |- |- |否 |对齐图案设置,详见下方options.alignment说明 |
+|timing |Object |- |- |否 |时序图案设置,详见下方options.timing说明 |
+|darkBlock |Object |- |- |否 |暗块设置,详见下方options.darkBlock说明 |
+|versionInformation |Object |- |- |否 |版本信息设置,详见下方options.versionInformation说明 |
+
+#### options.background说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |#FFFFFF|否 |背景色,若需要透明背景可设置为rgba(0,0,0,0)|
+|image |Object |- |- |否 |背景图片设置,详见下方options.background.image说明|
+
+#### options.background.image说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|src |String |- |- |否 |背景图片路径 |
+|width |Number |- |1 |否 |指定背景图片宽度,1为二维码size的100% |
+|height |Number |- |1 |否 |指定背景图片高度,1为二维码size的100% |
+|align |Array|['left'/'center'/'right', 'top'/'center'/'bottom'] |['center', 'center'] |否 |指定背景图片对齐方式,[0]为水平方位,[1]为垂直方位 |
+|anchor |Array|- |[0, 0] |否 |指定背景图片锚点,[0]为X轴偏移量,[1]为Y轴偏移量 |
+|alpha |Number |0-1 |1 |否 |指定背景图片透明度 |
+
+#### options.foreground说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |#FFFFFF|否 |前景色 |
+|image |Object |- |- |否 |前景图片设置,详见下方options.foreground.image说明 |
+
+#### options.foreground.image说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|src |String |- |- |否 |前景图片路径 |
+|width |Number |- |1/4 |否 |指定前景图片宽度,1为二维码size的100% |
+|height |Number |- |1/4 |否 |指定前景图片高度,1为二维码size的100% |
+|align |Array|['left'/'center'/'right', 'top'/'center'/'bottom'] |['center', 'center'] |否 |指定前景图片对齐方式,[0]为水平方位,[1]为垂直方位 |
+|anchor |Array|- |[0, 0] |否 |指定前景图片锚点,[0]为X轴偏移量,[1]为Y轴偏移量 |
+
+#### options.positionDetection说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |定位角区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |定位角小块颜色,默认值跟随前景色 |
+
+#### options.separator说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |options.background.color |否 |分割区域颜色,默认值跟随背景色 |
+
+#### options.alignment说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |对齐区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |对齐小块颜色,默认值跟随前景色 |
+
+#### options.timing说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |时序区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |时序小块颜色,默认值跟随前景色 |
+
+#### options.darkBlock说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|color |String |- |options.foreground.color |否 |暗块颜色,默认值跟随前景色 |
+
+#### options.versionInformation说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|backgroundColor|String |- |options.background.color |否 |版本信息区域背景色,默认值跟随背景色 |
+|foregroundColor|String |- |options.foreground.color |否 |版本信息小块颜色,默认值跟随前景色 |
+
+### u-qrcode.js使用
+
+引入u-qrcode.js
+
+``` javascript
+import uQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode';
+```
+
+或者使用npm安装
+
+> npm i u-qrcode
+
+``` javascript
+import uQRCode from 'u-qrcode';
+```
+
+nodejs引入
+
+``` javascript
+import uQRCode from 'u-qrcode/module';
+```
+
+在 `template` 中创建 `` 组件并设置 `id`,画布宽高
+
+```html
+
+```
+
+在 `script` 中调用生成方法
+
+```javascript
+import uQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/u-qrcode';
+
+export default {
+ data() {
+ return {
+ text: 'uQRCode',
+ size: 256
+ }
+ },
+ onReady() {
+ const ctx = uni.createCanvasContext('qrcode');
+ const uqrcode = new uQRCode(
+ {
+ text: this.text,
+ size: this.size
+ },
+ ctx
+ );
+ uqrcode.make();
+ uqrcode.draw();
+ }
+}
+```
+
+### new uQRCode(options, canvasContext, loadImage)说明
+
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|options |Object |- |- |是 |包含组件属性中的options的所有属性,详见下方options说明 |
+|canvasContext|Object |- |- |是 |canvas绘画上下文 |
+|loadImage |Promise|- |- |否 |绘制图片时,某些平台必传,例如微信小程序2d绘图需要创建Image对象,不能直接使用路径,这时就需要传入canvas.createImage给loadImage方法,否则无法绘制图片 |
+
+#### options说明,包含组件属性中的options的所有属性,下方仅列举未包含的属性,其余属性请移步到组件属性options说明查看
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|text |String |- |- |是 |二维码内容 |
+|size |Number |- |354 |否 |二维码大小 |
+
+### uQRCode实例属性
+|属性名 |类型 |说明 |
+|--- |--- |:--- |
+|options |Object |实例化传入的选项值 |
+|canvasContext|Object |画布实例 |
+|makeData |Object |制作二维码全部数据 |
+|modules |Array |制作二维码主要模块数据 |
+|moduleCount |Number |模块数量 |
+
+### uQRCode实例方法
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|make |- |void |制作二维码方法 |
+|draw |options|Promise|绘制二维码方法,绘制层级关系,最底层背景 -> 背景图片 -> 前景 -> 最顶层前景图片,options见下方说明 |
+
+#### draw(options)说明
+|属性名 |类型 |可选值 |默认值 |是否必填 |说明 |
+|--- |--- |--- |--- |--- |:--- |
+|drawBackground |Object: {before, after}|- |- |否 |绘制背景前后可执行自定义方法before,after |
+|drawBackgroundImage|Object: {before, after}|- |- |否 |绘制背景图前后可执行自定义方法before,after|
+|drawForeground |Object: {before, after}|- |- |否 |绘制前景前后可执行自定义方法before,after |
+|drawForegroundImage|Object: {before, after}|- |- |否 |绘制前景图前后可执行自定义方法before,after|
+
+### uQRCode静态属性
+|属性名 |类型 |说明 |
+|--- |--- |:--- |
+|errorCorrectLevel|Object |纠错等级 |
+|defaults |Object |预设默认值 |
+
+### uQRCode静态方法
+|方法名 |参数 |返回值 |说明 |
+|--- |--- |--- |:--- |
+|deepReplace|o, r |替换后的新对象 |对象属性深度替换 |
+
+### 常见问题
+
+**如何扫码跳转指定网页**
+
+二维码内容直接放入完整的网页地址即可,例如:`https://ext.dcloud.net.cn/plugin?id=1287`。微信客户端不能是ip地址。
+
+**nvue打包后生成失败**
+
+Canvas是作为独立的模块,打包时需要选择使用Canvas模块才能正常使用相关的功能。 需要在manifest.json的代码视图中配置如下(暂时还不支持可视化界面操作):
+```javascript
+"app-plus" : {
+ /* 模块配置 */
+ "modules" : {
+ "Canvas" : "nvue canvas" //使用Canvas模块
+ },
+ //...
+},
+//...
+```
+保存好提交云端打包。
diff --git a/uni_modules/hpy-form-select/changelog.md b/uni_modules/hpy-form-select/changelog.md
new file mode 100644
index 0000000..01f2a3e
--- /dev/null
+++ b/uni_modules/hpy-form-select/changelog.md
@@ -0,0 +1,2 @@
+## 0.0.10(2022-04-26)
+- 适配uni-forms校验
diff --git a/uni_modules/hpy-form-select/components/hpy-form-select/hpy-form-select.vue b/uni_modules/hpy-form-select/components/hpy-form-select/hpy-form-select.vue
new file mode 100644
index 0000000..78de734
--- /dev/null
+++ b/uni_modules/hpy-form-select/components/hpy-form-select/hpy-form-select.vue
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+ {{selectText}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/hpy-form-select/package.json b/uni_modules/hpy-form-select/package.json
new file mode 100644
index 0000000..c40ce8a
--- /dev/null
+++ b/uni_modules/hpy-form-select/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "hpy-form-select",
+ "displayName": "picker选择器、下拉框,选择器",
+ "version": "0.0.10",
+ "description": "下拉选择器 基于 picker 简单封装",
+ "keywords": [
+ "picker",
+ "选择器",
+ "下拉选择"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": ""
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-load-more"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/hpy-form-select/readme.md b/uni_modules/hpy-form-select/readme.md
new file mode 100644
index 0000000..30f721e
--- /dev/null
+++ b/uni_modules/hpy-form-select/readme.md
@@ -0,0 +1,169 @@
+
+## hpy-form-select 下拉选择器 基于 [picker](https://uniapp.dcloud.io/component/picker?id=picker) 简单封装
+
+> **组件名:hpy-form-select
+
+从底部弹起的滚动选择器。支持五种选择器,通过mode来区分,分别是普通选择器,多列选择器,时间选择器,日期选择器,省市区选择器,默认是普通选择器
+
+## API
+
+### FilePicker Props
+
+
+
+ 属性名 |
+ 类型 |
+ 默认值 |
+ 说明 |
+
+
+ islot |
+ Boolean | String |
+ false |
+ 是否使用插槽 |
+
+
+ title |
+ String |
+ 请选择 |
+ 默认标题 |
+
+
+ mode |
+ String |
+ 选择模式 |
+ selector | multiSelector |
+
+
+ start |
+ String |
+ |
+ 表示有效日期范围的开始,字符串格式为"YYYY-MM-DD" |
+
+
+ end |
+ String |
+ |
+ 表示有效日期范围的结束,字符串格式为"YYYY-MM-DD" |
+
+
+ fields |
+ String |
+ day |
+ 有效值 year、month、day,表示选择器的粒度,默认为 day,App 端未配置此项时使用系统 UI |
+
+
+ customItem |
+ String |
+ |
+ 可为每一列的顶部添加一个自定义的项 |
+
+
+ dataList |
+ Array |
+ |
+ 选择器数据 |
+
+
+ text |
+ String |
+ |
+ 显示值的key |
+
+
+ name |
+ String |
+ |
+ 保存值的key |
+
+
+ v-model | value |
+ Array | Object |
+ |
+ 绑定的数据 |
+
+
+ disabled |
+ Boolean | String |
+ false |
+ 是否禁用 |
+
+
+ hideBorder |
+ Boolean | String |
+ false |
+ 是否隐藏边框 |
+
+
+ hideArrow |
+ Boolean | String |
+ false |
+ 是否隐藏箭头 |
+
+
+
+
+## 使用示例
+## dataList 为对象数组时,name为实际保存的value值,text为显示的值
+## dataList 为对象数组[{name:'张三', age:'18'}, {name:'李四', age:'19'}]时,需要设置name、text属性,name为实际保存的value值,text为显示的值
+##
+## ======================================================================================================
+## dataList 为普通数组['张三', '李四'] name、text可不设置
+##
+## 类似:
+##
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 可自定义显示
+
+
+
+
+
+
+
+```
+
+```javascript
+export default {
+ data() {
+ return {
+ formData:{
+ hobbySelect:''
+ },
+ hobbyList: [{
+ text: '足球',
+ value: 1
+ }, {
+ text: '篮球',
+ value: 2
+ }, {
+ text: '游泳',
+ value: 3
+ }],
+ }
+ },
+ methods:{
+ change(e){
+ console.log(e.index);
+ console.log(e.value);
+ console.log(e.data);
+ }
+ }
+}
+
+```
\ No newline at end of file
diff --git a/uni_modules/uni-badge/changelog.md b/uni_modules/uni-badge/changelog.md
new file mode 100644
index 0000000..544ecc1
--- /dev/null
+++ b/uni_modules/uni-badge/changelog.md
@@ -0,0 +1,29 @@
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
+## 1.1.7(2021-11-08)
+- 优化 升级ui
+- 修改 size 属性默认值调整为 small
+- 修改 type 属性,默认值调整为 error,info 替换 default
+## 1.1.6(2021-09-22)
+- 修复 在字节小程序上样式不生效的 bug
+## 1.1.5(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.4(2021-07-29)
+- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
+## 1.1.3(2021-06-24)
+- 优化 示例项目
+## 1.1.1(2021-05-12)
+- 新增 组件示例地址
+## 1.1.0(2021-05-12)
+- 新增 uni-badge 的 absolute 属性,支持定位
+- 新增 uni-badge 的 offset 属性,支持定位偏移
+- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
+- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
+- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
+## 1.0.7(2021-05-07)
+- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
+- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
+- 新增 uni-badge 属性 custom-style, 支持自定义样式
+## 1.0.6(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
new file mode 100644
index 0000000..fcbfe93
--- /dev/null
+++ b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
@@ -0,0 +1,268 @@
+
+
+
+ {{displayValue}}
+
+
+
+
+
+
diff --git a/uni_modules/uni-badge/package.json b/uni_modules/uni-badge/package.json
new file mode 100644
index 0000000..4e9e631
--- /dev/null
+++ b/uni_modules/uni-badge/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-badge",
+ "displayName": "uni-badge 数字角标",
+ "version": "1.2.0",
+ "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
+ "keywords": [
+ "",
+ "badge",
+ "uni-ui",
+ "uniui",
+ "数字角标",
+ "徽章"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-badge/readme.md b/uni_modules/uni-badge/readme.md
new file mode 100644
index 0000000..bdf175d
--- /dev/null
+++ b/uni_modules/uni-badge/readme.md
@@ -0,0 +1,10 @@
+## Badge 数字角标
+> **组件名:uni-badge**
+> 代码块: `uBadge`
+
+数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
diff --git a/uni_modules/uni-calendar/changelog.md b/uni_modules/uni-calendar/changelog.md
new file mode 100644
index 0000000..6df4493
--- /dev/null
+++ b/uni_modules/uni-calendar/changelog.md
@@ -0,0 +1,16 @@
+## 1.4.5(2022-02-25)
+- 修复 条件编译 nvue 不支持的 css 样式
+## 1.4.4(2022-02-25)
+- 修复 条件编译 nvue 不支持的 css 样式
+## 1.4.3(2021-09-22)
+- 修复 startDate、 endDate 属性失效的 bug
+## 1.4.2(2021-08-24)
+- 新增 支持国际化
+## 1.4.1(2021-08-05)
+- 修复 弹出层被 tabbar 遮盖 bug
+## 1.4.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.3.16(2021-05-12)
+- 新增 组件示例地址
+## 1.3.15(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-calendar/components/uni-calendar/calendar.js b/uni_modules/uni-calendar/components/uni-calendar/calendar.js
new file mode 100644
index 0000000..b8d7d6f
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/calendar.js
@@ -0,0 +1,546 @@
+/**
+* @1900-2100区间内的公历、农历互转
+* @charset UTF-8
+* @github https://github.com/jjonline/calendar.js
+* @Author Jea杨(JJonline@JJonline.Cn)
+* @Time 2014-7-21
+* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
+* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
+* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
+* @Version 1.0.3
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+*/
+/* eslint-disable */
+var calendar = {
+
+ /**
+ * 农历1900-2100的润大小信息表
+ * @Array Of Property
+ * @return Hex
+ */
+ lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
+ 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
+ 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
+ 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
+ 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
+ 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
+ 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
+ 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
+ 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
+ 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
+ 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
+ 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
+ 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
+ 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
+ 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
+ /** Add By JJonline@JJonline.Cn**/
+ 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
+ 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
+ 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
+ 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
+ 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
+ 0x0d520], // 2100
+
+ /**
+ * 公历每个月份的天数普通表
+ * @Array Of Property
+ * @return Number
+ */
+ solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+ /**
+ * 天干地支之天干速查表
+ * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+ * @return Cn string
+ */
+ Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
+
+ /**
+ * 天干地支之地支速查表
+ * @Array Of Property
+ * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+ * @return Cn string
+ */
+ Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
+
+ /**
+ * 天干地支之地支速查表<=>生肖
+ * @Array Of Property
+ * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+ * @return Cn string
+ */
+ Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
+
+ /**
+ * 24节气速查表
+ * @Array Of Property
+ * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+ * @return Cn string
+ */
+ solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
+
+ /**
+ * 1900-2100各年的24节气日期速查表
+ * @Array Of Property
+ * @return 0x string For splice
+ */
+ sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
+ '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
+ 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
+ '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
+ '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
+ '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
+ '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
+ '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
+ '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
+ '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
+
+ /**
+ * 数字转中文速查表
+ * @Array Of Property
+ * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+ * @return Cn string
+ */
+ nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
+
+ /**
+ * 日期转农历称呼速查表
+ * @Array Of Property
+ * @trans ['初','十','廿','卅']
+ * @return Cn string
+ */
+ nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+
+ /**
+ * 月份转农历称呼速查表
+ * @Array Of Property
+ * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+ * @return Cn string
+ */
+ nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
+
+ /**
+ * 返回农历y年一整年的总天数
+ * @param lunar Year
+ * @return Number
+ * @eg:var count = calendar.lYearDays(1987) ;//count=387
+ */
+ lYearDays: function (y) {
+ var i; var sum = 348
+ for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
+ return (sum + this.leapDays(y))
+ },
+
+ /**
+ * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+ * @param lunar Year
+ * @return Number (0-12)
+ * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+ */
+ leapMonth: function (y) { // 闰字编码 \u95f0
+ return (this.lunarInfo[y - 1900] & 0xf)
+ },
+
+ /**
+ * 返回农历y年闰月的天数 若该年没有闰月则返回0
+ * @param lunar Year
+ * @return Number (0、29、30)
+ * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+ */
+ leapDays: function (y) {
+ if (this.leapMonth(y)) {
+ return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
+ }
+ return (0)
+ },
+
+ /**
+ * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+ * @param lunar Year
+ * @return Number (-1、29、30)
+ * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+ */
+ monthDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
+ return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
+ },
+
+ /**
+ * 返回公历(!)y年m月的天数
+ * @param solar Year
+ * @return Number (-1、28、29、30、31)
+ * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+ */
+ solarDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var ms = m - 1
+ if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
+ return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
+ } else {
+ return (this.solarMonth[ms])
+ }
+ },
+
+ /**
+ * 农历年份转换为干支纪年
+ * @param lYear 农历年的年份数
+ * @return Cn string
+ */
+ toGanZhiYear: function (lYear) {
+ var ganKey = (lYear - 3) % 10
+ var zhiKey = (lYear - 3) % 12
+ if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
+ if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
+ return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
+ },
+
+ /**
+ * 公历月、日判断所属星座
+ * @param cMonth [description]
+ * @param cDay [description]
+ * @return Cn string
+ */
+ toAstro: function (cMonth, cDay) {
+ var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+ var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+ return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
+ },
+
+ /**
+ * 传入offset偏移量返回干支
+ * @param offset 相对甲子的偏移量
+ * @return Cn string
+ */
+ toGanZhi: function (offset) {
+ return this.Gan[offset % 10] + this.Zhi[offset % 12]
+ },
+
+ /**
+ * 传入公历(!)y年获得该年第n个节气的公历日期
+ * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+ * @return day Number
+ * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+ */
+ getTerm: function (y, n) {
+ if (y < 1900 || y > 2100) { return -1 }
+ if (n < 1 || n > 24) { return -1 }
+ var _table = this.sTermInfo[y - 1900]
+ var _info = [
+ parseInt('0x' + _table.substr(0, 5)).toString(),
+ parseInt('0x' + _table.substr(5, 5)).toString(),
+ parseInt('0x' + _table.substr(10, 5)).toString(),
+ parseInt('0x' + _table.substr(15, 5)).toString(),
+ parseInt('0x' + _table.substr(20, 5)).toString(),
+ parseInt('0x' + _table.substr(25, 5)).toString()
+ ]
+ var _calday = [
+ _info[0].substr(0, 1),
+ _info[0].substr(1, 2),
+ _info[0].substr(3, 1),
+ _info[0].substr(4, 2),
+
+ _info[1].substr(0, 1),
+ _info[1].substr(1, 2),
+ _info[1].substr(3, 1),
+ _info[1].substr(4, 2),
+
+ _info[2].substr(0, 1),
+ _info[2].substr(1, 2),
+ _info[2].substr(3, 1),
+ _info[2].substr(4, 2),
+
+ _info[3].substr(0, 1),
+ _info[3].substr(1, 2),
+ _info[3].substr(3, 1),
+ _info[3].substr(4, 2),
+
+ _info[4].substr(0, 1),
+ _info[4].substr(1, 2),
+ _info[4].substr(3, 1),
+ _info[4].substr(4, 2),
+
+ _info[5].substr(0, 1),
+ _info[5].substr(1, 2),
+ _info[5].substr(3, 1),
+ _info[5].substr(4, 2)
+ ]
+ return parseInt(_calday[n - 1])
+ },
+
+ /**
+ * 传入农历数字月份返回汉语通俗表示法
+ * @param lunar month
+ * @return Cn string
+ * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+ */
+ toChinaMonth: function (m) { // 月 => \u6708
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var s = this.nStr3[m - 1]
+ s += '\u6708'// 加上月字
+ return s
+ },
+
+ /**
+ * 传入农历日期数字返回汉字表示法
+ * @param lunar day
+ * @return Cn string
+ * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+ */
+ toChinaDay: function (d) { // 日 => \u65e5
+ var s
+ switch (d) {
+ case 10:
+ s = '\u521d\u5341'; break
+ case 20:
+ s = '\u4e8c\u5341'; break
+ break
+ case 30:
+ s = '\u4e09\u5341'; break
+ break
+ default :
+ s = this.nStr2[Math.floor(d / 10)]
+ s += this.nStr1[d % 10]
+ }
+ return (s)
+ },
+
+ /**
+ * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+ * @param y year
+ * @return Cn string
+ * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+ */
+ getAnimal: function (y) {
+ return this.Animals[(y - 4) % 12]
+ },
+
+ /**
+ * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+ * @param y solar year
+ * @param m solar month
+ * @param d solar day
+ * @return JSON object
+ * @eg:console.log(calendar.solar2lunar(1987,11,01));
+ */
+ solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
+ // 年份限定、上限
+ if (y < 1900 || y > 2100) {
+ return -1// undefined转换为数字变为NaN
+ }
+ // 公历传参最下限
+ if (y == 1900 && m == 1 && d < 31) {
+ return -1
+ }
+ // 未传参 获得当天
+ if (!y) {
+ var objDate = new Date()
+ } else {
+ var objDate = new Date(y, parseInt(m) - 1, d)
+ }
+ var i; var leap = 0; var temp = 0
+ // 修正ymd参数
+ var y = objDate.getFullYear()
+ var m = objDate.getMonth() + 1
+ var d = objDate.getDate()
+ var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
+ for (i = 1900; i < 2101 && offset > 0; i++) {
+ temp = this.lYearDays(i)
+ offset -= temp
+ }
+ if (offset < 0) {
+ offset += temp; i--
+ }
+
+ // 是否今天
+ var isTodayObj = new Date()
+ var isToday = false
+ if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
+ isToday = true
+ }
+ // 星期几
+ var nWeek = objDate.getDay()
+ var cWeek = this.nStr1[nWeek]
+ // 数字表示周几顺应天朝周一开始的惯例
+ if (nWeek == 0) {
+ nWeek = 7
+ }
+ // 农历年
+ var year = i
+ var leap = this.leapMonth(i) // 闰哪个月
+ var isLeap = false
+
+ // 效验闰月
+ for (i = 1; i < 13 && offset > 0; i++) {
+ // 闰月
+ if (leap > 0 && i == (leap + 1) && isLeap == false) {
+ --i
+ isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
+ } else {
+ temp = this.monthDays(year, i)// 计算农历普通月天数
+ }
+ // 解除闰月
+ if (isLeap == true && i == (leap + 1)) { isLeap = false }
+ offset -= temp
+ }
+ // 闰月导致数组下标重叠取反
+ if (offset == 0 && leap > 0 && i == leap + 1) {
+ if (isLeap) {
+ isLeap = false
+ } else {
+ isLeap = true; --i
+ }
+ }
+ if (offset < 0) {
+ offset += temp; --i
+ }
+ // 农历月
+ var month = i
+ // 农历日
+ var day = offset + 1
+ // 天干地支处理
+ var sm = m - 1
+ var gzY = this.toGanZhiYear(year)
+
+ // 当月的两个节气
+ // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+ var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
+ var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
+
+ // 依据12节气修正干支月
+ var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
+ if (d >= firstNode) {
+ gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
+ }
+
+ // 传入的日期的节气与否
+ var isTerm = false
+ var Term = null
+ if (firstNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 2]
+ }
+ if (secondNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 1]
+ }
+ // 日柱 当月一日与 1900/1/1 相差天数
+ var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+ var gzD = this.toGanZhi(dayCyclical + d - 1)
+ // 该日期所属的星座
+ var astro = this.toAstro(m, d)
+
+ return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
+ },
+
+ /**
+ * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+ * @param y lunar year
+ * @param m lunar month
+ * @param d lunar day
+ * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+ * @return JSON object
+ * @eg:console.log(calendar.lunar2solar(1987,9,10));
+ */
+ lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
+ var isLeapMonth = !!isLeapMonth
+ var leapOffset = 0
+ var leapMonth = this.leapMonth(y)
+ var leapDay = this.leapDays(y)
+ if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+ if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
+ var day = this.monthDays(y, m)
+ var _day = day
+ // bugFix 2016-9-25
+ // if month is leap, _day use leapDays method
+ if (isLeapMonth) {
+ _day = this.leapDays(y, m)
+ }
+ if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
+
+ // 计算农历的时间差
+ var offset = 0
+ for (var i = 1900; i < y; i++) {
+ offset += this.lYearDays(i)
+ }
+ var leap = 0; var isAdd = false
+ for (var i = 1; i < m; i++) {
+ leap = this.leapMonth(y)
+ if (!isAdd) { // 处理闰月
+ if (leap <= i && leap > 0) {
+ offset += this.leapDays(y); isAdd = true
+ }
+ }
+ offset += this.monthDays(y, i)
+ }
+ // 转换闰月农历 需补充该年闰月的前一个月的时差
+ if (isLeapMonth) { offset += day }
+ // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+ var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+ var calObj = new Date((offset + d - 31) * 86400000 + stmap)
+ var cY = calObj.getUTCFullYear()
+ var cM = calObj.getUTCMonth() + 1
+ var cD = calObj.getUTCDate()
+
+ return this.solar2lunar(cY, cM, cD)
+ }
+}
+
+export default calendar
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
new file mode 100644
index 0000000..fcbd13c
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "ok",
+ "uni-calender.cancel": "cancel",
+ "uni-calender.today": "today",
+ "uni-calender.MON": "MON",
+ "uni-calender.TUE": "TUE",
+ "uni-calender.WED": "WED",
+ "uni-calender.THU": "THU",
+ "uni-calender.FRI": "FRI",
+ "uni-calender.SAT": "SAT",
+ "uni-calender.SUN": "SUN"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js b/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
new file mode 100644
index 0000000..de7509c
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
@@ -0,0 +1,8 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+ en,
+ 'zh-Hans': zhHans,
+ 'zh-Hant': zhHant
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
new file mode 100644
index 0000000..1ca43de
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "确定",
+ "uni-calender.cancel": "取消",
+ "uni-calender.today": "今日",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
new file mode 100644
index 0000000..e0fe33b
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "確定",
+ "uni-calender.cancel": "取消",
+ "uni-calender.today": "今日",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
new file mode 100644
index 0000000..0353011
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
@@ -0,0 +1,181 @@
+
+
+
+
+ {{weeks.date}}
+ {{todayText}}
+ {{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}
+ {{weeks.extraInfo.info}}
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
new file mode 100644
index 0000000..a2c33d0
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
@@ -0,0 +1,554 @@
+
+
+
+
+
+
+
+
+ {{nowDate.month}}
+
+
+
+ {{SUNText}}
+
+
+ {{monText}}
+
+
+ {{TUEText}}
+
+
+ {{WEDText}}
+
+
+ {{THUText}}
+
+
+ {{FRIText}}
+
+
+ {{SATText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-calendar/components/uni-calendar/util.js b/uni_modules/uni-calendar/components/uni-calendar/util.js
new file mode 100644
index 0000000..bae9273
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/util.js
@@ -0,0 +1,354 @@
+import CALENDAR from './calendar.js'
+
+class Calendar {
+ constructor({
+ date,
+ selected,
+ startDate,
+ endDate,
+ range
+ } = {}) {
+ // 当前日期
+ this.date = this.getDate(new Date()) // 当前初入日期
+ // 打点信息
+ this.selected = selected || [];
+ // 范围开始
+ this.startDate = startDate
+ // 范围结束
+ this.endDate = endDate
+ this.range = range
+ // 多选状态
+ this.cleanMultipleStatus()
+ // 每周日期
+ this.weeks = {}
+ // this._getWeek(this.date.fullDate)
+ }
+ /**
+ * 设置日期
+ * @param {Object} date
+ */
+ setDate(date) {
+ this.selectDate = this.getDate(date)
+ this._getWeek(this.selectDate.fullDate)
+ }
+
+ /**
+ * 清理多选状态
+ */
+ cleanMultipleStatus() {
+ this.multipleStatus = {
+ before: '',
+ after: '',
+ data: []
+ }
+ }
+
+ /**
+ * 重置开始日期
+ */
+ resetSatrtDate(startDate) {
+ // 范围开始
+ this.startDate = startDate
+
+ }
+
+ /**
+ * 重置结束日期
+ */
+ resetEndDate(endDate) {
+ // 范围结束
+ this.endDate = endDate
+ }
+
+ /**
+ * 获取任意时间
+ */
+ getDate(date, AddDayCount = 0, str = 'day') {
+ if (!date) {
+ date = new Date()
+ }
+ if (typeof date !== 'object') {
+ date = date.replace(/-/g, '/')
+ }
+ const dd = new Date(date)
+ switch (str) {
+ case 'day':
+ dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ case 'month':
+ if (dd.getDate() === 31) {
+ dd.setDate(dd.getDate() + AddDayCount)
+ } else {
+ dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+ }
+ break
+ case 'year':
+ dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ }
+ const y = dd.getFullYear()
+ const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+ const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+ return {
+ fullDate: y + '-' + m + '-' + d,
+ year: y,
+ month: m,
+ date: d,
+ day: dd.getDay()
+ }
+ }
+
+
+ /**
+ * 获取上月剩余天数
+ */
+ _getLastMonthDays(firstDay, full) {
+ let dateArr = []
+ for (let i = firstDay; i > 0; i--) {
+ const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+ dateArr.push({
+ date: beforeDate,
+ month: full.month - 1,
+ lunar: this.getlunar(full.year, full.month - 1, beforeDate),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+ /**
+ * 获取本月天数
+ */
+ _currentMonthDys(dateData, full) {
+ let dateArr = []
+ let fullDate = this.date.fullDate
+ for (let i = 1; i <= dateData; i++) {
+ let isinfo = false
+ let nowDate = full.year + '-' + (full.month < 10 ?
+ full.month : full.month) + '-' + (i < 10 ?
+ '0' + i : i)
+ // 是否今天
+ let isDay = fullDate === nowDate
+ // 获取打点信息
+ let info = this.selected && this.selected.find((item) => {
+ if (this.dateEqual(nowDate, item.date)) {
+ return item
+ }
+ })
+
+ // 日期禁用
+ let disableBefore = true
+ let disableAfter = true
+ if (this.startDate) {
+ // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+ // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+ disableBefore = this.dateCompare(this.startDate, nowDate)
+ }
+
+ if (this.endDate) {
+ // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+ // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+ disableAfter = this.dateCompare(nowDate, this.endDate)
+ }
+ let multiples = this.multipleStatus.data
+ let checked = false
+ let multiplesStatus = -1
+ if (this.range) {
+ if (multiples) {
+ multiplesStatus = multiples.findIndex((item) => {
+ return this.dateEqual(item, nowDate)
+ })
+ }
+ if (multiplesStatus !== -1) {
+ checked = true
+ }
+ }
+ let data = {
+ fullDate: nowDate,
+ year: full.year,
+ date: i,
+ multiple: this.range ? checked : false,
+ beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
+ afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
+ month: full.month,
+ lunar: this.getlunar(full.year, full.month, i),
+ disable: !(disableBefore && disableAfter),
+ isDay
+ }
+ if (info) {
+ data.extraInfo = info
+ }
+
+ dateArr.push(data)
+ }
+ return dateArr
+ }
+ /**
+ * 获取下月天数
+ */
+ _getNextMonthDays(surplus, full) {
+ let dateArr = []
+ for (let i = 1; i < surplus + 1; i++) {
+ dateArr.push({
+ date: i,
+ month: Number(full.month) + 1,
+ lunar: this.getlunar(full.year, Number(full.month) + 1, i),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+
+ /**
+ * 获取当前日期详情
+ * @param {Object} date
+ */
+ getInfo(date) {
+ if (!date) {
+ date = new Date()
+ }
+ const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+ return dateInfo
+ }
+
+ /**
+ * 比较时间大小
+ */
+ dateCompare(startDate, endDate) {
+ // 计算截止时间
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+ if (startDate <= endDate) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ /**
+ * 比较时间是否相等
+ */
+ dateEqual(before, after) {
+ // 计算截止时间
+ before = new Date(before.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ after = new Date(after.replace('-', '/').replace('-', '/'))
+ if (before.getTime() - after.getTime() === 0) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+
+ /**
+ * 获取日期范围内所有日期
+ * @param {Object} begin
+ * @param {Object} end
+ */
+ geDateAll(begin, end) {
+ var arr = []
+ var ab = begin.split('-')
+ var ae = end.split('-')
+ var db = new Date()
+ db.setFullYear(ab[0], ab[1] - 1, ab[2])
+ var de = new Date()
+ de.setFullYear(ae[0], ae[1] - 1, ae[2])
+ var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+ var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+ for (var k = unixDb; k <= unixDe;) {
+ k = k + 24 * 60 * 60 * 1000
+ arr.push(this.getDate(new Date(parseInt(k))).fullDate)
+ }
+ return arr
+ }
+ /**
+ * 计算阴历日期显示
+ */
+ getlunar(year, month, date) {
+ return CALENDAR.solar2lunar(year, month, date)
+ }
+ /**
+ * 设置打点
+ */
+ setSelectInfo(data, value) {
+ this.selected = value
+ this._getWeek(data)
+ }
+
+ /**
+ * 获取多选状态
+ */
+ setMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+
+ if (!this.range) return
+ if (before && after) {
+ this.multipleStatus.before = ''
+ this.multipleStatus.after = ''
+ this.multipleStatus.data = []
+ } else {
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+ }
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 获取每周数据
+ * @param {Object} dateData
+ */
+ _getWeek(dateData) {
+ const {
+ fullDate,
+ year,
+ month,
+ date,
+ day
+ } = this.getDate(dateData)
+ let firstDay = new Date(year, month - 1, 1).getDay()
+ let currentDay = new Date(year, month, 0).getDate()
+ let dates = {
+ lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+ currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+ nextMonthDays: [], // 下个月开始几天
+ weeks: []
+ }
+ let canlender = []
+ const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+ dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+ canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+ let weeks = {}
+ // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
+ for (let i = 0; i < canlender.length; i++) {
+ if (i % 7 === 0) {
+ weeks[parseInt(i / 7)] = new Array(7)
+ }
+ weeks[parseInt(i / 7)][i % 7] = canlender[i]
+ }
+ this.canlender = canlender
+ this.weeks = weeks
+ }
+
+ //静态方法
+ // static init(date) {
+ // if (!this.instance) {
+ // this.instance = new Calendar(date);
+ // }
+ // return this.instance;
+ // }
+}
+
+
+export default Calendar
diff --git a/uni_modules/uni-calendar/package.json b/uni_modules/uni-calendar/package.json
new file mode 100644
index 0000000..40455c8
--- /dev/null
+++ b/uni_modules/uni-calendar/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-calendar",
+ "displayName": "uni-calendar 日历",
+ "version": "1.4.5",
+ "description": "日历组件",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "日历",
+ "",
+ "打卡",
+ "日历选择"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-calendar/readme.md b/uni_modules/uni-calendar/readme.md
new file mode 100644
index 0000000..4f3ca0e
--- /dev/null
+++ b/uni_modules/uni-calendar/readme.md
@@ -0,0 +1,103 @@
+
+
+## Calendar 日历
+> **组件名:uni-calendar**
+> 代码块: `uCalendar`
+
+
+日历组件
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
+> - 仅支持自定义组件模式
+> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
+> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
+> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+```
+
+### 通过方法打开日历
+
+需要设置 `insert` 为 `false`
+
+```html
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {};
+ },
+ methods: {
+ open(){
+ this.$refs.calendar.open();
+ },
+ confirm(e) {
+ console.log(e);
+ }
+ }
+};
+
+```
+
+
+## API
+
+### Calendar Props
+
+| 属性名 | 类型 | 默认值| 说明 |
+| | |
+| date | String |- | 自定义当前时间,默认为今天 |
+| lunar | Boolean | false | 显示农历 |
+| startDate | String |- | 日期选择范围-开始日期 |
+| endDate | String |- | 日期选择范围-结束日期 |
+| range | Boolean | false | 范围选择 |
+| insert | Boolean | false | 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式 |
+|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 |
+| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
+|showMonth | Boolean | true | 是否显示月份为背景 |
+
+### Calendar Events
+
+| 事件名 | 说明 |返回值|
+| | | |
+| open | 弹出日历组件,`insert :false` 时生效|- |
+
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)
\ No newline at end of file
diff --git a/uni_modules/uni-card/changelog.md b/uni_modules/uni-card/changelog.md
new file mode 100644
index 0000000..c3cd8c4
--- /dev/null
+++ b/uni_modules/uni-card/changelog.md
@@ -0,0 +1,26 @@
+## 1.3.1(2021-12-20)
+- 修复 在vue页面下略缩图显示不正常的bug
+## 1.3.0(2021-11-19)
+- 重构插槽的用法 ,header 替换为 title
+- 新增 actions 插槽
+- 新增 cover 封面图属性和插槽
+- 新增 padding 内容默认内边距离
+- 新增 margin 卡片默认外边距离
+- 新增 spacing 卡片默认内边距
+- 新增 shadow 卡片阴影属性
+- 取消 mode 属性,可使用组合插槽代替
+- 取消 note 属性 ,使用actions插槽代替
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
+## 1.2.1(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.8(2021-07-01)
+- 优化 图文卡片无图片加载时,提供占位图标
+- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
+- 修复 thumbnail 不存在仍然占位的 bug
+## 1.1.7(2021-05-12)
+- 新增 组件示例地址
+## 1.1.6(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-card/components/uni-card/uni-card.vue b/uni_modules/uni-card/components/uni-card/uni-card.vue
new file mode 100644
index 0000000..38cf594
--- /dev/null
+++ b/uni_modules/uni-card/components/uni-card/uni-card.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-card/package.json b/uni_modules/uni-card/package.json
new file mode 100644
index 0000000..f16224d
--- /dev/null
+++ b/uni_modules/uni-card/package.json
@@ -0,0 +1,90 @@
+{
+ "id": "uni-card",
+ "displayName": "uni-card 卡片",
+ "version": "1.3.1",
+ "description": "Card 组件,提供常见的卡片样式。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "card",
+ "",
+ "卡片"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-icons",
+ "uni-scss"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-card/readme.md b/uni_modules/uni-card/readme.md
new file mode 100644
index 0000000..7434e71
--- /dev/null
+++ b/uni_modules/uni-card/readme.md
@@ -0,0 +1,12 @@
+
+
+## Card 卡片
+> **组件名:uni-card**
+> 代码块: `uCard`
+
+卡片视图组件。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
diff --git a/uni_modules/uni-collapse/changelog.md b/uni_modules/uni-collapse/changelog.md
new file mode 100644
index 0000000..292e4c7
--- /dev/null
+++ b/uni_modules/uni-collapse/changelog.md
@@ -0,0 +1,36 @@
+## 1.4.3(2022-01-25)
+- 修复 初始化的时候 ,open 属性失效的bug
+## 1.4.2(2022-01-21)
+- 修复 微信小程序resize后组件收起的bug
+## 1.4.1(2021-11-22)
+- 修复 vue3中个别scss变量无法找到的问题
+## 1.4.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse)
+## 1.3.3(2021-08-17)
+- 优化 show-arrow 属性默认为true
+## 1.3.2(2021-08-17)
+- 新增 show-arrow 属性,控制是否显示右侧箭头
+## 1.3.1(2021-07-30)
+- 优化 vue3下小程序事件警告的问题
+## 1.3.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.2.2(2021-07-21)
+- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
+## 1.2.1(2021-07-21)
+- 优化 组件示例
+## 1.2.0(2021-07-21)
+- 新增 组件折叠动画
+- 新增 value\v-model 属性 ,动态修改面板折叠状态
+- 新增 title 插槽 ,可定义面板标题
+- 新增 border 属性 ,显示隐藏面板内容分隔线
+- 新增 title-border 属性 ,显示隐藏面板标题分隔线
+- 修复 resize 方法失效的Bug
+- 修复 change 事件返回参数不正确的Bug
+- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
+## 1.1.7(2021-05-12)
+- 新增 组件示例地址
+## 1.1.6(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.1.5(2021-02-05)
+- 调整为uni_modules目录规范
\ No newline at end of file
diff --git a/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
new file mode 100644
index 0000000..d62a6a7
--- /dev/null
+++ b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
@@ -0,0 +1,402 @@
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
new file mode 100644
index 0000000..384c39a
--- /dev/null
+++ b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-collapse/package.json b/uni_modules/uni-collapse/package.json
new file mode 100644
index 0000000..65349cf
--- /dev/null
+++ b/uni_modules/uni-collapse/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-collapse",
+ "displayName": "uni-collapse 折叠面板",
+ "version": "1.4.3",
+ "description": "Collapse 组件,可以折叠 / 展开的内容区域。",
+ "keywords": [
+ "uni-ui",
+ "折叠",
+ "折叠面板",
+ "手风琴"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-collapse/readme.md b/uni_modules/uni-collapse/readme.md
new file mode 100644
index 0000000..bc758eb
--- /dev/null
+++ b/uni_modules/uni-collapse/readme.md
@@ -0,0 +1,12 @@
+
+
+## Collapse 折叠面板
+> **组件名:uni-collapse**
+> 代码块: `uCollapse`
+> 关联组件:`uni-collapse-item`、`uni-icons`。
+
+
+折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-combox/changelog.md b/uni_modules/uni-combox/changelog.md
new file mode 100644
index 0000000..23c2748
--- /dev/null
+++ b/uni_modules/uni-combox/changelog.md
@@ -0,0 +1,15 @@
+## 1.0.1(2021-11-23)
+- 优化 label、label-width 属性
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
+## 0.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.0.6(2021-05-12)
+- 新增 组件示例地址
+## 0.0.5(2021-04-21)
+- 优化 添加依赖 uni-icons, 导入后自动下载依赖
+## 0.0.4(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 0.0.3(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-combox/components/uni-combox/uni-combox.vue b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue
new file mode 100644
index 0000000..500b6f8
--- /dev/null
+++ b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue
@@ -0,0 +1,275 @@
+
+
+
+ {{label}}
+
+
+
+
+
+
+
+
+
+
+ {{emptyTips}}
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-combox/package.json b/uni_modules/uni-combox/package.json
new file mode 100644
index 0000000..4a05c3f
--- /dev/null
+++ b/uni_modules/uni-combox/package.json
@@ -0,0 +1,90 @@
+{
+ "id": "uni-combox",
+ "displayName": "uni-combox 组合框",
+ "version": "1.0.1",
+ "description": "可以选择也可以输入的表单项 ",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "combox",
+ "组合框",
+ "select"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "n"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-combox/readme.md b/uni_modules/uni-combox/readme.md
new file mode 100644
index 0000000..ffa2cc8
--- /dev/null
+++ b/uni_modules/uni-combox/readme.md
@@ -0,0 +1,11 @@
+
+
+## Combox 组合框
+> **组件名:uni-combox**
+> 代码块: `uCombox`
+
+
+组合框组件。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-countdown/changelog.md b/uni_modules/uni-countdown/changelog.md
new file mode 100644
index 0000000..f25beef
--- /dev/null
+++ b/uni_modules/uni-countdown/changelog.md
@@ -0,0 +1,24 @@
+## 1.2.2(2022-01-19)
+- 修复 在微信小程序中样式不生效的bug
+## 1.2.1(2022-01-18)
+- 新增 update 方法 ,在动态更新时间后,刷新组件
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-countdown](https://uniapp.dcloud.io/component/uniui/uni-countdown)
+## 1.1.3(2021-10-18)
+- 重构
+- 新增 font-size 支持自定义字体大小
+## 1.1.2(2021-08-24)
+- 新增 支持国际化
+## 1.1.1(2021-07-30)
+- 优化 vue3下小程序事件警告的问题
+## 1.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.5(2021-06-18)
+- 修复 uni-countdown 重复赋值跳两秒的 bug
+## 1.0.4(2021-05-12)
+- 新增 组件示例地址
+## 1.0.3(2021-05-08)
+- 修复 uni-countdown 不能控制倒计时的 bug
+## 1.0.2(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json b/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json
new file mode 100644
index 0000000..06309cb
--- /dev/null
+++ b/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json
@@ -0,0 +1,6 @@
+{
+ "uni-countdown.day": "day",
+ "uni-countdown.h": "h",
+ "uni-countdown.m": "m",
+ "uni-countdown.s": "s"
+}
diff --git a/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js b/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js
new file mode 100644
index 0000000..de7509c
--- /dev/null
+++ b/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js
@@ -0,0 +1,8 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+ en,
+ 'zh-Hans': zhHans,
+ 'zh-Hant': zhHant
+}
diff --git a/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json b/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json
new file mode 100644
index 0000000..358cdd1
--- /dev/null
+++ b/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "uni-countdown.day": "天",
+ "uni-countdown.h": "时",
+ "uni-countdown.m": "分",
+ "uni-countdown.s": "秒"
+}
diff --git a/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json b/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json
new file mode 100644
index 0000000..e5a63de
--- /dev/null
+++ b/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json
@@ -0,0 +1,6 @@
+{
+ "uni-countdown.day": "天",
+ "uni-countdown.h": "時",
+ "uni-countdown.m": "分",
+ "uni-countdown.s": "秒"
+}
diff --git a/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue b/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
new file mode 100644
index 0000000..1f8ef4e
--- /dev/null
+++ b/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
@@ -0,0 +1,271 @@
+
+
+ {{ d }}
+ {{dayText}}
+ {{ h }}
+ {{ showColon ? ':' : hourText }}
+ {{ i }}
+ {{ showColon ? ':' : minuteText }}
+ {{ s }}
+ {{secondText}}
+
+
+
+
diff --git a/uni_modules/uni-countdown/package.json b/uni_modules/uni-countdown/package.json
new file mode 100644
index 0000000..70e99ee
--- /dev/null
+++ b/uni_modules/uni-countdown/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-countdown",
+ "displayName": "uni-countdown 倒计时",
+ "version": "1.2.2",
+ "description": "CountDown 倒计时组件",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "countdown",
+ "倒计时"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-countdown/readme.md b/uni_modules/uni-countdown/readme.md
new file mode 100644
index 0000000..4bcb1aa
--- /dev/null
+++ b/uni_modules/uni-countdown/readme.md
@@ -0,0 +1,10 @@
+
+
+## CountDown 倒计时
+> **组件名:uni-countdown**
+> 代码块: `uCountDown`
+
+倒计时组件。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-countdown)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-data-checkbox/changelog.md b/uni_modules/uni-data-checkbox/changelog.md
new file mode 100644
index 0000000..d8f420b
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/changelog.md
@@ -0,0 +1,41 @@
+## 1.0.1(2022-02-07)
+- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
+## 0.2.5(2021-08-23)
+- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
+## 0.2.4(2021-08-17)
+- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
+## 0.2.3(2021-08-11)
+- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
+## 0.2.2(2021-07-30)
+- 优化 在uni-forms组件,与label不对齐的问题
+## 0.2.1(2021-07-27)
+- 修复 单选默认值为0不能选中的Bug
+## 0.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.1.11(2021-07-06)
+- 优化 删除无用日志
+## 0.1.10(2021-07-05)
+- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
+## 0.1.9(2021-07-05)
+- 修复 nvue 黑框样式问题
+## 0.1.8(2021-06-28)
+- 修复 selectedTextColor 属性不生效的Bug
+## 0.1.7(2021-06-02)
+- 新增 map 属性,可以方便映射text/value属性
+## 0.1.6(2021-05-26)
+- 修复 不关联服务空间的情况下组件报错的Bug
+## 0.1.5(2021-05-12)
+- 新增 组件示例地址
+## 0.1.4(2021-04-09)
+- 修复 nvue 下无法选中的问题
+## 0.1.3(2021-03-22)
+- 新增 disabled属性
+## 0.1.2(2021-02-24)
+- 优化 默认颜色显示
+## 0.1.1(2021-02-24)
+- 新增 支持nvue
+## 0.1.0(2021-02-18)
+- “暂无数据”显示居中
diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
new file mode 100644
index 0000000..ccea7e9
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
@@ -0,0 +1,817 @@
+
+
+
+
+
+ {{mixinDatacomErrorMessage}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-checkbox/package.json b/uni_modules/uni-data-checkbox/package.json
new file mode 100644
index 0000000..64131e7
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "uni-data-checkbox",
+ "displayName": "uni-data-checkbox 数据选择器",
+ "version": "1.0.1",
+ "description": "通过数据驱动的单选框和复选框",
+ "keywords": [
+ "uni-ui",
+ "checkbox",
+ "单选",
+ "多选",
+ "单选多选"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": "^3.1.1"
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-load-more","uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-data-checkbox/readme.md b/uni_modules/uni-data-checkbox/readme.md
new file mode 100644
index 0000000..6eb253d
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/readme.md
@@ -0,0 +1,18 @@
+
+
+## DataCheckbox 数据驱动的单选复选框
+> **组件名:uni-data-checkbox**
+> 代码块: `uDataCheckbox`
+
+
+本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
+
+1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
+2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
+3. 本组件合并了单选多选
+4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
+
+在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-data-picker/changelog.md b/uni_modules/uni-data-picker/changelog.md
new file mode 100644
index 0000000..486eedc
--- /dev/null
+++ b/uni_modules/uni-data-picker/changelog.md
@@ -0,0 +1,56 @@
+## 1.0.3(2022-02-25)
+- 修复 nvue 不支持的 v-show 的 bug
+## 1.0.2(2022-02-25)
+- 修复 条件编译 nvue 不支持的 css 样式
+## 1.0.1(2021-11-23)
+- 修复 由上个版本引发的map、v-model等属性不生效的bug
+## 1.0.0(2021-11-19)
+- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
+## 0.4.9(2021-10-28)
+- 修复 VUE2 v-model 概率无效的 bug
+## 0.4.8(2021-10-27)
+- 修复 v-model 概率无效的 bug
+## 0.4.7(2021-10-25)
+- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
+- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
+## 0.4.6(2021-10-19)
+- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
+## 0.4.5(2021-09-26)
+- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
+- 修复 readonly 为 true 时报错的 bug
+## 0.4.4(2021-09-26)
+- 修复 上一版本造成的 map 属性失效的 bug
+- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
+## 0.4.3(2021-09-24)
+- 修复 某些情况下级联未触发的 bug
+## 0.4.2(2021-09-23)
+- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
+- 新增 选项内容过长自动添加省略号
+## 0.4.1(2021-09-15)
+- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
+## 0.4.0(2021-07-13)
+- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.3.5(2021-06-04)
+- 修复 无法加载云端数据的问题
+## 0.3.4(2021-05-28)
+- 修复 v-model 无效问题
+- 修复 loaddata 为空数据组时加载时间过长问题
+- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
+## 0.3.3(2021-05-12)
+- 新增 组件示例地址
+## 0.3.2(2021-04-22)
+- 修复 非树形数据有 where 属性查询报错的问题
+## 0.3.1(2021-04-15)
+- 修复 本地数据概率无法回显时问题
+## 0.3.0(2021-04-07)
+- 新增 支持云端非树形表结构数据
+- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
+## 0.2.0(2021-03-15)
+- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
+## 0.1.9(2021-03-09)
+- 修复 微信小程序某些情况下无法选择的问题
+## 0.1.8(2021-02-05)
+- 优化 部分样式在 nvue 上的兼容表现
+## 0.1.7(2021-02-05)
+- 调整为 uni_modules 目录规范
diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
new file mode 100644
index 0000000..6ef26a2
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false
+ }
+ },
+ mounted () {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del']
+ }
+ const listener = ($event) => {
+ if (this.disable) {
+ return
+ }
+ const keyName = Object.keys(keyNames).find(key => {
+ const keyName = $event.key
+ const value = keyNames[key]
+ return value === keyName || (Array.isArray(value) && value.includes(keyName))
+ })
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {})
+ }, 0)
+ }
+ }
+ document.addEventListener('keyup', listener)
+ this.$once('hook:beforeDestroy', () => {
+ document.removeEventListener('keyup', listener)
+ })
+ },
+ render: () => {}
+}
+// #endif
diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
new file mode 100644
index 0000000..a76af2e
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
@@ -0,0 +1,539 @@
+
+
+
+
+
+ {{errorMessage}}
+
+
+
+
+
+
+ {{item.text}}{{split}}
+
+
+
+ {{placeholder}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{popupTitle}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
new file mode 100644
index 0000000..c12fd54
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
@@ -0,0 +1,563 @@
+export default {
+ props: {
+ localdata: {
+ type: [Array, Object],
+ default () {
+ return []
+ }
+ },
+ spaceInfo: {
+ type: Object,
+ default () {
+ return {}
+ }
+ },
+ collection: {
+ type: String,
+ default: ''
+ },
+ action: {
+ type: String,
+ default: ''
+ },
+ field: {
+ type: String,
+ default: ''
+ },
+ orderby: {
+ type: String,
+ default: ''
+ },
+ where: {
+ type: [String, Object],
+ default: ''
+ },
+ pageData: {
+ type: String,
+ default: 'add'
+ },
+ pageCurrent: {
+ type: Number,
+ default: 1
+ },
+ pageSize: {
+ type: Number,
+ default: 20
+ },
+ getcount: {
+ type: [Boolean, String],
+ default: false
+ },
+ getone: {
+ type: [Boolean, String],
+ default: false
+ },
+ gettree: {
+ type: [Boolean, String],
+ default: false
+ },
+ manual: {
+ type: Boolean,
+ default: false
+ },
+ value: {
+ type: [Array, String, Number],
+ default () {
+ return []
+ }
+ },
+ modelValue: {
+ type: [Array, String, Number],
+ default () {
+ return []
+ }
+ },
+ preload: {
+ type: Boolean,
+ default: false
+ },
+ stepSearh: {
+ type: Boolean,
+ default: true
+ },
+ selfField: {
+ type: String,
+ default: ''
+ },
+ parentField: {
+ type: String,
+ default: ''
+ },
+ multiple: {
+ type: Boolean,
+ default: false
+ },
+ map: {
+ type: Object,
+ default() {
+ return {
+ text: "text",
+ value: "value"
+ }
+ }
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ errorMessage: '',
+ loadMore: {
+ contentdown: '',
+ contentrefresh: '',
+ contentnomore: ''
+ },
+ dataList: [],
+ selected: [],
+ selectedIndex: 0,
+ page: {
+ current: this.pageCurrent,
+ size: this.pageSize,
+ count: 0
+ }
+ }
+ },
+ computed: {
+ isLocaldata() {
+ return !this.collection.length
+ },
+ postField() {
+ let fields = [this.field];
+ if (this.parentField) {
+ fields.push(`${this.parentField} as parent_value`);
+ }
+ return fields.join(',');
+ },
+ dataValue() {
+ let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
+ return isModelValue ? this.modelValue : this.value
+ },
+ hasValue() {
+ if (typeof this.dataValue === 'number') {
+ return true
+ }
+ return (this.dataValue != null) && (this.dataValue.length > 0)
+ }
+ },
+ created() {
+ this.$watch(() => {
+ var al = [];
+ ['pageCurrent',
+ 'pageSize',
+ 'spaceInfo',
+ 'value',
+ 'modelValue',
+ 'localdata',
+ 'collection',
+ 'action',
+ 'field',
+ 'orderby',
+ 'where',
+ 'getont',
+ 'getcount',
+ 'gettree'
+ ].forEach(key => {
+ al.push(this[key])
+ });
+ return al
+ }, (newValue, oldValue) => {
+ let needReset = false
+ for (let i = 2; i < newValue.length; i++) {
+ if (newValue[i] != oldValue[i]) {
+ needReset = true
+ break
+ }
+ }
+ if (newValue[0] != oldValue[0]) {
+ this.page.current = this.pageCurrent
+ }
+ this.page.size = this.pageSize
+
+ this.onPropsChange()
+ })
+ this._treeData = []
+ },
+ methods: {
+ onPropsChange() {
+ this._treeData = []
+ },
+ getCommand(options = {}) {
+ /* eslint-disable no-undef */
+ let db = uniCloud.database(this.spaceInfo)
+
+ const action = options.action || this.action
+ if (action) {
+ db = db.action(action)
+ }
+
+ const collection = options.collection || this.collection
+ db = db.collection(collection)
+
+ const where = options.where || this.where
+ if (!(!where || !Object.keys(where).length)) {
+ db = db.where(where)
+ }
+
+ const field = options.field || this.field
+ if (field) {
+ db = db.field(field)
+ }
+
+ const orderby = options.orderby || this.orderby
+ if (orderby) {
+ db = db.orderBy(orderby)
+ }
+
+ const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
+ const size = options.pageSize !== undefined ? options.pageSize : this.page.size
+ const getCount = options.getcount !== undefined ? options.getcount : this.getcount
+ const getTree = options.gettree !== undefined ? options.gettree : this.gettree
+
+ const getOptions = {
+ getCount,
+ getTree
+ }
+ if (options.getTreePath) {
+ getOptions.getTreePath = options.getTreePath
+ }
+
+ db = db.skip(size * (current - 1)).limit(size).get(getOptions)
+
+ return db
+ },
+ getNodeData(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+ this.getCommand({
+ field: this.postField,
+ where: this._pathWhere()
+ }).then((res) => {
+ this.loading = false
+ this.selected = res.result.data
+ callback && callback()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ getTreePath(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ getTreePath: {
+ startWith: `${this.selfField}=='${this.dataValue}'`
+ }
+ }).then((res) => {
+ this.loading = false
+ let treePath = []
+ this._extractTreePath(res.result.data, treePath)
+ this.selected = treePath
+ callback && callback()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ loadData() {
+ if (this.isLocaldata) {
+ this._processLocalData()
+ return
+ }
+
+ if (this.dataValue != null) {
+ this._loadNodeData((data) => {
+ this._treeData = data
+ this._updateBindData()
+ this._updateSelected()
+ })
+ return
+ }
+
+ if (this.stepSearh) {
+ this._loadNodeData((data) => {
+ this._treeData = data
+ this._updateBindData()
+ })
+ } else {
+ this._loadAllData((data) => {
+ this._treeData = []
+ this._extractTree(data, this._treeData, null)
+ this._updateBindData()
+ })
+ }
+ },
+ _loadAllData(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ gettree: true,
+ startwith: `${this.selfField}=='${this.dataValue}'`
+ }).then((res) => {
+ this.loading = false
+ callback(res.result.data)
+ this.onDataChange()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ _loadNodeData(callback, pw) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ where: pw || this._postWhere(),
+ pageSize: 500
+ }).then((res) => {
+ this.loading = false
+ callback(res.result.data)
+ this.onDataChange()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ _pathWhere() {
+ let result = []
+ let where_field = this._getParentNameByField();
+ if (where_field) {
+ result.push(`${where_field} == '${this.dataValue}'`)
+ }
+
+ if (this.where) {
+ return `(${this.where}) && (${result.join(' || ')})`
+ }
+
+ return result.join(' || ')
+ },
+ _postWhere() {
+ let result = []
+ let selected = this.selected
+ let parentField = this.parentField
+ if (parentField) {
+ result.push(`${parentField} == null || ${parentField} == ""`)
+ }
+ if (selected.length) {
+ for (var i = 0; i < selected.length - 1; i++) {
+ result.push(`${parentField} == '${selected[i].value}'`)
+ }
+ }
+
+ let where = []
+ if (this.where) {
+ where.push(`(${this.where})`)
+ }
+ if (result.length) {
+ where.push(`(${result.join(' || ')})`)
+ }
+
+ return where.join(' && ')
+ },
+ _nodeWhere() {
+ let result = []
+ let selected = this.selected
+ if (selected.length) {
+ result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
+ }
+
+ if (this.where) {
+ return `(${this.where}) && (${result.join(' || ')})`
+ }
+
+ return result.join(' || ')
+ },
+ _getParentNameByField() {
+ const fields = this.field.split(',');
+ let where_field = null;
+ for (let i = 0; i < fields.length; i++) {
+ const items = fields[i].split('as');
+ if (items.length < 2) {
+ continue;
+ }
+ if (items[1].trim() === 'value') {
+ where_field = items[0].trim();
+ break;
+ }
+ }
+ return where_field
+ },
+ _isTreeView() {
+ return (this.parentField && this.selfField)
+ },
+ _updateSelected() {
+ var dl = this.dataList
+ var sl = this.selected
+ let textField = this.map.text
+ let valueField = this.map.value
+ for (var i = 0; i < sl.length; i++) {
+ var value = sl[i].value
+ var dl2 = dl[i]
+ for (var j = 0; j < dl2.length; j++) {
+ var item2 = dl2[j]
+ if (item2[valueField] === value) {
+ sl[i].text = item2[textField]
+ break
+ }
+ }
+ }
+ },
+ _updateBindData(node) {
+ const {
+ dataList,
+ hasNodes
+ } = this._filterData(this._treeData, this.selected)
+
+ let isleaf = this._stepSearh === false && !hasNodes
+
+ if (node) {
+ node.isleaf = isleaf
+ }
+
+ this.dataList = dataList
+ this.selectedIndex = dataList.length - 1
+
+ if (!isleaf && this.selected.length < dataList.length) {
+ this.selected.push({
+ value: null,
+ text: "请选择"
+ })
+ }
+
+ return {
+ isleaf,
+ hasNodes
+ }
+ },
+ _filterData(data, paths) {
+ let dataList = []
+ let hasNodes = true
+
+ dataList.push(data.filter((item) => {
+ return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
+ }))
+ for (let i = 0; i < paths.length; i++) {
+ var value = paths[i].value
+ var nodes = data.filter((item) => {
+ return item.parent_value === value
+ })
+
+ if (nodes.length) {
+ dataList.push(nodes)
+ } else {
+ hasNodes = false
+ }
+ }
+
+ return {
+ dataList,
+ hasNodes
+ }
+ },
+ _extractTree(nodes, result, parent_value) {
+ let list = result || []
+ let valueField = this.map.value
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i]
+
+ let child = {}
+ for (let key in node) {
+ if (key !== 'children') {
+ child[key] = node[key]
+ }
+ }
+ if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
+ child.parent_value = parent_value
+ }
+ result.push(child)
+
+ let children = node.children
+ if (children) {
+ this._extractTree(children, result, node[valueField])
+ }
+ }
+ },
+ _extractTreePath(nodes, result) {
+ let list = result || []
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i]
+
+ let child = {}
+ for (let key in node) {
+ if (key !== 'children') {
+ child[key] = node[key]
+ }
+ }
+ result.push(child)
+
+ let children = node.children
+ if (children) {
+ this._extractTreePath(children, result)
+ }
+ }
+ },
+ _findNodePath(key, nodes, path = []) {
+ let textField = this.map.text
+ let valueField = this.map.value
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i]
+ let children = node.children
+ let text = node[textField]
+ let value = node[valueField]
+
+ path.push({
+ value,
+ text
+ })
+
+ if (value === key) {
+ return path
+ }
+
+ if (children) {
+ const p = this._findNodePath(key, children, path)
+ if (p.length) {
+ return p
+ }
+ }
+
+ path.pop()
+ }
+ return []
+ },
+ _processLocalData() {
+ this._treeData = []
+ this._extractTree(this.localdata, this._treeData)
+
+ var inputValue = this.dataValue
+ if (inputValue === undefined) {
+ return
+ }
+
+ if (Array.isArray(inputValue)) {
+ inputValue = inputValue[inputValue.length - 1]
+ if (typeof inputValue === 'object' && inputValue[this.map.value]) {
+ inputValue = inputValue[this.map.value]
+ }
+ }
+
+ this.selected = this._findNodePath(inputValue, this.localdata)
+ }
+ }
+}
diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
new file mode 100644
index 0000000..72f8b33
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
@@ -0,0 +1,333 @@
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+ {{item[map.text]}}
+
+
+
+
+
+
+
+
+
+ {{errorMessage}}
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-picker/package.json b/uni_modules/uni-data-picker/package.json
new file mode 100644
index 0000000..d4925ef
--- /dev/null
+++ b/uni_modules/uni-data-picker/package.json
@@ -0,0 +1,92 @@
+{
+ "id": "uni-data-picker",
+ "displayName": "uni-data-picker 数据驱动的picker选择器",
+ "version": "1.0.3",
+ "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "picker",
+ "级联",
+ "省市区",
+ ""
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-load-more",
+ "uni-icons",
+ "uni-scss"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-data-picker/readme.md b/uni_modules/uni-data-picker/readme.md
new file mode 100644
index 0000000..6cda224
--- /dev/null
+++ b/uni_modules/uni-data-picker/readme.md
@@ -0,0 +1,22 @@
+## DataPicker 级联选择
+> **组件名:uni-data-picker**
+> 代码块: `uDataPicker`
+> 关联组件:`uni-data-pickerview`、`uni-load-more`。
+
+
+`` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
+
+支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
+
+候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
+
+`` 组件尤其适用于地址选择、分类选择等选择类。
+
+`` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
+
+`` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
+
+在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-dateformat/changelog.md b/uni_modules/uni-dateformat/changelog.md
new file mode 100644
index 0000000..d551d7b
--- /dev/null
+++ b/uni_modules/uni-dateformat/changelog.md
@@ -0,0 +1,10 @@
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-dateformat](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
+## 0.0.5(2021-07-08)
+- 调整 默认时间不再是当前时间,而是显示'-'字符
+## 0.0.4(2021-05-12)
+- 新增 组件示例地址
+## 0.0.3(2021-02-04)
+- 调整为uni_modules目录规范
+- 修复 iOS 平台日期格式化出错的问题
diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
new file mode 100644
index 0000000..e00d559
--- /dev/null
+++ b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
@@ -0,0 +1,200 @@
+// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
+function pad(str, length = 2) {
+ str += ''
+ while (str.length < length) {
+ str = '0' + str
+ }
+ return str.slice(-length)
+}
+
+const parser = {
+ yyyy: (dateObj) => {
+ return pad(dateObj.year, 4)
+ },
+ yy: (dateObj) => {
+ return pad(dateObj.year)
+ },
+ MM: (dateObj) => {
+ return pad(dateObj.month)
+ },
+ M: (dateObj) => {
+ return dateObj.month
+ },
+ dd: (dateObj) => {
+ return pad(dateObj.day)
+ },
+ d: (dateObj) => {
+ return dateObj.day
+ },
+ hh: (dateObj) => {
+ return pad(dateObj.hour)
+ },
+ h: (dateObj) => {
+ return dateObj.hour
+ },
+ mm: (dateObj) => {
+ return pad(dateObj.minute)
+ },
+ m: (dateObj) => {
+ return dateObj.minute
+ },
+ ss: (dateObj) => {
+ return pad(dateObj.second)
+ },
+ s: (dateObj) => {
+ return dateObj.second
+ },
+ SSS: (dateObj) => {
+ return pad(dateObj.millisecond, 3)
+ },
+ S: (dateObj) => {
+ return dateObj.millisecond
+ },
+}
+
+// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12
+function getDate(time) {
+ if (time instanceof Date) {
+ return time
+ }
+ switch (typeof time) {
+ case 'string':
+ {
+ // 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
+ if (time.indexOf('T') > -1) {
+ return new Date(time)
+ }
+ return new Date(time.replace(/-/g, '/'))
+ }
+ default:
+ return new Date(time)
+ }
+}
+
+export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
+ if (!date && date !== 0) {
+ return ''
+ }
+ date = getDate(date)
+ const dateObj = {
+ year: date.getFullYear(),
+ month: date.getMonth() + 1,
+ day: date.getDate(),
+ hour: date.getHours(),
+ minute: date.getMinutes(),
+ second: date.getSeconds(),
+ millisecond: date.getMilliseconds()
+ }
+ const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
+ let flag = true
+ let result = format
+ while (flag) {
+ flag = false
+ result = result.replace(tokenRegExp, function(matched) {
+ flag = true
+ return parser[matched](dateObj)
+ })
+ }
+ return result
+}
+
+export function friendlyDate(time, {
+ locale = 'zh',
+ threshold = [60000, 3600000],
+ format = 'yyyy/MM/dd hh:mm:ss'
+}) {
+ if (time === '-') {
+ return time
+ }
+ if (!time && time !== 0) {
+ return ''
+ }
+ const localeText = {
+ zh: {
+ year: '年',
+ month: '月',
+ day: '天',
+ hour: '小时',
+ minute: '分钟',
+ second: '秒',
+ ago: '前',
+ later: '后',
+ justNow: '刚刚',
+ soon: '马上',
+ template: '{num}{unit}{suffix}'
+ },
+ en: {
+ year: 'year',
+ month: 'month',
+ day: 'day',
+ hour: 'hour',
+ minute: 'minute',
+ second: 'second',
+ ago: 'ago',
+ later: 'later',
+ justNow: 'just now',
+ soon: 'soon',
+ template: '{num} {unit} {suffix}'
+ }
+ }
+ const text = localeText[locale] || localeText.zh
+ let date = getDate(time)
+ let ms = date.getTime() - Date.now()
+ let absMs = Math.abs(ms)
+ if (absMs < threshold[0]) {
+ return ms < 0 ? text.justNow : text.soon
+ }
+ if (absMs >= threshold[1]) {
+ return formatDate(date, format)
+ }
+ let num
+ let unit
+ let suffix = text.later
+ if (ms < 0) {
+ suffix = text.ago
+ ms = -ms
+ }
+ const seconds = Math.floor((ms) / 1000)
+ const minutes = Math.floor(seconds / 60)
+ const hours = Math.floor(minutes / 60)
+ const days = Math.floor(hours / 24)
+ const months = Math.floor(days / 30)
+ const years = Math.floor(months / 12)
+ switch (true) {
+ case years > 0:
+ num = years
+ unit = text.year
+ break
+ case months > 0:
+ num = months
+ unit = text.month
+ break
+ case days > 0:
+ num = days
+ unit = text.day
+ break
+ case hours > 0:
+ num = hours
+ unit = text.hour
+ break
+ case minutes > 0:
+ num = minutes
+ unit = text.minute
+ break
+ default:
+ num = seconds
+ unit = text.second
+ break
+ }
+
+ if (locale === 'en') {
+ if (num === 1) {
+ num = 'a'
+ } else {
+ unit += 's'
+ }
+ }
+
+ return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
+ suffix)
+}
diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
new file mode 100644
index 0000000..c5ed030
--- /dev/null
+++ b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
@@ -0,0 +1,88 @@
+
+ {{dateShow}}
+
+
+
+
+
diff --git a/uni_modules/uni-dateformat/package.json b/uni_modules/uni-dateformat/package.json
new file mode 100644
index 0000000..786a670
--- /dev/null
+++ b/uni_modules/uni-dateformat/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-dateformat",
+ "displayName": "uni-dateformat 日期格式化",
+ "version": "1.0.0",
+ "description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "日期格式化",
+ "时间格式化",
+ "格式化时间",
+ ""
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-dateformat/readme.md b/uni_modules/uni-dateformat/readme.md
new file mode 100644
index 0000000..37ddb6e
--- /dev/null
+++ b/uni_modules/uni-dateformat/readme.md
@@ -0,0 +1,11 @@
+
+
+### DateFormat 日期格式化
+> **组件名:uni-dateformat**
+> 代码块: `uDateformat`
+
+
+日期格式化组件。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/changelog.md b/uni_modules/uni-datetime-picker/changelog.md
new file mode 100644
index 0000000..9611a30
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/changelog.md
@@ -0,0 +1,89 @@
+## 2.2.4(2022-03-31)
+- 修复 Vue3 下动态赋值,单选类型未响应的 bug
+## 2.2.3(2022-03-28)
+- 修复 Vue3 下动态赋值未响应的 bug
+## 2.2.2(2021-12-10)
+- 修复 clear-icon 属性在小程序平台不生效的 bug
+## 2.2.1(2021-12-10)
+- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的 bug
+## 2.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
+## 2.1.5(2021-11-09)
+- 新增 提供组件设计资源,组件样式调整
+## 2.1.4(2021-09-10)
+- 修复 hide-second 在移动端的 bug
+- 修复 单选赋默认值时,赋值日期未高亮的 bug
+- 修复 赋默认值时,移动端未正确显示时间的 bug
+## 2.1.3(2021-09-09)
+- 新增 hide-second 属性,支持只使用时分,隐藏秒
+## 2.1.2(2021-09-03)
+- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
+- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
+- 优化 调整字号大小,美化日历界面
+- 修复 因国际化导致的 placeholder 失效的 bug
+## 2.1.1(2021-08-24)
+- 新增 支持国际化
+- 优化 范围选择器在 pc 端过宽的问题
+## 2.1.0(2021-08-09)
+- 新增 适配 vue3
+## 2.0.19(2021-08-09)
+- 新增 支持作为 uni-forms 子组件相关功能
+- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug
+## 2.0.18(2021-08-05)
+- 修复 type 属性动态赋值无效的 bug
+- 修复 ‘确认’按钮被 tabbar 遮盖 bug
+- 修复 组件未赋值时范围选左、右日历相同的 bug
+## 2.0.17(2021-08-04)
+- 修复 范围选未正确显示当前值的 bug
+- 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug
+## 2.0.16(2021-07-21)
+- 新增 return-type 属性支持返回 date 日期对象
+## 2.0.15(2021-07-14)
+- 修复 单选日期类型,初始赋值后不在当前日历的 bug
+- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
+- 优化 移动端移除显示框的清空按钮,无实际用途
+## 2.0.14(2021-07-14)
+- 修复 组件赋值为空,界面未更新的 bug
+- 修复 start 和 end 不能动态赋值的 bug
+- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的 bug
+## 2.0.13(2021-07-08)
+- 修复 范围选择不能动态赋值的 bug
+## 2.0.12(2021-07-08)
+- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
+## 2.0.11(2021-07-08)
+- 优化 弹出层在超出视窗边缘定位不准确的问题
+## 2.0.10(2021-07-08)
+- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的 bug
+- 优化 弹出层在超出视窗边缘被遮盖的问题
+## 2.0.9(2021-07-07)
+- 新增 maskClick 事件
+- 修复 特殊情况日历 rpx 布局错误的 bug,rpx -> px
+- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
+## 2.0.8(2021-07-07)
+- 新增 日期时间显示框支持插槽
+## 2.0.7(2021-07-01)
+- 优化 添加 uni-icons 依赖
+## 2.0.6(2021-05-22)
+- 修复 图标在小程序上不显示的 bug
+- 优化 重命名引用组件,避免潜在组件命名冲突
+## 2.0.5(2021-05-20)
+- 优化 代码目录扁平化
+## 2.0.4(2021-05-12)
+- 新增 组件示例地址
+## 2.0.3(2021-05-10)
+- 修复 ios 下不识别 '-' 日期格式的 bug
+- 优化 pc 下弹出层添加边框和阴影
+## 2.0.2(2021-05-08)
+- 修复 在 admin 中获取弹出层定位错误的bug
+## 2.0.1(2021-05-08)
+- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
+## 2.0.0(2021-04-30)
+- 支持日历形式的日期+时间的范围选择
+ > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
+## 1.0.6(2021-03-18)
+- 新增 hide-second 属性,时间支持仅选择时、分
+- 修复 选择跟显示的日期不一样的 bug
+- 修复 chang事件触发2次的 bug
+- 修复 分、秒 end 范围错误的 bug
+- 优化 更好的 nvue 适配
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
new file mode 100644
index 0000000..3d2dbea
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
@@ -0,0 +1,185 @@
+
+
+
+
+ {{weeks.date}}
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
new file mode 100644
index 0000000..f05adaf
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
@@ -0,0 +1,898 @@
+
+
+
+
+
+
+
+ {{nowDate.month}}
+
+
+
+ {{SUNText}}
+
+
+ {{monText}}
+
+
+ {{TUEText}}
+
+
+ {{WEDText}}
+
+
+ {{THUText}}
+
+
+ {{FRIText}}
+
+
+ {{SATText}}
+
+
+
+
+
+
+
+
+
+
+ {{tempSingleDate ? tempSingleDate : selectDateText}}
+
+
+
+
+
+
+ {{tempRange.before ? tempRange.before : startDateText}}
+
+
+
+
+
+
+ {{tempRange.after ? tempRange.after : endDateText}}
+
+
+
+
+
+
+ 确认
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
new file mode 100644
index 0000000..cc76311
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "select date",
+ "uni-datetime-picker.selectTime": "select time",
+ "uni-datetime-picker.selectDateTime": "select datetime",
+ "uni-datetime-picker.startDate": "start date",
+ "uni-datetime-picker.endDate": "end date",
+ "uni-datetime-picker.startTime": "start time",
+ "uni-datetime-picker.endTime": "end time",
+ "uni-datetime-picker.ok": "ok",
+ "uni-datetime-picker.clear": "clear",
+ "uni-datetime-picker.cancel": "cancel",
+ "uni-calender.MON": "MON",
+ "uni-calender.TUE": "TUE",
+ "uni-calender.WED": "WED",
+ "uni-calender.THU": "THU",
+ "uni-calender.FRI": "FRI",
+ "uni-calender.SAT": "SAT",
+ "uni-calender.SUN": "SUN"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
new file mode 100644
index 0000000..de7509c
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
@@ -0,0 +1,8 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+ en,
+ 'zh-Hans': zhHans,
+ 'zh-Hant': zhHant
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
new file mode 100644
index 0000000..7bc7405
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "选择日期",
+ "uni-datetime-picker.selectTime": "选择时间",
+ "uni-datetime-picker.selectDateTime": "选择日期时间",
+ "uni-datetime-picker.startDate": "开始日期",
+ "uni-datetime-picker.endDate": "结束日期",
+ "uni-datetime-picker.startTime": "开始时间",
+ "uni-datetime-picker.endTime": "结束时间",
+ "uni-datetime-picker.ok": "确定",
+ "uni-datetime-picker.clear": "清除",
+ "uni-datetime-picker.cancel": "取消",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
new file mode 100644
index 0000000..7d37043
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "選擇日期",
+ "uni-datetime-picker.selectTime": "選擇時間",
+ "uni-datetime-picker.selectDateTime": "選擇日期時間",
+ "uni-datetime-picker.startDate": "開始日期",
+ "uni-datetime-picker.endDate": "結束日期",
+ "uni-datetime-picker.startTime": "開始时间",
+ "uni-datetime-picker.endTime": "結束时间",
+ "uni-datetime-picker.ok": "確定",
+ "uni-datetime-picker.clear": "清除",
+ "uni-datetime-picker.cancel": "取消",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js
new file mode 100644
index 0000000..9601aba
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false
+ }
+ },
+ mounted () {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del']
+ }
+ const listener = ($event) => {
+ if (this.disable) {
+ return
+ }
+ const keyName = Object.keys(keyNames).find(key => {
+ const keyName = $event.key
+ const value = keyNames[key]
+ return value === keyName || (Array.isArray(value) && value.includes(keyName))
+ })
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {})
+ }, 0)
+ }
+ }
+ document.addEventListener('keyup', listener)
+ this.$once('hook:beforeDestroy', () => {
+ document.removeEventListener('keyup', listener)
+ })
+ },
+ render: () => {}
+}
+// #endif
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
new file mode 100644
index 0000000..699aa63
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
@@ -0,0 +1,927 @@
+
+
+
+
+
+ {{time}}
+
+ {{selectTimeText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
new file mode 100644
index 0000000..ea00857
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
@@ -0,0 +1,997 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{rangeSeparator}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
new file mode 100644
index 0000000..efa5773
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
@@ -0,0 +1,410 @@
+class Calendar {
+ constructor({
+ date,
+ selected,
+ startDate,
+ endDate,
+ range,
+ // multipleStatus
+ } = {}) {
+ // 当前日期
+ this.date = this.getDate(new Date()) // 当前初入日期
+ // 打点信息
+ this.selected = selected || [];
+ // 范围开始
+ this.startDate = startDate
+ // 范围结束
+ this.endDate = endDate
+ this.range = range
+ // 多选状态
+ this.cleanMultipleStatus()
+ // 每周日期
+ this.weeks = {}
+ // this._getWeek(this.date.fullDate)
+ // this.multipleStatus = multipleStatus
+ this.lastHover = false
+ }
+ /**
+ * 设置日期
+ * @param {Object} date
+ */
+ setDate(date) {
+ this.selectDate = this.getDate(date)
+ this._getWeek(this.selectDate.fullDate)
+ }
+
+ /**
+ * 清理多选状态
+ */
+ cleanMultipleStatus() {
+ this.multipleStatus = {
+ before: '',
+ after: '',
+ data: []
+ }
+ }
+
+ /**
+ * 重置开始日期
+ */
+ resetSatrtDate(startDate) {
+ // 范围开始
+ this.startDate = startDate
+
+ }
+
+ /**
+ * 重置结束日期
+ */
+ resetEndDate(endDate) {
+ // 范围结束
+ this.endDate = endDate
+ }
+
+ /**
+ * 获取任意时间
+ */
+ getDate(date, AddDayCount = 0, str = 'day') {
+ if (!date) {
+ date = new Date()
+ }
+ if (typeof date !== 'object') {
+ date = date.replace(/-/g, '/')
+ }
+ const dd = new Date(date)
+ switch (str) {
+ case 'day':
+ dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ case 'month':
+ if (dd.getDate() === 31) {
+ dd.setDate(dd.getDate() + AddDayCount)
+ } else {
+ dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+ }
+ break
+ case 'year':
+ dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ }
+ const y = dd.getFullYear()
+ const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+ const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+ return {
+ fullDate: y + '-' + m + '-' + d,
+ year: y,
+ month: m,
+ date: d,
+ day: dd.getDay()
+ }
+ }
+
+
+ /**
+ * 获取上月剩余天数
+ */
+ _getLastMonthDays(firstDay, full) {
+ let dateArr = []
+ for (let i = firstDay; i > 0; i--) {
+ const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+ dateArr.push({
+ date: beforeDate,
+ month: full.month - 1,
+ disable: true
+ })
+ }
+ return dateArr
+ }
+ /**
+ * 获取本月天数
+ */
+ _currentMonthDys(dateData, full) {
+ let dateArr = []
+ let fullDate = this.date.fullDate
+ for (let i = 1; i <= dateData; i++) {
+ let isinfo = false
+ let nowDate = full.year + '-' + (full.month < 10 ?
+ full.month : full.month) + '-' + (i < 10 ?
+ '0' + i : i)
+ // 是否今天
+ let isDay = fullDate === nowDate
+ // 获取打点信息
+ let info = this.selected && this.selected.find((item) => {
+ if (this.dateEqual(nowDate, item.date)) {
+ return item
+ }
+ })
+
+ // 日期禁用
+ let disableBefore = true
+ let disableAfter = true
+ if (this.startDate) {
+ // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+ // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+ disableBefore = this.dateCompare(this.startDate, nowDate)
+ }
+
+ if (this.endDate) {
+ // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+ // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+ disableAfter = this.dateCompare(nowDate, this.endDate)
+ }
+ let multiples = this.multipleStatus.data
+ let checked = false
+ let multiplesStatus = -1
+ if (this.range) {
+ if (multiples) {
+ multiplesStatus = multiples.findIndex((item) => {
+ return this.dateEqual(item, nowDate)
+ })
+ }
+ if (multiplesStatus !== -1) {
+ checked = true
+ }
+ }
+ let data = {
+ fullDate: nowDate,
+ year: full.year,
+ date: i,
+ multiple: this.range ? checked : false,
+ beforeMultiple: this.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after),
+ afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after),
+ month: full.month,
+ disable: !(disableBefore && disableAfter),
+ isDay,
+ userChecked: false
+ }
+ if (info) {
+ data.extraInfo = info
+ }
+
+ dateArr.push(data)
+ }
+ return dateArr
+ }
+ /**
+ * 获取下月天数
+ */
+ _getNextMonthDays(surplus, full) {
+ let dateArr = []
+ for (let i = 1; i < surplus + 1; i++) {
+ dateArr.push({
+ date: i,
+ month: Number(full.month) + 1,
+ disable: true
+ })
+ }
+ return dateArr
+ }
+
+ /**
+ * 获取当前日期详情
+ * @param {Object} date
+ */
+ getInfo(date) {
+ if (!date) {
+ date = new Date()
+ }
+ const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+ return dateInfo
+ }
+
+ /**
+ * 比较时间大小
+ */
+ dateCompare(startDate, endDate) {
+ // 计算截止时间
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+ if (startDate <= endDate) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ /**
+ * 比较时间是否相等
+ */
+ dateEqual(before, after) {
+ // 计算截止时间
+ before = new Date(before.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ after = new Date(after.replace('-', '/').replace('-', '/'))
+ if (before.getTime() - after.getTime() === 0) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ /**
+ * 比较真实起始日期
+ */
+
+ isLogicBefore(currentDay, before, after) {
+ let logicBefore = before
+ if (before && after) {
+ logicBefore = this.dateCompare(before, after) ? before : after
+ }
+ return this.dateEqual(logicBefore, currentDay)
+ }
+
+ isLogicAfter(currentDay, before, after) {
+ let logicAfter = after
+ if (before && after) {
+ logicAfter = this.dateCompare(before, after) ? after : before
+ }
+ return this.dateEqual(logicAfter, currentDay)
+ }
+
+ /**
+ * 获取日期范围内所有日期
+ * @param {Object} begin
+ * @param {Object} end
+ */
+ geDateAll(begin, end) {
+ var arr = []
+ var ab = begin.split('-')
+ var ae = end.split('-')
+ var db = new Date()
+ db.setFullYear(ab[0], ab[1] - 1, ab[2])
+ var de = new Date()
+ de.setFullYear(ae[0], ae[1] - 1, ae[2])
+ var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+ var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+ for (var k = unixDb; k <= unixDe;) {
+ k = k + 24 * 60 * 60 * 1000
+ arr.push(this.getDate(new Date(parseInt(k))).fullDate)
+ }
+ return arr
+ }
+
+ /**
+ * 获取多选状态
+ */
+ setMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+ if (!this.range) return
+ if (before && after) {
+ if (!this.lastHover) {
+ this.lastHover = true
+ return
+ }
+ this.multipleStatus.before = fullDate
+ this.multipleStatus.after = ''
+ this.multipleStatus.data = []
+ this.multipleStatus.fulldate = ''
+ this.lastHover = false
+ } else {
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ this.lastHover = false
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
+ .after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
+ .before);
+ }
+ this.lastHover = true
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 鼠标 hover 更新多选状态
+ */
+ setHoverMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+
+ if (!this.range) return
+ if (this.lastHover) return
+
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 更新默认值多选状态
+ */
+ setDefaultMultiple(before, after) {
+ this.multipleStatus.before = before
+ this.multipleStatus.after = after
+ if (before && after) {
+ if (this.dateCompare(before, after)) {
+ this.multipleStatus.data = this.geDateAll(before, after);
+ this._getWeek(after)
+ } else {
+ this.multipleStatus.data = this.geDateAll(after, before);
+ this._getWeek(before)
+ }
+ }
+ }
+
+ /**
+ * 获取每周数据
+ * @param {Object} dateData
+ */
+ _getWeek(dateData) {
+ const {
+ fullDate,
+ year,
+ month,
+ date,
+ day
+ } = this.getDate(dateData)
+ let firstDay = new Date(year, month - 1, 1).getDay()
+ let currentDay = new Date(year, month, 0).getDate()
+ let dates = {
+ lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+ currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+ nextMonthDays: [], // 下个月开始几天
+ weeks: []
+ }
+ let canlender = []
+ const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+ dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+ canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+ let weeks = {}
+ // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
+ for (let i = 0; i < canlender.length; i++) {
+ if (i % 7 === 0) {
+ weeks[parseInt(i / 7)] = new Array(7)
+ }
+ weeks[parseInt(i / 7)][i % 7] = canlender[i]
+ }
+ this.canlender = canlender
+ this.weeks = weeks
+ }
+
+ //静态方法
+ // static init(date) {
+ // if (!this.instance) {
+ // this.instance = new Calendar(date);
+ // }
+ // return this.instance;
+ // }
+}
+
+
+export default Calendar
diff --git a/uni_modules/uni-datetime-picker/package.json b/uni_modules/uni-datetime-picker/package.json
new file mode 100644
index 0000000..0e44103
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/package.json
@@ -0,0 +1,90 @@
+{
+ "id": "uni-datetime-picker",
+ "displayName": "uni-datetime-picker 日期选择器",
+ "version": "2.2.4",
+ "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
+ "keywords": [
+ "uni-datetime-picker",
+ "uni-ui",
+ "uniui",
+ "日期时间选择器",
+ "日期时间"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "n"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-datetime-picker/readme.md b/uni_modules/uni-datetime-picker/readme.md
new file mode 100644
index 0000000..162fbef
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/readme.md
@@ -0,0 +1,21 @@
+
+
+> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
+
+## DatetimePicker 时间选择器
+
+> **组件名:uni-datetime-picker**
+> 代码块: `uDatetimePicker`
+
+
+该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
+
+若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
+
+**_点击 picker 默认值规则:_**
+
+- 若设置初始值 value, 会显示在 picker 显示框中
+- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-drawer/changelog.md b/uni_modules/uni-drawer/changelog.md
new file mode 100644
index 0000000..6d2488c
--- /dev/null
+++ b/uni_modules/uni-drawer/changelog.md
@@ -0,0 +1,13 @@
+## 1.2.1(2021-11-22)
+- 修复 vue3中个别scss变量无法找到的问题
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-drawer](https://uniapp.dcloud.io/component/uniui/uni-drawer)
+## 1.1.1(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.1.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.7(2021-05-12)
+- 新增 组件示例地址
+## 1.0.6(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-drawer/components/uni-drawer/keypress.js b/uni_modules/uni-drawer/components/uni-drawer/keypress.js
new file mode 100644
index 0000000..62dda46
--- /dev/null
+++ b/uni_modules/uni-drawer/components/uni-drawer/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false
+ }
+ },
+ mounted () {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del']
+ }
+ const listener = ($event) => {
+ if (this.disable) {
+ return
+ }
+ const keyName = Object.keys(keyNames).find(key => {
+ const keyName = $event.key
+ const value = keyNames[key]
+ return value === keyName || (Array.isArray(value) && value.includes(keyName))
+ })
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {})
+ }, 0)
+ }
+ }
+ document.addEventListener('keyup', listener)
+ // this.$once('hook:beforeDestroy', () => {
+ // document.removeEventListener('keyup', listener)
+ // })
+ },
+ render: () => {}
+}
+// #endif
diff --git a/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
new file mode 100644
index 0000000..82331a8
--- /dev/null
+++ b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-drawer/package.json b/uni_modules/uni-drawer/package.json
new file mode 100644
index 0000000..dd056e4
--- /dev/null
+++ b/uni_modules/uni-drawer/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "uni-drawer",
+ "displayName": "uni-drawer 抽屉",
+ "version": "1.2.1",
+ "description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "drawer",
+ "抽屉",
+ "侧滑导航"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-drawer/readme.md b/uni_modules/uni-drawer/readme.md
new file mode 100644
index 0000000..dcf6e6b
--- /dev/null
+++ b/uni_modules/uni-drawer/readme.md
@@ -0,0 +1,10 @@
+
+
+## Drawer 抽屉
+> **组件名:uni-drawer**
+> 代码块: `uDrawer`
+
+抽屉侧滑菜单。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-drawer)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-easyinput/changelog.md b/uni_modules/uni-easyinput/changelog.md
new file mode 100644
index 0000000..1cbe623
--- /dev/null
+++ b/uni_modules/uni-easyinput/changelog.md
@@ -0,0 +1,35 @@
+## 1.0.2(2022-04-12)
+- 修复 默认值不生效的bug
+## 1.0.1(2022-04-02)
+- 修复 value不能为0的bug
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
+## 0.1.4(2021-08-20)
+- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
+## 0.1.3(2021-08-11)
+- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
+## 0.1.2(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 0.1.1
+- 优化 errorMessage 属性支持 Boolean 类型
+## 0.1.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.0.16(2021-06-29)
+- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
+## 0.0.15(2021-06-21)
+- 修复 passwordIcon 属性拼写错误的 bug
+## 0.0.14(2021-06-18)
+- 新增 passwordIcon 属性,当type=password时是否显示小眼睛图标
+- 修复 confirmType 属性不生效的问题
+## 0.0.13(2021-06-04)
+- 修复 disabled 状态可清出内容的 bug
+## 0.0.12(2021-05-12)
+- 新增 组件示例地址
+## 0.0.11(2021-05-07)
+- 修复 input-border 属性不生效的问题
+## 0.0.10(2021-04-30)
+- 修复 ios 遮挡文字、显示一半的问题
+## 0.0.9(2021-02-05)
+- 调整为uni_modules目录规范
+- 优化 兼容 nvue 页面
diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/common.js b/uni_modules/uni-easyinput/components/uni-easyinput/common.js
new file mode 100644
index 0000000..df9abe1
--- /dev/null
+++ b/uni_modules/uni-easyinput/components/uni-easyinput/common.js
@@ -0,0 +1,56 @@
+/**
+ * @desc 函数防抖
+ * @param func 目标函数
+ * @param wait 延迟执行毫秒数
+ * @param immediate true - 立即执行, false - 延迟执行
+ */
+export const debounce = function(func, wait = 1000, immediate = true) {
+ let timer;
+ console.log(1);
+ return function() {
+ console.log(123);
+ let context = this,
+ args = arguments;
+ if (timer) clearTimeout(timer);
+ if (immediate) {
+ let callNow = !timer;
+ timer = setTimeout(() => {
+ timer = null;
+ }, wait);
+ if (callNow) func.apply(context, args);
+ } else {
+ timer = setTimeout(() => {
+ func.apply(context, args);
+ }, wait)
+ }
+ }
+}
+/**
+ * @desc 函数节流
+ * @param func 函数
+ * @param wait 延迟执行毫秒数
+ * @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
+ */
+export const throttle = (func, wait = 1000, type = 1) => {
+ let previous = 0;
+ let timeout;
+ return function() {
+ let context = this;
+ let args = arguments;
+ if (type === 1) {
+ let now = Date.now();
+
+ if (now - previous > wait) {
+ func.apply(context, args);
+ previous = now;
+ }
+ } else if (type === 2) {
+ if (!timeout) {
+ timeout = setTimeout(() => {
+ timeout = null;
+ func.apply(context, args)
+ }, wait)
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
new file mode 100644
index 0000000..33f73bd
--- /dev/null
+++ b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json
new file mode 100644
index 0000000..f1195b1
--- /dev/null
+++ b/uni_modules/uni-easyinput/package.json
@@ -0,0 +1,90 @@
+{
+ "id": "uni-easyinput",
+ "displayName": "uni-easyinput 增强输入框",
+ "version": "1.0.2",
+ "description": "Easyinput 组件是对原生input组件的增强",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "input",
+ "uni-easyinput",
+ "输入框"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-easyinput/readme.md b/uni_modules/uni-easyinput/readme.md
new file mode 100644
index 0000000..f1faf8f
--- /dev/null
+++ b/uni_modules/uni-easyinput/readme.md
@@ -0,0 +1,11 @@
+
+
+### Easyinput 增强输入框
+> **组件名:uni-easyinput**
+> 代码块: `uEasyinput`
+
+
+easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-fab/changelog.md b/uni_modules/uni-fab/changelog.md
new file mode 100644
index 0000000..24e26b1
--- /dev/null
+++ b/uni_modules/uni-fab/changelog.md
@@ -0,0 +1,17 @@
+## 1.2.2(2021-12-29)
+- 更新 组件依赖
+## 1.2.1(2021-11-19)
+- 修复 阴影颜色不正确的bug
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fab](https://uniapp.dcloud.io/component/uniui/uni-fab)
+## 1.1.1(2021-11-09)
+- 新增 提供组件设计资源,组件样式调整
+## 1.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.7(2021-05-12)
+- 新增 组件示例地址
+## 1.0.6(2021-02-05)
+- 调整为uni_modules目录规范
+- 优化 按钮背景色调整
+- 优化 兼容pc端
diff --git a/uni_modules/uni-fab/components/uni-fab/uni-fab.vue b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue
new file mode 100644
index 0000000..bef97f1
--- /dev/null
+++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue
@@ -0,0 +1,475 @@
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-fab/package.json b/uni_modules/uni-fab/package.json
new file mode 100644
index 0000000..0f27daa
--- /dev/null
+++ b/uni_modules/uni-fab/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "uni-fab",
+ "displayName": "uni-fab 悬浮按钮",
+ "version": "1.2.2",
+ "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "按钮",
+ "悬浮按钮",
+ "fab"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss","uni-icons"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-fab/readme.md b/uni_modules/uni-fab/readme.md
new file mode 100644
index 0000000..9a444e8
--- /dev/null
+++ b/uni_modules/uni-fab/readme.md
@@ -0,0 +1,9 @@
+## Fab 悬浮按钮
+> **组件名:uni-fab**
+> 代码块: `uFab`
+
+
+点击可展开一个图形按钮菜单
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fab)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-fav/changelog.md b/uni_modules/uni-fav/changelog.md
new file mode 100644
index 0000000..4b3f8c2
--- /dev/null
+++ b/uni_modules/uni-fav/changelog.md
@@ -0,0 +1,17 @@
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fav](https://uniapp.dcloud.io/component/uniui/uni-fav)
+## 1.1.1(2021-08-24)
+- 新增 支持国际化
+## 1.1.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.6(2021-05-12)
+- 新增 组件示例地址
+## 1.0.5(2021-04-21)
+- 优化 添加依赖 uni-icons, 导入后自动下载依赖
+## 1.0.4(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.0.3(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.0.2(2021-02-05)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/en.json b/uni_modules/uni-fav/components/uni-fav/i18n/en.json
new file mode 100644
index 0000000..9a0759e
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/i18n/en.json
@@ -0,0 +1,4 @@
+{
+ "uni-fav.collect": "collect",
+ "uni-fav.collected": "collected"
+}
diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/index.js b/uni_modules/uni-fav/components/uni-fav/i18n/index.js
new file mode 100644
index 0000000..de7509c
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/i18n/index.js
@@ -0,0 +1,8 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+ en,
+ 'zh-Hans': zhHans,
+ 'zh-Hant': zhHant
+}
diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json
new file mode 100644
index 0000000..67c89bf
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json
@@ -0,0 +1,4 @@
+{
+ "uni-fav.collect": "收藏",
+ "uni-fav.collected": "已收藏"
+}
diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json
new file mode 100644
index 0000000..67c89bf
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json
@@ -0,0 +1,4 @@
+{
+ "uni-fav.collect": "收藏",
+ "uni-fav.collected": "已收藏"
+}
diff --git a/uni_modules/uni-fav/components/uni-fav/uni-fav.vue b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue
new file mode 100644
index 0000000..4e87bc8
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+ {{ checked ? contentFav : contentDefault }}
+
+
+
+
+
+
diff --git a/uni_modules/uni-fav/package.json b/uni_modules/uni-fav/package.json
new file mode 100644
index 0000000..39e4f33
--- /dev/null
+++ b/uni_modules/uni-fav/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-fav",
+ "displayName": "uni-fav 收藏按钮",
+ "version": "1.2.0",
+ "description": " Fav 收藏组件,可自定义颜色、大小。",
+ "keywords": [
+ "fav",
+ "uni-ui",
+ "uniui",
+ "收藏"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-fav/readme.md b/uni_modules/uni-fav/readme.md
new file mode 100644
index 0000000..4de125d
--- /dev/null
+++ b/uni_modules/uni-fav/readme.md
@@ -0,0 +1,10 @@
+
+
+## Fav 收藏按钮
+> **组件名:uni-fav**
+> 代码块: `uFav`
+
+用于收藏功能,可点击切换选中、不选中的状态。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fav)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md
new file mode 100644
index 0000000..840a9e6
--- /dev/null
+++ b/uni_modules/uni-file-picker/changelog.md
@@ -0,0 +1,61 @@
+## 1.0.1(2021-11-23)
+- 修复 参数为对象的情况下,url在某些情况显示错误的bug
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
+## 0.2.16(2021-11-08)
+- 修复 传入空对象 ,显示错误的Bug
+## 0.2.15(2021-08-30)
+- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug
+## 0.2.14(2021-08-23)
+- 新增 参数中返回 fileID 字段
+## 0.2.13(2021-08-23)
+- 修复 腾讯云传入fileID 不能回显的bug
+- 修复 选择图片后,不能放大的问题
+## 0.2.12(2021-08-17)
+- 修复 由于 0.2.11 版本引起的不能回显图片的Bug
+## 0.2.11(2021-08-16)
+- 新增 clearFiles(index) 方法,可以手动删除指定文件
+- 修复 v-model 值设为 null 报错的Bug
+## 0.2.10(2021-08-13)
+- 修复 return-type="object" 时,无法删除文件的Bug
+## 0.2.9(2021-08-03)
+- 修复 auto-upload 属性失效的Bug
+## 0.2.8(2021-07-31)
+- 修复 fileExtname属性不指定值报错的Bug
+## 0.2.7(2021-07-31)
+- 修复 在某种场景下图片不回显的Bug
+## 0.2.6(2021-07-30)
+- 修复 return-type为object下,返回值不正确的Bug
+## 0.2.5(2021-07-30)
+- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题
+## 0.2.3(2021-07-28)
+- 优化 调整示例代码
+## 0.2.2(2021-07-27)
+- 修复 vue3 下赋值错误的Bug
+- 优化 h5平台下上传文件导致页面卡死的问题
+## 0.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.1.1(2021-07-02)
+- 修复 sourceType 缺少默认值导致 ios 无法选择文件
+## 0.1.0(2021-06-30)
+- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改
+## 0.0.11(2021-06-30)
+- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
+## 0.0.10(2021-06-29)
+- 优化 文件上传后进度条消失时机
+## 0.0.9(2021-06-29)
+- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug
+## 0.0.8(2021-06-15)
+- 修复 删除文件时无法触发 v-model 的Bug
+## 0.0.7(2021-05-12)
+- 新增 组件示例地址
+## 0.0.6(2021-04-09)
+- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
+## 0.0.5(2021-04-09)
+- 优化 更新组件示例
+## 0.0.4(2021-04-09)
+- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
+## 0.0.3(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js
new file mode 100644
index 0000000..24a07f5
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js
@@ -0,0 +1,224 @@
+'use strict';
+
+const ERR_MSG_OK = 'chooseAndUploadFile:ok';
+const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
+
+function chooseImage(opts) {
+ const {
+ count,
+ sizeType = ['original', 'compressed'],
+ sourceType = ['album', 'camera'],
+ extension
+ } = opts
+ return new Promise((resolve, reject) => {
+ uni.chooseImage({
+ count,
+ sizeType,
+ sourceType,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function chooseVideo(opts) {
+ const {
+ camera,
+ compressed,
+ maxDuration,
+ sourceType = ['album', 'camera'],
+ extension
+ } = opts;
+ return new Promise((resolve, reject) => {
+ uni.chooseVideo({
+ camera,
+ compressed,
+ maxDuration,
+ sourceType,
+ extension,
+ success(res) {
+ const {
+ tempFilePath,
+ duration,
+ size,
+ height,
+ width
+ } = res;
+ resolve(normalizeChooseAndUploadFileRes({
+ errMsg: 'chooseVideo:ok',
+ tempFilePaths: [tempFilePath],
+ tempFiles: [
+ {
+ name: (res.tempFile && res.tempFile.name) || '',
+ path: tempFilePath,
+ size,
+ type: (res.tempFile && res.tempFile.type) || '',
+ width,
+ height,
+ duration,
+ fileType: 'video',
+ cloudPath: '',
+ }, ],
+ }, 'video'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function chooseAll(opts) {
+ const {
+ count,
+ extension
+ } = opts;
+ return new Promise((resolve, reject) => {
+ let chooseFile = uni.chooseFile;
+ if (typeof wx !== 'undefined' &&
+ typeof wx.chooseMessageFile === 'function') {
+ chooseFile = wx.chooseMessageFile;
+ }
+ if (typeof chooseFile !== 'function') {
+ return reject({
+ errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
+ });
+ }
+ chooseFile({
+ type: 'all',
+ count,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function normalizeChooseAndUploadFileRes(res, fileType) {
+ res.tempFiles.forEach((item, index) => {
+ if (!item.name) {
+ item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
+ }
+ if (fileType) {
+ item.fileType = fileType;
+ }
+ item.cloudPath =
+ Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
+ });
+ if (!res.tempFilePaths) {
+ res.tempFilePaths = res.tempFiles.map((file) => file.path);
+ }
+ return res;
+}
+
+function uploadCloudFiles(files, max = 5, onUploadProgress) {
+ files = JSON.parse(JSON.stringify(files))
+ const len = files.length
+ let count = 0
+ let self = this
+ return new Promise(resolve => {
+ while (count < max) {
+ next()
+ }
+
+ function next() {
+ let cur = count++
+ if (cur >= len) {
+ !files.find(item => !item.url && !item.errMsg) && resolve(files)
+ return
+ }
+ const fileItem = files[cur]
+ const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
+ fileItem.url = ''
+ delete fileItem.errMsg
+
+ uniCloud
+ .uploadFile({
+ filePath: fileItem.path,
+ cloudPath: fileItem.cloudPath,
+ fileType: fileItem.fileType,
+ onUploadProgress: res => {
+ res.index = index
+ onUploadProgress && onUploadProgress(res)
+ }
+ })
+ .then(res => {
+ fileItem.url = res.fileID
+ fileItem.index = index
+ if (cur < len) {
+ next()
+ }
+ })
+ .catch(res => {
+ fileItem.errMsg = res.errMsg || res.message
+ fileItem.index = index
+ if (cur < len) {
+ next()
+ }
+ })
+ }
+ })
+}
+
+
+
+
+
+function uploadFiles(choosePromise, {
+ onChooseFile,
+ onUploadProgress
+}) {
+ return choosePromise
+ .then((res) => {
+ if (onChooseFile) {
+ const customChooseRes = onChooseFile(res);
+ if (typeof customChooseRes !== 'undefined') {
+ return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
+ res : chooseRes);
+ }
+ }
+ return res;
+ })
+ .then((res) => {
+ if (res === false) {
+ return {
+ errMsg: ERR_MSG_OK,
+ tempFilePaths: [],
+ tempFiles: [],
+ };
+ }
+ return res
+ })
+}
+
+function chooseAndUploadFile(opts = {
+ type: 'all'
+}) {
+ if (opts.type === 'image') {
+ return uploadFiles(chooseImage(opts), opts);
+ }
+ else if (opts.type === 'video') {
+ return uploadFiles(chooseVideo(opts), opts);
+ }
+ return uploadFiles(chooseAll(opts), opts);
+}
+
+export {
+ chooseAndUploadFile,
+ uploadCloudFiles
+};
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
new file mode 100644
index 0000000..a9d05a8
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
@@ -0,0 +1,651 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
new file mode 100644
index 0000000..625d92e
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
new file mode 100644
index 0000000..2a29bc2
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
new file mode 100644
index 0000000..60aaa3e
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
@@ -0,0 +1,109 @@
+/**
+ * 获取文件名和后缀
+ * @param {String} name
+ */
+export const get_file_ext = (name) => {
+ const last_len = name.lastIndexOf('.')
+ const len = name.length
+ return {
+ name: name.substring(0, last_len),
+ ext: name.substring(last_len + 1, len)
+ }
+}
+
+/**
+ * 获取扩展名
+ * @param {Array} fileExtname
+ */
+export const get_extname = (fileExtname) => {
+ if (!Array.isArray(fileExtname)) {
+ let extname = fileExtname.replace(/(\[|\])/g, '')
+ return extname.split(',')
+ } else {
+ return fileExtname
+ }
+ return []
+}
+
+/**
+ * 获取文件和检测是否可选
+ */
+export const get_files_and_is_max = (res, _extname) => {
+ let filePaths = []
+ let files = []
+ if(!_extname || _extname.length === 0){
+ return {
+ filePaths,
+ files
+ }
+ }
+ res.tempFiles.forEach(v => {
+ let fileFullName = get_file_ext(v.name)
+ const extname = fileFullName.ext.toLowerCase()
+ if (_extname.indexOf(extname) !== -1) {
+ files.push(v)
+ filePaths.push(v.path)
+ }
+ })
+ if (files.length !== res.tempFiles.length) {
+ uni.showToast({
+ title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
+ icon: 'none',
+ duration: 5000
+ })
+ }
+
+ return {
+ filePaths,
+ files
+ }
+}
+
+
+/**
+ * 获取图片信息
+ * @param {Object} filepath
+ */
+export const get_file_info = (filepath) => {
+ return new Promise((resolve, reject) => {
+ uni.getImageInfo({
+ src: filepath,
+ success(res) {
+ resolve(res)
+ },
+ fail(err) {
+ reject(err)
+ }
+ })
+ })
+}
+/**
+ * 获取封装数据
+ */
+export const get_file_data = async (files, type = 'image') => {
+ // 最终需要上传数据库的数据
+ let fileFullName = get_file_ext(files.name)
+ const extname = fileFullName.ext.toLowerCase()
+ let filedata = {
+ name: files.name,
+ uuid: files.uuid,
+ extname: extname || '',
+ cloudPath: files.cloudPath,
+ fileType: files.fileType,
+ url: files.path || files.path,
+ size: files.size, //单位是字节
+ image: {},
+ path: files.path,
+ video: {}
+ }
+ if (type === 'image') {
+ const imageinfo = await get_file_info(files.path)
+ delete filedata.video
+ filedata.image.width = imageinfo.width
+ filedata.image.height = imageinfo.height
+ filedata.image.location = imageinfo.path
+ } else {
+ delete filedata.image
+ }
+ return filedata
+}
diff --git a/uni_modules/uni-file-picker/package.json b/uni_modules/uni-file-picker/package.json
new file mode 100644
index 0000000..d659bb5
--- /dev/null
+++ b/uni_modules/uni-file-picker/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-file-picker",
+ "displayName": "uni-file-picker 文件选择上传",
+ "version": "1.0.1",
+ "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "图片上传",
+ "文件上传"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "n"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md
new file mode 100644
index 0000000..c8399a5
--- /dev/null
+++ b/uni_modules/uni-file-picker/readme.md
@@ -0,0 +1,11 @@
+
+## FilePicker 文件选择上传
+
+> **组件名:uni-file-picker**
+> 代码块: `uFilePicker`
+
+
+文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-forms/changelog.md b/uni_modules/uni-forms/changelog.md
new file mode 100644
index 0000000..26e120b
--- /dev/null
+++ b/uni_modules/uni-forms/changelog.md
@@ -0,0 +1,60 @@
+## 1.3.2(2021-12-09)
+-
+## 1.3.1(2021-11-19)
+- 修复 label 插槽不生效的bug
+## 1.3.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-forms](https://uniapp.dcloud.io/component/uniui/uni-forms)
+## 1.2.7(2021-08-13)
+- 修复 没有添加校验规则的字段依然报错的Bug
+## 1.2.6(2021-08-11)
+- 修复 重置表单错误信息无法清除的问题
+## 1.2.5(2021-08-11)
+- 优化 组件文档
+## 1.2.4(2021-08-11)
+- 修复 表单验证只生效一次的问题
+## 1.2.3(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.2.2(2021-07-26)
+- 修复 vue2 下条件编译导致destroyed生命周期失效的Bug
+- 修复 1.2.1 引起的示例在小程序平台报错的Bug
+## 1.2.1(2021-07-22)
+- 修复 动态校验表单,默认值为空的情况下校验失效的Bug
+- 修复 不指定name属性时,运行报错的Bug
+- 优化 label默认宽度从65调整至70,使required为true且四字时不换行
+- 优化 组件示例,新增动态校验示例代码
+- 优化 组件文档,使用方式更清晰
+## 1.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.2(2021-06-25)
+- 修复 pattern 属性在微信小程序平台无效的问题
+## 1.1.1(2021-06-22)
+- 修复 validate-trigger属性为submit且err-show-type属性为toast时不能弹出的Bug
+## 1.1.0(2021-06-22)
+- 修复 只写setRules方法而导致校验不生效的Bug
+- 修复 由上个办法引发的错误提示文字错位的Bug
+## 1.0.48(2021-06-21)
+- 修复 不设置 label 属性 ,无法设置label插槽的问题
+## 1.0.47(2021-06-21)
+- 修复 不设置label属性,label-width属性不生效的bug
+- 修复 setRules 方法与rules属性冲突的问题
+## 1.0.46(2021-06-04)
+- 修复 动态删减数据导致报错的问题
+## 1.0.45(2021-06-04)
+- 新增 modelValue 属性 ,value 即将废弃
+## 1.0.44(2021-06-02)
+- 新增 uni-forms-item 可以设置单独的 rules
+- 新增 validate 事件增加 keepitem 参数,可以选择那些字段不过滤
+- 优化 submit 事件重命名为 validate
+## 1.0.43(2021-05-12)
+- 新增 组件示例地址
+## 1.0.42(2021-04-30)
+- 修复 自定义检验器失效的问题
+## 1.0.41(2021-03-05)
+- 更新 校验器
+- 修复 表单规则设置类型为 number 的情况下,值为0校验失败的Bug
+## 1.0.40(2021-03-04)
+- 修复 动态显示uni-forms-item的情况下,submit 方法获取值错误的Bug
+## 1.0.39(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 校验器传入 int 等类型 ,返回String类型的Bug
diff --git a/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
new file mode 100644
index 0000000..a5ae8ab
--- /dev/null
+++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
@@ -0,0 +1,509 @@
+
+
+
+
+
+
+ *
+
+ {{ label }}
+
+
+
+
+
+
+
+ {{ showMsg === 'undertext' ? msg : '' }}
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue
new file mode 100644
index 0000000..d8b4e66
--- /dev/null
+++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue
@@ -0,0 +1,472 @@
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-forms/components/uni-forms/validate.js b/uni_modules/uni-forms/components/uni-forms/validate.js
new file mode 100644
index 0000000..1834c6c
--- /dev/null
+++ b/uni_modules/uni-forms/components/uni-forms/validate.js
@@ -0,0 +1,486 @@
+var pattern = {
+ email: /^\S+?@\S+?\.\S+?$/,
+ idcard: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
+ url: new RegExp(
+ "^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$",
+ 'i')
+};
+
+const FORMAT_MAPPING = {
+ "int": 'integer',
+ "bool": 'boolean',
+ "double": 'number',
+ "long": 'number',
+ "password": 'string'
+ // "fileurls": 'array'
+}
+
+function formatMessage(args, resources = '') {
+ var defaultMessage = ['label']
+ defaultMessage.forEach((item) => {
+ if (args[item] === undefined) {
+ args[item] = ''
+ }
+ })
+
+ let str = resources
+ for (let key in args) {
+ let reg = new RegExp('{' + key + '}')
+ str = str.replace(reg, args[key])
+ }
+ return str
+}
+
+function isEmptyValue(value, type) {
+ if (value === undefined || value === null) {
+ return true;
+ }
+
+ if (typeof value === 'string' && !value) {
+ return true;
+ }
+
+ if (Array.isArray(value) && !value.length) {
+ return true;
+ }
+
+ if (type === 'object' && !Object.keys(value).length) {
+ return true;
+ }
+
+ return false;
+}
+
+const types = {
+ integer(value) {
+ return types.number(value) && parseInt(value, 10) === value;
+ },
+ string(value) {
+ return typeof value === 'string';
+ },
+ number(value) {
+ if (isNaN(value)) {
+ return false;
+ }
+ return typeof value === 'number';
+ },
+ "boolean": function(value) {
+ return typeof value === 'boolean';
+ },
+ "float": function(value) {
+ return types.number(value) && !types.integer(value);
+ },
+ array(value) {
+ return Array.isArray(value);
+ },
+ object(value) {
+ return typeof value === 'object' && !types.array(value);
+ },
+ date(value) {
+ return value instanceof Date;
+ },
+ timestamp(value) {
+ if (!this.integer(value) || Math.abs(value).toString().length > 16) {
+ return false
+ }
+ return true;
+ },
+ file(value) {
+ return typeof value.url === 'string';
+ },
+ email(value) {
+ return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255;
+ },
+ url(value) {
+ return typeof value === 'string' && !!value.match(pattern.url);
+ },
+ pattern(reg, value) {
+ try {
+ return new RegExp(reg).test(value);
+ } catch (e) {
+ return false;
+ }
+ },
+ method(value) {
+ return typeof value === 'function';
+ },
+ idcard(value) {
+ return typeof value === 'string' && !!value.match(pattern.idcard);
+ },
+ 'url-https'(value) {
+ return this.url(value) && value.startsWith('https://');
+ },
+ 'url-scheme'(value) {
+ return value.startsWith('://');
+ },
+ 'url-web'(value) {
+ return false;
+ }
+}
+
+class RuleValidator {
+
+ constructor(message) {
+ this._message = message
+ }
+
+ async validateRule(fieldKey, fieldValue, value, data, allData) {
+ var result = null
+
+ let rules = fieldValue.rules
+
+ let hasRequired = rules.findIndex((item) => {
+ return item.required
+ })
+ if (hasRequired < 0) {
+ if (value === null || value === undefined) {
+ return result
+ }
+ if (typeof value === 'string' && !value.length) {
+ return result
+ }
+ }
+
+ var message = this._message
+
+ if (rules === undefined) {
+ return message['default']
+ }
+
+ for (var i = 0; i < rules.length; i++) {
+ let rule = rules[i]
+ let vt = this._getValidateType(rule)
+
+ Object.assign(rule, {
+ label: fieldValue.label || `["${fieldKey}"]`
+ })
+
+ if (RuleValidatorHelper[vt]) {
+ result = RuleValidatorHelper[vt](rule, value, message)
+ if (result != null) {
+ break
+ }
+ }
+
+ if (rule.validateExpr) {
+ let now = Date.now()
+ let resultExpr = rule.validateExpr(value, allData, now)
+ if (resultExpr === false) {
+ result = this._getMessage(rule, rule.errorMessage || this._message['default'])
+ break
+ }
+ }
+
+ if (rule.validateFunction) {
+ result = await this.validateFunction(rule, value, data, allData, vt)
+ if (result !== null) {
+ break
+ }
+ }
+ }
+
+ if (result !== null) {
+ result = message.TAG + result
+ }
+
+ return result
+ }
+
+ async validateFunction(rule, value, data, allData, vt) {
+ let result = null
+ try {
+ let callbackMessage = null
+ const res = await rule.validateFunction(rule, value, allData || data, (message) => {
+ callbackMessage = message
+ })
+ if (callbackMessage || (typeof res === 'string' && res) || res === false) {
+ result = this._getMessage(rule, callbackMessage || res, vt)
+ }
+ } catch (e) {
+ result = this._getMessage(rule, e.message, vt)
+ }
+ return result
+ }
+
+ _getMessage(rule, message, vt) {
+ return formatMessage(rule, message || rule.errorMessage || this._message[vt] || message['default'])
+ }
+
+ _getValidateType(rule) {
+ var result = ''
+ if (rule.required) {
+ result = 'required'
+ } else if (rule.format) {
+ result = 'format'
+ } else if (rule.arrayType) {
+ result = 'arrayTypeFormat'
+ } else if (rule.range) {
+ result = 'range'
+ } else if (rule.maximum !== undefined || rule.minimum !== undefined) {
+ result = 'rangeNumber'
+ } else if (rule.maxLength !== undefined || rule.minLength !== undefined) {
+ result = 'rangeLength'
+ } else if (rule.pattern) {
+ result = 'pattern'
+ } else if (rule.validateFunction) {
+ result = 'validateFunction'
+ }
+ return result
+ }
+}
+
+const RuleValidatorHelper = {
+ required(rule, value, message) {
+ if (rule.required && isEmptyValue(value, rule.format || typeof value)) {
+ return formatMessage(rule, rule.errorMessage || message.required);
+ }
+
+ return null
+ },
+
+ range(rule, value, message) {
+ const {
+ range,
+ errorMessage
+ } = rule;
+
+ let list = new Array(range.length);
+ for (let i = 0; i < range.length; i++) {
+ const item = range[i];
+ if (types.object(item) && item.value !== undefined) {
+ list[i] = item.value;
+ } else {
+ list[i] = item;
+ }
+ }
+
+ let result = false
+ if (Array.isArray(value)) {
+ result = (new Set(value.concat(list)).size === list.length);
+ } else {
+ if (list.indexOf(value) > -1) {
+ result = true;
+ }
+ }
+
+ if (!result) {
+ return formatMessage(rule, errorMessage || message['enum']);
+ }
+
+ return null
+ },
+
+ rangeNumber(rule, value, message) {
+ if (!types.number(value)) {
+ return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+ }
+
+ let {
+ minimum,
+ maximum,
+ exclusiveMinimum,
+ exclusiveMaximum
+ } = rule;
+ let min = exclusiveMinimum ? value <= minimum : value < minimum;
+ let max = exclusiveMaximum ? value >= maximum : value > maximum;
+
+ if (minimum !== undefined && min) {
+ return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMinimum ?
+ 'exclusiveMinimum' : 'minimum'
+ ])
+ } else if (maximum !== undefined && max) {
+ return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMaximum ?
+ 'exclusiveMaximum' : 'maximum'
+ ])
+ } else if (minimum !== undefined && maximum !== undefined && (min || max)) {
+ return formatMessage(rule, rule.errorMessage || message['number'].range)
+ }
+
+ return null
+ },
+
+ rangeLength(rule, value, message) {
+ if (!types.string(value) && !types.array(value)) {
+ return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+ }
+
+ let min = rule.minLength;
+ let max = rule.maxLength;
+ let val = value.length;
+
+ if (min !== undefined && val < min) {
+ return formatMessage(rule, rule.errorMessage || message['length'].minLength)
+ } else if (max !== undefined && val > max) {
+ return formatMessage(rule, rule.errorMessage || message['length'].maxLength)
+ } else if (min !== undefined && max !== undefined && (val < min || val > max)) {
+ return formatMessage(rule, rule.errorMessage || message['length'].range)
+ }
+
+ return null
+ },
+
+ pattern(rule, value, message) {
+ if (!types['pattern'](rule.pattern, value)) {
+ return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+ }
+
+ return null
+ },
+
+ format(rule, value, message) {
+ var customTypes = Object.keys(types);
+ var format = FORMAT_MAPPING[rule.format] ? FORMAT_MAPPING[rule.format] : (rule.format || rule.arrayType);
+
+ if (customTypes.indexOf(format) > -1) {
+ if (!types[format](value)) {
+ return formatMessage(rule, rule.errorMessage || message.typeError);
+ }
+ }
+
+ return null
+ },
+
+ arrayTypeFormat(rule, value, message) {
+ if (!Array.isArray(value)) {
+ return formatMessage(rule, rule.errorMessage || message.typeError);
+ }
+
+ for (let i = 0; i < value.length; i++) {
+ const element = value[i];
+ let formatResult = this.format(rule, element, message)
+ if (formatResult !== null) {
+ return formatResult
+ }
+ }
+
+ return null
+ }
+}
+
+class SchemaValidator extends RuleValidator {
+
+ constructor(schema, options) {
+ super(SchemaValidator.message);
+
+ this._schema = schema
+ this._options = options || null
+ }
+
+ updateSchema(schema) {
+ this._schema = schema
+ }
+
+ async validate(data, allData) {
+ let result = this._checkFieldInSchema(data)
+ if (!result) {
+ result = await this.invokeValidate(data, false, allData)
+ }
+ return result.length ? result[0] : null
+ }
+
+ async validateAll(data, allData) {
+ let result = this._checkFieldInSchema(data)
+ if (!result) {
+ result = await this.invokeValidate(data, true, allData)
+ }
+ return result
+ }
+
+ async validateUpdate(data, allData) {
+ let result = this._checkFieldInSchema(data)
+ if (!result) {
+ result = await this.invokeValidateUpdate(data, false, allData)
+ }
+ return result.length ? result[0] : null
+ }
+
+ async invokeValidate(data, all, allData) {
+ let result = []
+ let schema = this._schema
+ for (let key in schema) {
+ let value = schema[key]
+ let errorMessage = await this.validateRule(key, value, data[key], data, allData)
+ if (errorMessage != null) {
+ result.push({
+ key,
+ errorMessage
+ })
+ if (!all) break
+ }
+ }
+ return result
+ }
+
+ async invokeValidateUpdate(data, all, allData) {
+ let result = []
+ for (let key in data) {
+ let errorMessage = await this.validateRule(key, this._schema[key], data[key], data, allData)
+ if (errorMessage != null) {
+ result.push({
+ key,
+ errorMessage
+ })
+ if (!all) break
+ }
+ }
+ return result
+ }
+
+ _checkFieldInSchema(data) {
+ var keys = Object.keys(data)
+ var keys2 = Object.keys(this._schema)
+ if (new Set(keys.concat(keys2)).size === keys2.length) {
+ return ''
+ }
+
+ var noExistFields = keys.filter((key) => {
+ return keys2.indexOf(key) < 0;
+ })
+ var errorMessage = formatMessage({
+ field: JSON.stringify(noExistFields)
+ }, SchemaValidator.message.TAG + SchemaValidator.message['defaultInvalid'])
+ return [{
+ key: 'invalid',
+ errorMessage
+ }]
+ }
+}
+
+function Message() {
+ return {
+ TAG: "",
+ default: '验证错误',
+ defaultInvalid: '提交的字段{field}在数据库中并不存在',
+ validateFunction: '验证无效',
+ required: '{label}必填',
+ 'enum': '{label}超出范围',
+ timestamp: '{label}格式无效',
+ whitespace: '{label}不能为空',
+ typeError: '{label}类型无效',
+ date: {
+ format: '{label}日期{value}格式无效',
+ parse: '{label}日期无法解析,{value}无效',
+ invalid: '{label}日期{value}无效'
+ },
+ length: {
+ minLength: '{label}长度不能少于{minLength}',
+ maxLength: '{label}长度不能超过{maxLength}',
+ range: '{label}必须介于{minLength}和{maxLength}之间'
+ },
+ number: {
+ minimum: '{label}不能小于{minimum}',
+ maximum: '{label}不能大于{maximum}',
+ exclusiveMinimum: '{label}不能小于等于{minimum}',
+ exclusiveMaximum: '{label}不能大于等于{maximum}',
+ range: '{label}必须介于{minimum}and{maximum}之间'
+ },
+ pattern: {
+ mismatch: '{label}格式不匹配'
+ }
+ };
+}
+
+
+SchemaValidator.message = new Message();
+
+export default SchemaValidator
diff --git a/uni_modules/uni-forms/package.json b/uni_modules/uni-forms/package.json
new file mode 100644
index 0000000..dfa7af4
--- /dev/null
+++ b/uni_modules/uni-forms/package.json
@@ -0,0 +1,90 @@
+{
+ "id": "uni-forms",
+ "displayName": "uni-forms 表单",
+ "version": "1.3.2",
+ "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据",
+ "keywords": [
+ "uni-ui",
+ "表单",
+ "校验",
+ "表单校验",
+ "表单验证"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-scss",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-forms/readme.md b/uni_modules/uni-forms/readme.md
new file mode 100644
index 0000000..63d5a04
--- /dev/null
+++ b/uni_modules/uni-forms/readme.md
@@ -0,0 +1,23 @@
+
+
+## Forms 表单
+
+> **组件名:uni-forms**
+> 代码块: `uForms`、`uni-forms-item`
+> 关联组件:`uni-forms-item`、`uni-easyinput`、`uni-data-checkbox`、`uni-group`。
+
+
+uni-app的内置组件已经有了 `