Browse Source

初始化

master
tanghong 1 year ago
commit
d8629f96fa
  1. 49
      .gitignore
  2. 19
      App.vue
  3. 46
      api/card.js
  4. 66
      api/login.js
  5. 31
      api/oauth.js
  6. 52
      api/system/dict/data.js
  7. 60
      api/system/dict/type.js
  8. 41
      api/system/user.js
  9. 90
      components/geek-xd/components/geek-certificate/geek-certificate.vue
  10. 681
      components/geek-xd/components/geek-color-picker/geek-color-picker.vue
  11. 123
      components/geek-xd/components/geek-commodity/geek-commodity.vue
  12. 72
      components/geek-xd/components/geek-menu/geek-menu.vue
  13. 221
      components/geek-xd/components/geek-order/geek-order.vue
  14. 90
      components/geek-xd/components/geek-qrcode/README.md
  15. 205
      components/geek-xd/components/geek-qrcode/geek-qrcode.vue
  16. 1206
      components/geek-xd/components/geek-qrcode/qrcode.js
  17. 84
      components/geek-xd/components/geek-statistic/geek-statistic.vue
  18. 18
      components/geek-xd/types/index.ts
  19. 320
      components/qiun-data-charts/changelog.md
  20. 1614
      components/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
  21. 46
      components/qiun-data-charts/components/qiun-error/qiun-error.vue
  22. 162
      components/qiun-data-charts/components/qiun-loading/loading1.vue
  23. 170
      components/qiun-data-charts/components/qiun-loading/loading2.vue
  24. 173
      components/qiun-data-charts/components/qiun-loading/loading3.vue
  25. 222
      components/qiun-data-charts/components/qiun-loading/loading4.vue
  26. 229
      components/qiun-data-charts/components/qiun-loading/loading5.vue
  27. 36
      components/qiun-data-charts/components/qiun-loading/qiun-loading.vue
  28. 422
      components/qiun-data-charts/js_sdk/u-charts/config-echarts.js
  29. 606
      components/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
  30. 5
      components/qiun-data-charts/js_sdk/u-charts/readme.md
  31. 7706
      components/qiun-data-charts/js_sdk/u-charts/u-charts.js
  32. 18
      components/qiun-data-charts/js_sdk/u-charts/u-charts.min.js
  33. 201
      components/qiun-data-charts/license.md
  34. 80
      components/qiun-data-charts/package.json
  35. 84
      components/qiun-data-charts/readme.md
  36. 23
      components/qiun-data-charts/static/app-plus/echarts.min.js
  37. 23
      components/qiun-data-charts/static/h5/echarts.min.js
  38. 54
      components/ruoyi/DictTag/index.vue
  39. 1
      components/u-city-select/area.js
  40. 1
      components/u-city-select/city.js
  41. 1
      components/u-city-select/province.js
  42. 240
      components/u-city-select/u-city-select.vue
  43. 167
      components/uni-section/uni-section.vue
  44. 31
      config.js
  45. 79
      directive/common/copyText.ts
  46. 7
      directive/common/focus.ts
  47. 50
      directive/common/full.ts
  48. 18
      directive/index.ts
  49. 30
      directive/permission/hasPermi.ts
  50. 30
      directive/permission/hasRole.ts
  51. 11
      env.d.ts
  52. 21
      index.html
  53. 38
      main.js
  54. 72
      manifest.json
  55. 11475
      package-lock.json
  56. 86
      package.json
  57. 280
      pages.json
  58. 43
      pages/common/textview/index.vue
  59. 34
      pages/common/webview/index.vue
  60. 75
      pages/index.vue
  61. 213
      pages/login.vue
  62. 242
      pages/mine.vue
  63. 131
      pages/template.config.js
  64. 65
      pages/template.vue
  65. 184
      pages/work.vue
  66. 130
      pages_geek/pages/code/index.vue
  67. 120
      pages_geek/pages/index/index.vue
  68. 71
      pages_mine/pages/about/index.vue
  69. 642
      pages_mine/pages/avatar/index.vue
  70. 109
      pages_mine/pages/help/index.vue
  71. 132
      pages_mine/pages/info/edit.vue
  72. 53
      pages_mine/pages/info/index.vue
  73. 91
      pages_mine/pages/pwd/index.vue
  74. 104
      pages_mine/pages/setting/index.vue
  75. 148
      pages_qiun/components/card-swiper/card-swiper.vue
  76. 141
      pages_qiun/components/data-center/user-healthy.vue
  77. 200
      pages_qiun/components/data-center/user-operate.vue
  78. 385
      pages_qiun/components/data-center/user-server.vue
  79. 132
      pages_qiun/components/data-center/wechat.vue
  80. 93
      pages_qiun/components/data-progress/data-progress.vue
  81. 1117
      pages_qiun/components/data-table/senior-table.vue
  82. 218
      pages_qiun/components/drop-down/drop-down.vue
  83. 125
      pages_qiun/components/progress-bar/progress-bar.vue
  84. 93
      pages_qiun/components/ranking-list/ranking-list.vue
  85. 186
      pages_qiun/components/text-block/text-block.vue
  86. 600
      pages_qiun/components/uni-calendar/calendar.js
  87. 170
      pages_qiun/components/uni-calendar/uni-calendar-item.vue
  88. 512
      pages_qiun/components/uni-calendar/uni-calendar.vue
  89. 357
      pages_qiun/components/uni-calendar/util.js
  90. 134
      pages_qiun/components/wuc-tab/wuc-tab.vue
  91. 585
      pages_qiun/pages/finance/index.vue
  92. 348
      pages_qiun/pages/main/index.vue
  93. 259
      pages_qiun/pages/school/index.vue
  94. 762
      pages_qiun/pages/sport/index.vue
  95. 170
      pages_qiun/static/js/common.js
  96. 79
      pages_qiun/static/js/config.js
  97. 68
      pages_qiun/static/json/finance/1.json
  98. 33
      pages_qiun/static/json/finance/2.json
  99. 26
      pages_qiun/static/json/school/1.json
  100. 28
      pages_qiun/static/json/school/2.json

49
.gitignore

@ -0,0 +1,49 @@
# 忽略生成的文件
build/
dist/
unpackage/
*.class
*.jar
*.war
*.ear
# 忽略编辑器/IDE生成的文件和目录
.idea/
.vscode/
.hbuilderx
*.swp
*.swo
*~
# 忽略依赖管理工具生成的目录
node_modules/
bower_components/
vendor/
# 忽略操作系统文件
.DS_Store
Thumbs.db
# 忽略日志文件
*.log
# 忽略敏感或包含个人信息的文件(根据需要添加更多)
credentials.json
config.ini
secrets.txt
# 忽略其他自定义的文件或目录
/custom_directory/
# 排除特定扩展名的文件(根据需要添加更多)
*.bak
*.tmp
# 排除特定文件名(根据需要添加更多)
debug.log
# 不排除下列扩展名的文件
!*.allowed_extension
# 不排除下列文件名
!important_file.txt

19
App.vue

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

46
api/card.js

@ -0,0 +1,46 @@
import request from '@/utils/request'
// 用户绑定充值卡
export function userBindRechargeNum() {
return request({
url: '/app/card/userBindRechargeNum',
method: 'get'
})
}
// 获取充值卡信息
export function getRechargeNum() {
return request({
url: '/app/card/getRechargeNum',
method: 'get'
})
}
// 获取实名信息
export function getRealNameUrl() {
return request({
url: '/app/card/getRealNameUrl',
method: 'get'
})
}
// 获取分组套餐
export function getGroupPackage() {
return request({
url: '/app/card/getGroupPackage',
method: 'get'
})
}
// 套餐充值
export function recharge() {
return request({
url: '/app/card/recharge',
method: 'get'
})
}

66
api/login.js

@ -0,0 +1,66 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid, tenantId, grantType, clientId) {
const data = {
username,
password,
code,
uuid,
tenantId,
grantType,
clientId,
}
return request({
url: '/app/login',
headers: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
},
method: 'post',
data: data
})
}
// 注册方法
export function register(data) {
return request({
url: '/app/register',
headers: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
}
// 退出方法
export function logout() {
return request({
url: '/logout',
method: 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/auth/code',
headers: {
isToken: false
},
method: 'get',
timeout: 20000
})
}

31
api/oauth.js

@ -0,0 +1,31 @@
import request from '@/utils/request'
/**
* 微信登录
* @param {*} source pub miniapp
* @param {*} code
* @returns
*/
export function wxLogin(source,code) {
return request({
url: `/oauth/wx/login/${source}/${code}`,
headers: {
isToken: false
},
method: 'post',
})
}
/**
* 微信绑定
* @param {*} source 微信绑定
* @param {*} code
* @returns
*/
export function wxRegister(source,code) {
return request({
url: `/oauth/wx/register/${source}/${code}`,
headers: {
isToken: true
},
method: 'post',
})
}

52
api/system/dict/data.js

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询字典数据列表
export function listData(query) {
return request({
url: '/system/dict/data/list',
method: 'get',
params: query
})
}
// 查询字典数据详细
export function getData(dictCode) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'get'
})
}
// 根据字典类型查询字典数据信息
export function getDicts(dictType) {
return request({
url: '/system/dict/data/type/' + dictType,
method: 'get'
})
}
// 新增字典数据
export function addData(data) {
return request({
url: '/system/dict/data',
method: 'post',
data: data
})
}
// 修改字典数据
export function updateData(data) {
return request({
url: '/system/dict/data',
method: 'put',
data: data
})
}
// 删除字典数据
export function delData(dictCode) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'delete'
})
}

60
api/system/dict/type.js

@ -0,0 +1,60 @@
import request from '@/utils/request'
// 查询字典类型列表
export function listType(query) {
return request({
url: '/system/dict/type/list',
method: 'get',
params: query
})
}
// 查询字典类型详细
export function getType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'get'
})
}
// 新增字典类型
export function addType(data) {
return request({
url: '/system/dict/type',
method: 'post',
data: data
})
}
// 修改字典类型
export function updateType(data) {
return request({
url: '/system/dict/type',
method: 'put',
data: data
})
}
// 删除字典类型
export function delType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'delete'
})
}
// 刷新字典缓存
export function refreshCache() {
return request({
url: '/system/dict/type/refreshCache',
method: 'delete'
})
}
// 获取字典选择框列表
export function optionselect() {
return request({
url: '/system/dict/type/optionselect',
method: 'get'
})
}

41
api/system/user.js

@ -0,0 +1,41 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
params: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return upload({
url: '/system/user/profile/avatar',
name: data.name,
filePath: data.filePath
})
}

90
components/geek-xd/components/geek-certificate/geek-certificate.vue

@ -0,0 +1,90 @@
<template>
<view class="upload">
<view class="imagebox">
<view class="imageborder">
<view class="main">
<slot></slot>
</view>
</view>
</view>
<view class="text">
<text>{{ text }}</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const text = ref("")
</script>
<style scoped lang="scss">
.upload {
height: 400rpx;
width: 90%;
border-radius: 20rpx;
overflow: hidden;
.imagebox {
height: 80%;
background-color: #eff8ff;
align-items: center;
justify-content: center;
display: flex;
.imageborder {
border: 5px #319fea solid;
position: relative;
width: 70%;
height: 80%;
border-radius: 30rpx;
&::after {
position: absolute;
content: ' ';
background-color: #eff8ff;
height: 80%;
width: 120%;
top: 10%;
left: -10%;
}
&::before {
position: absolute;
content: ' ';
background-color: #eff8ff;
top: -10%;
left: 10%;
height: 120%;
width: 80%;
}
.main {
position: absolute;
background-color: #eff8ff;
top: 5%;
left: 5%;
height: 90%;
width: 90%;
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
}
}
}
.text {
height: 20%;
background-color: #319fea;
display: flex;
justify-content: center;
align-items: center;
text {
color: #ffffff;
}
}
}
</style>

681
components/geek-xd/components/geek-color-picker/geek-color-picker.vue

@ -0,0 +1,681 @@
<template>
<view v-show="show" class="t-wrapper" @touchmove.stop.prevent="moveHandle">
<view class="t-mask" :class="{ active: active }" @click.stop="close"></view>
<view class="t-box" :class="{ active: active }">
<view class="t-header">
<view class="t-header-button" @click="close">取消</view>
<view class="t-header-button confrim" @click="confirm">确认</view>
</view>
<view class="t-color__box"
:style="{ background: 'rgb(' + bgcolor.r + ',' + bgcolor.g + ',' + bgcolor.b + ')' }">
<view class="t-background boxs" @touchstart="touchstart($event, 0)" @touchmove="touchmove($event, 0)"
@touchend="touchend($event, 0)">
<view class="t-color-mask"></view>
<view class="t-pointer" :style="{ top: site[0].top - 8 + 'px', left: site[0].left - 8 + 'px' }"></view>
</view>
</view>
<view class="t-control__box">
<view class="t-control__color">
<view class="t-control__color-content"
:style="{ background: 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + rgba.a + ')' }"></view>
</view>
<view class="t-control-box__item">
<view class="t-controller boxs" @touchstart="touchstart($event, 1)" @touchmove="touchmove($event, 1)"
@touchend="touchend($event, 1)">
<view class="t-hue">
<view class="t-circle" :style="{ left: site[1].left - 12 + 'px' }"></view>
</view>
</view>
<view class="t-controller boxs" @touchstart="touchstart($event, 2)" @touchmove="touchmove($event, 2)"
@touchend="touchend($event, 2)">
<view class="t-transparency">
<view class="t-circle" :style="{ left: site[2].left - 12 + 'px' }"></view>
</view>
</view>
</view>
</view>
<view class="t-result__box">
<view v-if="mode" class="t-result__item">
<view class="t-result__box-input">{{ hex }}</view>
<view class="t-result__box-text">HEX</view>
</view>
<template v-else>
<view class="t-result__item">
<view class="t-result__box-input">{{ rgba.r }}</view>
<view class="t-result__box-text">R</view>
</view>
<view class="t-result__item">
<view class="t-result__box-input">{{ rgba.g }}</view>
<view class="t-result__box-text">G</view>
</view>
<view class="t-result__item">
<view class="t-result__box-input">{{ rgba.b }}</view>
<view class="t-result__box-text">B</view>
</view>
<view class="t-result__item">
<view class="t-result__box-input">{{ rgba.a }}</view>
<view class="t-result__box-text">A</view>
</view>
</template>
<view class="t-result__item t-select" @click="select">
<view class="t-result__box-input">
<view>切换</view>
<view>模式</view>
</view>
</view>
</view>
<view class="t-alternative">
<view class="t-alternative__item" v-for="(item, index) in colorList" :key="index">
<view class="t-alternative__item-content"
:style="{ background: 'rgba(' + item.r + ',' + item.g + ',' + item.b + ',' + item.a + ')' }"
@click="selectColor(item)">
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
color: {
type: Object,
default() {
return { r: 0, g: 0, b: 0, a: 0 }
}
},
spareColor: {
type: Array,
default() {
return []
}
}
},
data() {
return {
show: false,
active: false,
// rgba
rgba: { r: 0, g: 0, b: 0, a: 1 },
// hsb
hsb: { h: 0, s: 0, b: 0 },
site: [{ top: 0, left: 0 }, { left: 0 }, { left: 0 }],
index: 0,
bgcolor: { r: 255, g: 0, b: 0, a: 1 },
hex: '#000000',
mode: true,
colorList: [
{ r: 244, g: 67, b: 54, a: 1 },
{ r: 233, g: 30, b: 99, a: 1 },
{ r: 156, g: 39, b: 176, a: 1 },
{ r: 103, g: 58, b: 183, a: 1 },
{ r: 63, g: 81, b: 181, a: 1 },
{ r: 33, g: 150, b: 243, a: 1 },
{ r: 3, g: 169, b: 244, a: 1 },
{ r: 0, g: 188, b: 212, a: 1 },
{ r: 0, g: 150, b: 136, a: 1 },
{ r: 76, g: 175, b: 80, a: 1 },
{ r: 139, g: 195, b: 74, a: 1 },
{ r: 205, g: 220, b: 57, a: 1 },
{ r: 255, g: 235, b: 59, a: 1 },
{ r: 255, g: 193, b: 7, a: 1 },
{ r: 255, g: 152, b: 0, a: 1 },
{ r: 255, g: 87, b: 34, a: 1 },
{ r: 121, g: 85, b: 72, a: 1 },
{ r: 158, g: 158, b: 158, a: 1 },
{ r: 0, g: 0, b: 0, a: 0.5 },
{ r: 0, g: 0, b: 0, a: 0 },
]
};
},
created() {
this.rgba = this.color;
if (this.spareColor.length !== 0) {
this.colorList = this.spareColor;
}
},
methods: {
/**
* 初始化
*/
init() {
// hsb
this.hsb = this.rgbToHex(this.rgba);
this.setValue(this.rgba);
},
moveHandle() { },
open() {
this.show = true;
this.$nextTick(() => {
this.init();
setTimeout(() => {
this.active = true;
setTimeout(() => {
this.getSelectorQuery();
}, 350)
}, 50)
})
},
close() {
this.active = false;
this.$nextTick(() => {
setTimeout(() => {
this.show = false;
}, 500)
})
},
confirm() {
this.close();
this.$emit('confirm', {
rgba: this.rgba,
hex: this.hex
})
},
//
select() {
this.mode = !this.mode
},
//
selectColor(item) {
this.setColorBySelect(item)
},
touchstart(e, index) {
const { pageX, pageY, clientX, clientY } = e.touches[0];
this.pageX = clientX;
this.pageY = clientY;
this.setPosition(this.pageX, this.pageY, index);
},
touchmove(e, index) {
const { pageX, pageY, clientX, clientY } = e.touches[0];
this.moveX = clientX;
this.moveY = clientY;
this.setPosition(this.moveX, this.moveY, index);
},
touchend(e, index) {
},
/**
* 设置位置
*/
setPosition(x, y, index) {
this.index = index;
const {
top,
left,
width,
height
} = this.position[index];
//
this.site[index].left = Math.max(0, Math.min(parseInt(x - left), width));
if (index === 0) {
this.site[index].top = Math.max(0, Math.min(parseInt(y - top), height));
//
this.hsb.s = parseInt((100 * this.site[index].left) / width);
this.hsb.b = parseInt(100 - (100 * this.site[index].top) / height);
this.setColor();
this.setValue(this.rgba);
} else {
this.setControl(index, this.site[index].left);
}
},
/**
* 设置 rgb 颜色
*/
setColor() {
const rgb = this.HSBToRGB(this.hsb);
this.rgba.r = rgb.r;
this.rgba.g = rgb.g;
this.rgba.b = rgb.b;
},
/**
* 设置二进制颜色
* @param {Object} rgb
*/
setValue(rgb) {
this.hex = '#' + this.rgbToHex(rgb);
},
setControl(index, x) {
const {
top,
left,
width,
height
} = this.position[index];
if (index === 1) {
this.hsb.h = parseInt((360 * x) / width);
this.bgcolor = this.HSBToRGB({
h: this.hsb.h,
s: 100,
b: 100
});
this.setColor()
} else {
this.rgba.a = (x / width).toFixed(1);
}
this.setValue(this.rgba);
},
/**
* rgb 二进制 hex
* @param {Object} rgb
*/
rgbToHex(rgb) {
let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)];
hex.map(function (str, i) {
if (str.length == 1) {
hex[i] = '0' + str;
}
});
return hex.join('');
},
setColorBySelect(getrgb) {
const {
r,
g,
b,
a
} = getrgb;
let rgb = {}
rgb = {
r: r ? parseInt(r) : 0,
g: g ? parseInt(g) : 0,
b: b ? parseInt(b) : 0,
a: a ? a : 0,
};
this.rgba = rgb;
this.hsb = this.rgbToHsb(rgb);
this.changeViewByHsb();
},
changeViewByHsb() {
const [a, b, c] = this.position;
this.site[0].left = parseInt(this.hsb.s * a.width / 100);
this.site[0].top = parseInt((100 - this.hsb.b) * a.height / 100);
this.setColor(this.hsb.h);
this.setValue(this.rgba);
this.bgcolor = this.HSBToRGB({
h: this.hsb.h,
s: 100,
b: 100
});
this.site[1].left = this.hsb.h / 360 * b.width;
this.site[2].left = this.rgba.a * c.width;
},
/**
* hsb rgb
* @param {Object} 颜色模式 H(hues)表示色相S(saturation)表示饱和度Bbrightness表示亮度
*/
HSBToRGB(hsb) {
let rgb = {};
let h = Math.round(hsb.h);
let s = Math.round((hsb.s * 255) / 100);
let v = Math.round((hsb.b * 255) / 100);
if (s == 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
let t1 = v;
let t2 = ((255 - s) * v) / 255;
let t3 = ((t1 - t2) * (h % 60)) / 60;
if (h == 360) h = 0;
if (h < 60) {
rgb.r = t1;
rgb.b = t2;
rgb.g = t2 + t3;
} else if (h < 120) {
rgb.g = t1;
rgb.b = t2;
rgb.r = t1 - t3;
} else if (h < 180) {
rgb.g = t1;
rgb.r = t2;
rgb.b = t2 + t3;
} else if (h < 240) {
rgb.b = t1;
rgb.r = t2;
rgb.g = t1 - t3;
} else if (h < 300) {
rgb.b = t1;
rgb.g = t2;
rgb.r = t2 + t3;
} else if (h < 360) {
rgb.r = t1;
rgb.g = t2;
rgb.b = t1 - t3;
} else {
rgb.r = 0;
rgb.g = 0;
rgb.b = 0;
}
}
return {
r: Math.round(rgb.r),
g: Math.round(rgb.g),
b: Math.round(rgb.b)
};
},
rgbToHsb(rgb) {
let hsb = {
h: 0,
s: 0,
b: 0
};
let min = Math.min(rgb.r, rgb.g, rgb.b);
let max = Math.max(rgb.r, rgb.g, rgb.b);
let delta = max - min;
hsb.b = max;
hsb.s = max != 0 ? 255 * delta / max : 0;
if (hsb.s != 0) {
if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta;
else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta;
else hsb.h = 4 + (rgb.r - rgb.g) / delta;
} else hsb.h = -1;
hsb.h *= 60;
if (hsb.h < 0) hsb.h = 0;
hsb.s *= 100 / 255;
hsb.b *= 100 / 255;
return hsb;
},
getSelectorQuery() {
const views = uni.createSelectorQuery().in(this);
views
.selectAll('.boxs')
.boundingClientRect(data => {
if (!data || data.length === 0) {
setTimeout(() => this.getSelectorQuery(), 20)
return
}
this.position = data;
// this.site[0].top = data[0].height;
// this.site[0].left = 0;
// this.site[1].left = data[1].width;
// this.site[2].left = data[2].width;
this.setColorBySelect(this.rgba);
})
.exec();
}
},
watch: {
spareColor(newVal) {
this.colorList = newVal;
}
}
};
</script>
<style lang="scss" scoped>
.t-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
z-index: 9999;
}
.t-box {
width: 100%;
position: absolute;
bottom: 0;
padding: 30upx 0;
padding-top: 0;
background: #fff;
transition: all 0.3s;
transform: translateY(100%);
&.active {
transform: translateY(0%);
}
}
.t-header {
display: flex;
justify-content: space-between;
width: 100%;
height: 100upx;
border-bottom: 1px #eee solid;
box-shadow: 1px 0 2px rgba(0, 0, 0, 0.1);
background: #fff;
}
.t-header-button {
display: flex;
align-items: center;
width: 150upx;
height: 100upx;
font-size: 30upx;
color: #666;
padding-left: 20upx;
&:last-child {
justify-content: flex-end;
padding-right: 20upx;
}
&.confrim {
color: #007AFF;
}
}
.t-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: -1;
transition: all 0.3s;
opacity: 0;
&.active {
opacity: 1;
}
}
.t-color__box {
position: relative;
height: 400upx;
background: rgb(255, 0, 0);
overflow: hidden;
box-sizing: border-box;
margin: 0 20upx;
margin-top: 20upx;
box-sizing: border-box;
}
.t-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
}
.t-color-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 400upx;
background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
}
.t-pointer {
position: absolute;
bottom: -8px;
left: -8px;
z-index: 2;
width: 15px;
height: 15px;
border: 1px #fff solid;
border-radius: 50%;
}
.t-show-color {
width: 100upx;
height: 50upx;
}
.t-control__box {
margin-top: 50upx;
width: 100%;
display: flex;
padding-left: 20upx;
box-sizing: border-box;
}
.t-control__color {
flex-shrink: 0;
width: 100upx;
height: 100upx;
border-radius: 50%;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36upx 36upx;
background-position: 0 0, 18upx 18upx;
border: 1px #eee solid;
overflow: hidden;
}
.t-control__color-content {
width: 100%;
height: 100%;
}
.t-control-box__item {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
padding: 0 30upx;
}
.t-controller {
position: relative;
width: 100%;
height: 16px;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 32upx 32upx;
background-position: 0 0, 16upx 16upx;
}
.t-hue {
width: 100%;
height: 100%;
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.t-transparency {
width: 100%;
height: 100%;
background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
}
.t-circle {
position: absolute;
top: -2px;
width: 20px;
height: 20px;
box-sizing: border-box;
border-radius: 50%;
background: #fff;
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
}
.t-result__box {
margin-top: 20upx;
padding: 10upx;
width: 100%;
display: flex;
box-sizing: border-box;
}
.t-result__item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10upx;
width: 100%;
box-sizing: border-box;
}
.t-result__box-input {
padding: 10upx 0;
width: 100%;
font-size: 28upx;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
color: #999;
text-align: center;
background: #fff;
}
.t-result__box-text {
margin-top: 10upx;
font-size: 28upx;
line-height: 2;
}
.t-select {
flex-shrink: 0;
width: 150upx;
padding: 0 30upx;
.t-result__box-input {
border-radius: 10upx;
border: none;
color: #999;
box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
background: #fff;
&:active {
box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.1);
}
}
}
.t-alternative {
display: flex;
flex-wrap: wrap;
width: 100%;
padding-right: 10upx;
box-sizing: border-box;
}
.t-alternative__item {
margin-left: 12upx;
margin-top: 10upx;
width: 50upx;
height: 50upx;
border-radius: 10upx;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36upx 36upx;
background-position: 0 0, 18upx 18upx;
border: 1px #eee solid;
overflow: hidden;
&:active {
transition: all 0.3s;
transform: scale(1.1);
}
}
.t-alternative__item-content {
width: 50upx;
height: 50upx;
background: rgba(255, 0, 0, 0.5);
}
</style>

123
components/geek-xd/components/geek-commodity/geek-commodity.vue

@ -0,0 +1,123 @@
<script setup>
const props = defineProps({
img: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
subTitle: {
type: String,
default: ''
},
price: {
type: Number,
default: 0
},
type: {
type: String,
default: 'line' // line, rect
}
})
</script>
<template>
<view class="card" :class="type" @click="$emit('click')">
<image class="img" :src="img" />
<view class="content">
<view class="title">{{ title }}</view>
<view class="subTitle">{{ subTitle }}</view>
<view class="price">{{ price }}</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.card {
padding: 0;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
height: 240rpx;
width: 700rpx;
padding: 20rpx;
margin: 10rpx;
position: relative;
.img {
height: 200rpx;
width: 200rpx;
}
}
.line {
display: flex;
.content {
height: 200rpx;
padding-left: 20rpx;
.title {
width: 400rpx;
font-size: 35rpx;
}
.subTitle {
width: 400rpx;
height: 90rpx;
margin-top: 10rpx;
font-size: 20rpx;
color: rgb(87, 87, 87);
}
.price {
font-size: 40rpx;
color: red;
width: 400rpx;
}
}
}
.rect {
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
height: 500rpx;
width: 350rpx;
padding: 0;
margin: 10rpx;
display: inline-block;
.img {
border-radius: 10px 10px 0 0;
height: 350rpx;
width: 350rpx;
}
.content {
padding: 0 20rpx;
margin: 0;
height: 140rpx;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
width: 330rpx;
font-size: 25rpx;
}
.subTitle {
width: 330rpx;
height: 60rpx;
font-size: 20rpx;
color: rgb(87, 87, 87);
}
.price {
font-size: 30rpx;
color: red;
width: 100%;
}
}
}
</style>

72
components/geek-xd/components/geek-menu/geek-menu.vue

@ -0,0 +1,72 @@
<script setup>
import { computed } from 'vue';
const props = defineProps({
icon: {
type: String,
default: ''
},
size: {
type: Number,
default: 80
},
label: {
type: String,
default: "菜单"
},
labelColor: {
type: String,
default: '#515151'
},
type: {
type: String,
default: 'circle'
}
})
const menuStyle = computed(() => {
return {
width: `${props.size + 40}rpx`,
height: `${props.size + 40}rpx`
}
})
const titleStype = computed(() => {
return {
width: `${props.size + 40}rpx`,
color: props.labelColor
}
})
</script>
<template>
<view class="menu" :class="type" :style="menuStyle" @click="$emit('click')">
<image :src="icon" style="width: 100%;height: 100%"></image>
</view>
<view class="title" :style="titleStype">{{ label }}</view>
</template>
<style lang="scss" scoped>
.menu {
padding: 20rpx;
}
.circle {
padding: 20rpx;
border-radius: 100%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
&:active {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
}
}
.rect {
padding: 15rpx;
margin-bottom: -15rpx;
&:active {
opacity: 0.5;
}
}
.title {
text-align: center;
}
</style>

221
components/geek-xd/components/geek-order/geek-order.vue

@ -0,0 +1,221 @@
<template>
<view class="geek-card" @click="$emit('click')">
<view class="geek-header">
<view class="geek-shop">{{ shop }} > </view>
<view class="geek-status">{{ status }}</view>
</view>
<view class="geek-content">
<image class="geek-img" :src="img"></image>
<view class="geek-label">{{ label }}</view>
<view class="geek-sum">
<view class="geek-price">
<view class="geek-sum-1">{{ number.integerPart }}</view>
<view class="geek-sum-2">. {{ number.decimalPart }}</view>
</view>
<view class="geek-sum-3"> {{ num }} </view>
</view>
</view>
<view class="geek-footer">
<view class="geek-more" @click="$emit('more')">更多</view>
<view class="geek-buttonGroup">
<view class="geek-btn" @click="$emit('sell')">卖了换钱</view>
<view class="geek-btn" @click="$emit('return')">退换/售后</view>
<view class="geek-buy" @click="$emit('again')">再次购买</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
shop: {
type: String,
default: ''
},
status: {
type: String,
default: ''
},
img: {
type: String,
default: ''
},
label: {
type: String,
default: ''
},
price: {
type: Number,
default: 0
},
num: {
type: Number,
default: 0
},
type: {
type: String,
default: 'line'
}
})
const number = computed(() => {
return formatNumber(props.price, 2)
})
function formatNumber(num, place) {
let fixedNum = Number(num).toFixed(place); //
let parts = fixedNum.split('.'); //
let integerPart = parts[0]; //
let decimalPart = parts[1]; //
// 使padStart0
decimalPart = decimalPart.padStart(place, '0');
return {
integerPart, decimalPart
}
}
</script>
<style lang="scss" scoped>
.geek-card {
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
padding: 20rpx;
background-color: white;
border: 1rpx solid rgb(183, 183, 183);
border-radius: 20rpx;
height: 360rpx;
width: 700rpx;
margin: 25rpx;
.geek-header {
display: flex;
justify-content: space-between;
height: 60rpx;
width: 100%;
margin-bottom: 6rpx;
.geek-shop {
font-size: 28rpx;
font-weight: 600;
}
.geek-status {
width: 100rpx;
text-align: center;
opacity: 0.5;
font-size: 25rpx;
text-align: end;
}
}
.geek-content {
position: relative;
height: auto;
width: 664rpx;
.geek-img {
border-radius: 30rpx;
height: 170rpx;
width: 170rpx;
display: inline-block;
}
.geek-label {
position: absolute;
top: 40rpx;
left: 178rpx;
width: 350rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.geek-sum {
position: absolute;
top: 44rpx;
right: 20rpx;
width: 150rpx;
height: 84rpx;
.geek-price {
display: flex;
justify-content: flex-end;
font-weight: bold;
.geek-sum-1 {
font-size: 32rpx;
}
.geek-sum-2 {
padding-top: 20rpx;
font-size: 20rpx;
}
}
.geek-sum-3 {
font-size: 20rpx;
text-align: end;
}
}
}
.geek-footer {
display: flex;
justify-content: space-between;
height: 60rpx;
width: 100%;
font-size: 25rpx;
.geek-more {
height: 60rpx;
margin-right: 110rpx;
text-align: center;
line-height: 60rpx;
display: inline-block;
}
.geek-buttonGroup {
height: 60rpx;
display: inline-block;
.geek-btn {
border: 1rpx solid #E9E9E9;
width: 140rpx;
height: 60rpx;
border-radius: 80rpx;
opacity: 0.8;
padding: 10rpx;
margin-right: 10rpx;
text-align: center;
display: inline-block;
}
.geek-buy {
width: 140rpx;
height: 60rpx;
border-radius: 80rpx;
opacity: 0.8;
padding: 10rpx;
text-align: center;
display: inline-block;
color: #F25E53;
border: 1rpx solid #F4DADA;
}
}
}
}
</style>

90
components/geek-xd/components/geek-qrcode/README.md

@ -0,0 +1,90 @@
# uni-app 二维码生成器
改自作者诗小柒的tki-qrcode二维码生成器
### 作者:董玉可
1. H5、微信小程序、支付宝小程序、APP,其它平台的小程序没有测试
2. 使用canvas生成
3. 可设置二维码背景色,前景色,角标色
4. 可设置二维码logo
## 重要的事情说3遍 重要的事情说3遍 重要的事情说3遍
1. IOS、Android真机都可以正常生成二维码
2. 使用的时候出现无法生成二维码或空白的请先github直接打包下载,问题依旧,请github上直接提出问题并配图
3. 有问题请说明问题原因,这样我才好定位,否则我也无法解决
4. 如果此插件有帮助到你请打5分或赞赏我,你的支持是我更新的动力
+ 图片1 是微信小程序真机实测
+ 图片2 是微信小程序模拟实测
+ 图片3 是支付宝小程序模拟器实测
+ 图片4 是安卓真机实测
+ 图片5 H5
### 使用方法
`template` 中使用
```javascript
<view class="qrimg">
<geek-qrcode
ref="qrcode"
:cid="cid"
:val="val"
:size="size"
:unit="unit"
:background="background"
:foreground="foreground"
:pdground="pdground"
:icon="icon"
:iconSize="iconsize"
:lv="lv"
:onval="onval"
:loadMake="loadMake"
:usingComponents="usingComponents"
:showLoading="showLoading"
:loadingText="loadingText"
@result="qrR" />
</view>
```
### 属性
| 属性名 | 类型 | 默认值 | 可选值 | 说明 |
| :-------------- | :-----: | :---------------: | :----: | :-------------------------------------------------------------------------------------------------- |
| cid | String | tki-qrcode-canvas | | canvasId,页面存在多个二维码组件时需设置不同的ID |
| size | Number | 200 | | 生成的二维码大小 |
| unit | String | upx | px | 大小单位尺寸 |
| show | Boolean | true | | 默认使用组件中的image标签显示二维码 |
| val | String | 二维码 | | 要生成的内容 |
| background | String | #000000 | | 二维码背景色 |
| foreground | String | #ffffff | | 二维码前景色 |
| pdground | String | #ffffff | | 二维码角标色 |
| icon | String | | | 二维码图标URL(必须是本地图片,网络图需要先下载至本地) |
| iconSize | Number | 40 | | 二维码图标大小(注意此大小不会跟随二维码size 动态变化,设置时需要注意大小,不要太大,以免无法识别) |
| lv | Number | 3 | | 容错级别(一般不用设置) |
| onval | Boolean | false | | 监听val值变化自动重新生成二维码 |
| loadMake | Boolean | false | | 组件初始化完成后自动生成二维码,val需要有值 |
| usingComponents | Boolean | true | false | 是否使用了自定义组件模式(主要是为了修复非自定义组件模式时 v-if 无法生成二维码的问题) |
| showLoading | Boolean | true | false | 是否显示loading |
| loadingText | String | 二维码生成中 | | loading文字 |
### 方法
| 方法名 | 参数 | 默认值 | 说明 |
| :----------- | :--: | :----: | :-------------------------------------------------- |
| _makeCode() | | | 生成二维码 |
| _clearCode() | | | 清空二维码(清空二维码会触发result回调 返回值为空) |
| _saveCode() | | | 保存二维码到图库 |
### 事件
| 事件名 | 返回值 | 说明 |
| :----- | :----------------------------: | --------------------------------------: |
| result | 生成的图片base64或图片临时地址 | 返回二维码路径 注:_clearCode()后返回空 |
### 感谢
[uni-app](https://uniapp.dcloud.io/ "uni-app")
[qrcode](https://github.com/aralejs/qrcode "qrcode")

205
components/geek-xd/components/geek-qrcode/geek-qrcode.vue

@ -0,0 +1,205 @@
<template xlang="wxml" minapp="mpvue">
<view class="geek-qrcode">
<canvas class="geek-qrcode-canvas" :canvas-id="cid" :style="{width:cpSize+'px',height:cpSize+'px'}" />
<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
</view>
</template>
<script>
import QRCode from "./qrcode.js"
let qrcode
export default {
name: "geek-qrcode",
props: {
cid: {
type: String,
default: 'geek-qrcode-canvas'
},
size: {
type: Number,
default: 200
},
unit: {
type: String,
default: 'upx'
},
show: {
type: Boolean,
default: true
},
val: {
type: String,
default: ''
},
background: {
type: String,
default: '#ffffff'
},
foreground: {
type: String,
default: '#000000'
},
pdground: {
type: String,
default: '#000000'
},
icon: {
type: String,
default: ''
},
iconSize: {
type: Number,
default: 40
},
lv: {
type: Number,
default: 3
},
onval: {
type: Boolean,
default: false
},
loadMake: {
type: Boolean,
default: false
},
usingComponents: {
type: Boolean,
default: true
},
showLoading: {
type: Boolean,
default: true
},
loadingText: {
type: String,
default: '二维码生成中'
},
},
data() {
return {
result: '',
}
},
methods: {
_makeCode() {
let that = this
if (!this._empty(this.val)) {
qrcode = new QRCode({
context: that, //
canvasId:that.cid, // canvas-id
usingComponents: that.usingComponents, //
showLoading: that.showLoading, // loading
loadingText: that.loadingText, // loading
text: that.val, //
size: that.cpSize, //
background: that.background, //
foreground: that.foreground, //
pdground: that.pdground, //
correctLevel: that.lv, //
image: that.icon, //
imageSize: that.iconSize,//
cbResult: function (res) { //
that._result(res)
},
});
} else {
uni.showToast({
title: '二维码内容不能为空',
icon: 'none',
duration: 2000
});
}
},
_clearCode() {
this._result('')
qrcode.clear()
},
_saveCode() {
let that = this;
if (this.result != "") {
uni.saveImageToPhotosAlbum({
filePath: that.result,
success: function () {
uni.showToast({
title: '二维码保存成功',
icon: 'success',
duration: 2000
});
}
});
}
},
_result(res) {
this.result = res;
this.$emit('result', res)
},
_empty(v) {
let tp = typeof v,
rt = false;
if (tp == "number" && String(v) == "") {
rt = true
} else if (tp == "undefined") {
rt = true
} else if (tp == "object") {
if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
} else if (tp == "string") {
if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
} else if (tp == "function") {
rt = false
}
return rt
}
},
watch: {
size: function (n, o) {
if (n != o && !this._empty(n)) {
this.cSize = n
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 100);
}
}
},
val: function (n, o) {
if (this.onval) {
if (n != o && !this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
}
},
computed: {
cpSize() {
if(this.unit == "upx"){
return uni.upx2px(this.size)
}else{
return this.size
}
}
},
mounted: function () {
if (this.loadMake) {
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
}
</script>
<style>
.geek-qrcode {
position: relative;
}
.geek-qrcode-canvas {
position: fixed;
top: -99999upx;
left: -99999upx;
z-index: -99999;
}
</style>

1206
components/geek-xd/components/geek-qrcode/qrcode.js

File diff suppressed because it is too large

84
components/geek-xd/components/geek-statistic/geek-statistic.vue

@ -0,0 +1,84 @@
<template>
<view :style="labelStyle" class="title">{{ label }}</view>
<view :style="numberStyle" class="number">{{ formatNumber(number,props.place) }}</view>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
label: {
type: String,
default: "订单数量"
},
width: {
type: Number,
default: 300
},
labelColor: {
type: String,
default: '#white'
},
labelSize: {
type: Number,
default: 16
},
number: {
type: Number,
default: 80
},
numberColor: {
type: String,
default: 'red'
},
numberSize: {
type: Number,
default: 20
},
place: {
type: Number,
default: 2
}
})
const labelStyle = computed(() => {
return {
width: `${props.width}rpx`,
color: props.labelColor,
fontSize: `${props.labelSize}px`
}
})
const numberStyle = computed(() => {
return {
width: `${props.width}rpx`,
color: props.numberColor,
fontSize: `${props.numberSize}px`
}
})
function formatNumber(num,place) {
let fixedNum = Number(num).toFixed(place); //
let parts = fixedNum.split('.'); //
let integerPart = parts[0]; //
let decimalPart = parts[1]; //
// 使padStart0
decimalPart = decimalPart.padStart(place, '0');
return integerPart + '.' + decimalPart;
}
</script>
<style lang="scss" scoped>
.title {
text-align: center;
}
.number {
text-align: center;
}
</style>

18
components/geek-xd/types/index.ts

@ -0,0 +1,18 @@
export interface Menu {
icon: string,
label: string
}
export interface Commodity {
img: string,
title: string,
subTitle?: string,
price: number
}
export interface CommodityOrder extends Commodity {
shop: string,
status: string,
num: number,
label?:string
}

320
components/qiun-data-charts/changelog.md

@ -0,0 +1,320 @@
## 2.5.0-20230101(2023-01-01)
- 秋云图表组件 修改条件编译顺序,确保uniapp的cli方式的项目依赖不完整时可以正常显示
- 秋云图表组件 恢复props属性directory的使用,以修复vue3项目中,开启echarts后,echarts目录识别错误的bug
- uCharts.js 修复区域图、混合图只有一个数据时图表显示不正确的bug
- uCharts.js 修复折线图、区域图中时间轴类别图表tooltip指示点显示不正确的bug
- uCharts.js 修复x轴使用labelCount时,并且boundaryGap = 'justify' 并且关闭Y轴显示的时候,最后一个坐标值不显示的bug
- uCharts.js 修复折线图只有一组数据时 ios16 渲染颜色不正确的bug
- uCharts.js 修复玫瑰图半径显示不正确的bug
- uCharts.js 柱状图、山峰图增加正负图功能,y轴网格如果需要显示0轴则由 min max 及 splitNumber 确定,后续版本优化自动显示0轴
- uCharts.js 柱状图column增加 opts.extra.column.labelPosition,数据标签位置,有效值为 outside外部, insideTop内顶部, center内中间, bottom内底部
- uCharts.js 雷达图radar增加 opts.extra.radar.labelShow,否显示各项标识文案是,默认true
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.boxPadding,提示窗边框填充距离,默认3px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.fontSize,提示窗字体大小配置,默认13px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.lineHeight,提示窗文字行高,默认20px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShow,是否显示左侧图例,默认true
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShape,图例形状,图例标识样式,有效值为 auto自动跟随图例, diamond◆, circle●, triangle▲, square■, rect▬, line-
- uCharts.js 标记线markLine增加 opts.extra.markLine.labelFontSize,字体大小配置,默认13px
- uCharts.js 标记线markLine增加 opts.extra.markLine.labelPadding,标签边框内填充距离,默认6px
- uCharts.js 折线图line增加 opts.extra.line.linearType,渐变色类型,可选值 none关闭渐变色,custom 自定义渐变色。使用自定义渐变色时请赋值serie.linearColor作为颜色值
- uCharts.js 折线图line增加 serie.linearColor,渐变色数组,格式为2维数组[起始位置,颜色值],例如[[0,'#0EE2F8'],[0.3,'#2BDCA8'],[0.6,'#1890FF'],[1,'#9A60B4']]
- uCharts.js 折线图line增加 opts.extra.line.onShadow,是否开启折线阴影,开启后请赋值serie.setShadow阴影设置
- uCharts.js 折线图line增加 serie.setShadow,阴影配置,格式为4位数组:[offsetX,offsetY,blur,color]
- uCharts.js 折线图line增加 opts.extra.line.animation,动画效果方向,可选值为vertical 垂直动画效果,horizontal 水平动画效果
- uCharts.js X轴xAxis增加 opts.xAxis.lineHeight,X轴字体行高,默认20px
- uCharts.js X轴xAxis增加 opts.xAxis.marginTop,X轴文字距离轴线的距离,默认0px
- uCharts.js X轴xAxis增加 opts.xAxis.title,当前X轴标题
- uCharts.js X轴xAxis增加 opts.xAxis.titleFontSize,标题字体大小,默认13px
- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetY,标题纵向偏移距离,负数为向上偏移,正数向下偏移
- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetX,标题横向偏移距离,负数为向左偏移,正数向右偏移
- uCharts.js X轴xAxis增加 opts.xAxis.titleFontColor,标题字体颜色,默认#666666
## 报错TypeError: Cannot read properties of undefined (reading 'length')
- 如果是uni-modules版本组件,请先登录HBuilderX账号;
- 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
- 如果是cli项目请使用码云上的非uniCloud版本组件;
- 或者添加uniCloud的依赖;
- 或者使用原生uCharts;
## 2.4.5-20221130(2022-11-30)
- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
- uCharts.js 折线图修复特殊情况下只有单点数据,并改变线宽后点变为圆形的bug
- uCharts.js 修复Y轴disabled启用后无效并报错的bug
- uCharts.js 修复仪表盘起始结束角度特殊情况下显示不正确的bug
- uCharts.js 雷达图新增参数 opts.extra.radar.radius , 自定义雷达图半径
- uCharts.js 折线图、区域图增加tooltip指示点,opts.extra.line.activeType/opts.extra.area.activeType,可选值"none"不启用激活指示点,"hollow"空心点模式,"solid"实心点模式
## 2.4.4-20221102(2022-11-02)
- 秋云图表组件 修复使用echarts时reload、reshow无法调用重新渲染的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/40)
- 秋云图表组件 修复使用echarts时,初始化时宽高不正确的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/42)
- 秋云图表组件 修复uniapp的h5使用history模式时,无法加载echarts的bug
- 秋云图表组件 小程序端@complete、@scrollLeft、@scrollRight、@getTouchStart、@getTouchMove、@getTouchEnd事件增加opts参数传出,方便一些特殊需求的交互获取数据。
- uCharts.js 修复calTooltipYAxisData方法内formatter格式化方法未与y轴方法同步的问题,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/43)
- uCharts.js 地图新增参数opts.series[i].fillOpacity,以透明度方式来设置颜色过度效果,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/38)
- uCharts.js 地图新增参数opts.extra.map.active,是否启用点击激活变色
- uCharts.js 地图新增参数opts.extra.map.activeTextColor,是否启用点击激活变色
- uCharts.js 地图新增渲染完成事件renderComplete
- uCharts.js 漏斗图修复当部分数据相同时tooltip提示窗点击错误的bug
- uCharts.js 漏斗图新增参数series.data[i].centerText 居中标签文案
- uCharts.js 漏斗图新增参数series.data[i].centerTextSize 居中标签文案字体大小,默认opts.fontSize
- uCharts.js 漏斗图新增参数series.data[i].centerTextColor 居中标签文案字体颜色,默认#FFFFFF
- uCharts.js 漏斗图新增参数opts.extra.funnel.minSize 最小值的最小宽度,默认0
- uCharts.js 进度条新增参数opts.extra.arcbar.direction,动画方向,可选值为cw顺时针、ccw逆时针
- uCharts.js 混合图新增参数opts.extra.mix.line.width,折线的宽度,默认2
- uCharts.js 修复tooltip开启horizentalLine水平横线标注时,图表显示错位的bug
- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
- uCharts.js 修复开启滚动条后X轴文字超出绘图区域后的隐藏逻辑
- uCharts.js 柱状图、条状图修复堆叠模式不能通过{value,color}赋值单个柱子颜色的问题
- uCharts.js 气泡图修复不识别series.textSize和series.textColor的bug
## 报错TypeError: Cannot read properties of undefined (reading 'length')
1. 如果是uni-modules版本组件,请先登录HBuilderX账号;
2. 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
3. 如果是cli项目请使用码云上的非uniCloud版本组件;
4. 或者添加uniCloud的依赖;
5. 或者使用原生uCharts;
## 2.4.3-20220505(2022-05-05)
- 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时,再次赋值后画布闪动的bug
- 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug
- uCharts.js 雷达图新增参数opts.extra.radar.gridEval,数据点位网格抽希,默认1
- uCharts.js 雷达图新增参数opts.extra.radar.axisLabel, 是否显示刻度点值,默认false
- uCharts.js 雷达图新增参数opts.extra.radar.axisLabelTofix,刻度点值小数位数,默认0
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointShow,是否显示末端刻度圆点,默认false
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointRadius,刻度圆点的半径,默认3
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointColor,刻度圆点的颜色,默认#cccccc
- uCharts.js 雷达图新增参数opts.extra.radar.linearType,渐变色类型,可选值"none"关闭渐变,"custom"开启渐变
- uCharts.js 雷达图新增参数opts.extra.radar.customColor,自定义渐变颜色,数组类型对应series的数组长度以匹配不同series颜色的不同配色方案,例如["#FA7D8D", "#EB88E2"]
- uCharts.js 雷达图优化支持series.textColor、series.textSize属性
- uCharts.js 柱状图中温度计式图标,优化支持全圆角类型,修复边框有缝隙的bug,详见官网【演示】中的温度计图表
- uCharts.js 柱状图新增参数opts.extra.column.activeWidth,当前点击柱状图的背景宽度,默认一个单元格单位
- uCharts.js 混合图增加opts.extra.mix.area.gradient 区域图是否开启渐变色
- uCharts.js 混合图增加opts.extra.mix.area.opacity 区域图透明度,默认0.2
- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelText,自定义标签文字,避免formatter格式化的繁琐,详见官网【演示】中的饼图
- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelShow,自定义是否显示某一个指示标签,避免因饼图类别太多导致标签重复或者居多导致图形变形的问题,详见官网【演示】中的饼图
- uCharts.js 增加opts.series[i].legendText/opts.series[0].data[i].legendText(与series.name同级)自定义图例显示文字的方法
- uCharts.js 优化X轴、Y轴formatter格式化方法增加形参,统一为fromatter:function(value,index,opts){}
- uCharts.js 修复横屏模式下无法使用双指缩放方法的bug
- uCharts.js 修复当只有一条数据或者多条数据值相等的时候Y轴自动计算的最大值错误的bug
- 【官网模板】增加外部自定义图例与图表交互的例子,[点击跳转](https://www.ucharts.cn/v2/#/layout/info?id=2)
## 注意:非unimodules 版本如因更新 hbx 至 3.4.7 导致报错如下,请到码云更新非 unimodules 版本组件,[点击跳转](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)
> Error in callback for immediate watcher "uchartsOpts": "SyntaxError: Unexpected token u in JSON at position 0"
## 2.4.2-20220421(2022-04-21)
- 秋云图表组件 修复HBX升级3.4.6.20220420版本后echarts报错的问题
## 2.4.2-20220420(2022-04-20)
## 重要!此版本uCharts新增了很多功能,修复了诸多已知问题
- 秋云图表组件 新增onzoom开启双指缩放功能(仅uCharts),前提需要直角坐标系类图表类型,并且ontouch为true、opts.enableScroll为true,详见实例项目K线图
- 秋云图表组件 新增optsWatch是否监听opts变化,关闭optsWatch后,动态修改opts不会触发图表重绘
- 秋云图表组件 修复开启canvas2d功能后,动态更新数据后画布闪动的bug
- 秋云图表组件 去除directory属性,改为自动获取echarts.min.js路径(升级不受影响)
- 秋云图表组件 增加getImage()方法及@getImage事件,通过ref调用getImage()方法获,触发@getImage事件获取当前画布的base64图片文件流。
- 秋云图表组件 支付宝、字节跳动、飞书、快手小程序支持开启canvas2d同层渲染设置。
- 秋云图表组件 新增加【非uniCloud】版本组件,避免有些不需要uniCloud的使用组件发布至小程序需要提交隐私声明问题,请到码云[【非uniCloud版本】](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6),或npm[【非uniCloud版本】](https://www.npmjs.com/package/@qiun/uni-ucharts)下载使用。
- uCharts.js 新增dobuleZoom双指缩放功能
- uCharts.js 新增山峰图type="mount",数据格式为饼图类格式,不需要传入categories,具体详见新版官网在线演示
- uCharts.js 修复折线图当数据中存在null时tooltip报错的bug
- uCharts.js 修复饼图类当画布比较小时自动计算的半径是负数报错的bug
- uCharts.js 统一各图表类型的series.formatter格式化方法的形参为(val, index, series, opts),方便格式化时有更多参数可用
- uCharts.js 标记线功能增加labelText自定义显示文字,增加labelAlign标签显示位置(左侧或右侧),增加标签显示位置微调labelOffsetX、labelOffsetY
- uCharts.js 修复条状图当数值很小时开启圆角后样式错误的bug
- uCharts.js 修复X轴开启disabled后,X轴仍占用空间的bug
- uCharts.js 修复X轴开启滚动条并且开启rotateLabel后,X轴文字与滚动条重叠的bug
- uCharts.js 增加X轴rotateAngle文字旋转自定义角度,取值范围(-90至90)
- uCharts.js 修复地图文字标签层级显示不正确的bug
- uCharts.js 修复饼图、圆环图、玫瑰图当数据全部为0的时候不显示数据标签的bug
- uCharts.js 修复当opts.padding上边距为0时,Y轴顶部刻度标签位置不正确的bug
## 另外我们还开发了各大原生小程序组件,已发布至码云和npm
[https://gitee.com/uCharts/uCharts](https://gitee.com/uCharts/uCharts)
[https://www.npmjs.com/~qiun](https://www.npmjs.com/~qiun)
## 对于原生uCharts文档我们已上线新版官方网站,详情点击下面链接进入官网
[https://www.uCharts.cn/v2/](https://www.ucharts.cn/v2/)
## 2.3.7-20220122(2022-01-22)
## 重要!使用vue3编译,请使用cli模式并升级至最新依赖,HbuilderX编译需要使用3.3.8以上版本
- uCharts.js 修复uni-app平台组件模式使用vue3编译到小程序报错的bug。
## 2.3.7-20220118(2022-01-18)
## 注意,使用vue3的前提是需要3.3.8.20220114-alpha版本的HBuilder!
## 2.3.67-20220118(2022-01-18)
- 秋云图表组件 组件初步支持vue3,全端编译会有些问题,具体详见下面修改:
1. 小程序端运行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new uni_modules_qiunDataCharts_js_sdk_uCharts_uCharts.uCharts,将.uCharts去掉。
2. 小程序端发行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new e.uCharts,将.uCharts去掉,变为 new e。
3. 如果觉得上述步骤比较麻烦,如果您的项目只编译到小程序端,可以修改u-charts.js最后一行导出方式,将 export default uCharts;变更为 export default { uCharts: uCharts }; 这样变更后,H5和App端的renderjs会有问题,请开发者自行选择。(此问题非组件问题,请等待DC官方修复Vue3的小程序端)
## 2.3.6-20220111(2022-01-11)
- 秋云图表组件 修改组件 props 属性中的 background 默认值为 rgba(0,0,0,0)
## 2.3.6-20211201(2021-12-01)
- uCharts.js 修复bar条状图开启圆角模式时,值很小时圆角渲染错误的bug
## 2.3.5-20211014(2021-10-15)
- uCharts.js 增加vue3的编译支持(仅原生uCharts,qiun-data-charts组件后续会支持,请关注更新)
## 2.3.4-20211012(2021-10-12)
- 秋云图表组件 修复 mac os x 系统 mouseover 事件丢失的 bug
## 2.3.3-20210706(2021-07-06)
- uCharts.js 增加雷达图开启数据点值(opts.dataLabel)的显示
## 2.3.2-20210627(2021-06-27)
- 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
## 2.3.1-20210616(2021-06-16)
- uCharts.js 修复圆角柱状图使用4角圆角时,当数值过大时不正确的bug
## 2.3.0-20210612(2021-06-12)
- uCharts.js 【重要】uCharts增加nvue兼容,可在nvue项目中使用gcanvas组件渲染uCharts,[详见码云uCharts-demo-nvue](https://gitee.com/uCharts/uCharts)
- 秋云图表组件 增加tapLegend属性,是否开启图例点击交互事件
- 秋云图表组件 getIndex事件中增加返回uCharts实例中的opts参数,以便在页面中调用参数
- 示例项目 pages/other/other.vue增加app端自定义tooltip的方法,详见showOptsTooltip方法
## 2.2.1-20210603(2021-06-03)
- uCharts.js 修复饼图、圆环图、玫瑰图,当起始角度不为0时,tooltip位置不准确的bug
- uCharts.js 增加温度计式柱状图开启顶部半圆形的配置
## 2.2.0-20210529(2021-05-29)
- uCharts.js 增加条状图type="bar"
- 示例项目 pages/ucharts/ucharts.vue增加条状图的demo
## 2.1.7-20210524(2021-05-24)
- uCharts.js 修复大数据量模式下曲线图不平滑的bug
## 2.1.6-20210523(2021-05-23)
- 秋云图表组件 修复小程序端开启滚动条更新数据后滚动条位置不符合预期的bug
## 2.1.5-2021051702(2021-05-17)
- uCharts.js 修复自定义Y轴min和max值为0时不能正确显示的bug
## 2.1.5-20210517(2021-05-17)
- uCharts.js 修复Y轴自定义min和max时,未按指定的最大值最小值显示坐标轴刻度的bug
## 2.1.4-20210516(2021-05-16)
- 秋云图表组件 优化onWindowResize防抖方法
- 秋云图表组件 修复APP端uCharts更新数据时,清空series显示loading图标后再显示图表,图表抖动的bug
- uCharts.js 修复开启canvas2d后,x轴、y轴、series自定义字体大小未按比例缩放的bug
- 示例项目 修复format-e.vue拼写错误导致app端使用uCharts渲染图表
## 2.1.3-20210513(2021-05-13)
- 秋云图表组件 修改uCharts变更chartData数据为updateData方法,支持带滚动条的数据动态打点
- 秋云图表组件 增加onWindowResize防抖方法 fix by ど誓言,如尘般染指流年づ
- 秋云图表组件 H5或者APP变更chartData数据显示loading图表时,原数据闪现的bug
- 秋云图表组件 props增加errorReload禁用错误点击重新加载的方法
- uCharts.js 增加tooltip显示category(x轴对应点位)标题的功能,opts.extra.tooltip.showCategory,默认为false
- uCharts.js 修复mix混合图只有柱状图时,tooltip的分割线显示位置不正确的bug
- uCharts.js 修复开启滚动条,图表在拖动中动态打点,滚动条位置不正确的bug
- uCharts.js 修复饼图类数据格式为echarts数据格式,series为空数组报错的bug
- 示例项目 修改uCharts.js更新到v2.1.2版本后,@getIndex方法获取索引值变更为e.currentIndex.index
- 示例项目 pages/updata/updata.vue增加滚动条拖动更新(数据动态打点)的demo
- 示例项目 pages/other/other.vue增加errorReload禁用错误点击重新加载的demo
## 2.1.2-20210509(2021-05-09)
秋云图表组件 修复APP端初始化时就传入chartData或lacaldata不显示图表的bug
## 2.1.1-20210509(2021-05-09)
- 秋云图表组件 变更ECharts的eopts配置在renderjs内执行,支持在config-echarts.js配置文件内写function配置。
- 秋云图表组件 修复APP端报错Prop being mutated: "onmouse"错误的bug。
- 秋云图表组件 修复APP端报错Error: Not Found:Page[6][-1,27] at view.umd.min.js:1的bug。
## 2.1.0-20210507(2021-05-07)
- 秋云图表组件 修复初始化时就有数据或者数据更新的时候loading加载动画闪动的bug
- uCharts.js 修复x轴format方法categories为字符串类型时返回NaN的bug
- uCharts.js 修复series.textColor、legend.fontColor未执行全局默认颜色的bug
## 2.1.0-20210506(2021-05-06)
- 秋云图表组件 修复极个别情况下报错item.properties undefined的bug
- 秋云图表组件 修复极个别情况下关闭加载动画reshow不起作用,无法显示图表的bug
- 示例项目 pages/ucharts/ucharts.vue 增加时间轴折线图(type="tline")、时间轴区域图(type="tarea")、散点图(type="scatter")、气泡图demo(type="bubble")、倒三角形漏斗图(opts.extra.funnel.type="triangle")、金字塔形漏斗图(opts.extra.funnel.type="pyramid")
- 示例项目 pages/format-u/format-u.vue 增加X轴format格式化示例
- uCharts.js 升级至v2.1.0版本
- uCharts.js 修复 玫瑰图面积模式点击tooltip位置不正确的bug
- uCharts.js 修复 玫瑰图点击图例,只剩一个类别显示空白的bug
- uCharts.js 修复 饼图类图点击图例,其他图表tooltip位置某些情况下不准的bug
- uCharts.js 修复 x轴为矢量轴(时间轴)情况下,点击tooltip位置不正确的bug
- uCharts.js 修复 词云图获取点击索引偶尔不准的bug
- uCharts.js 增加 直角坐标系图表X轴format格式化方法(原生uCharts.js用法请使用formatter)
- uCharts.js 增加 漏斗图扩展配置,倒三角形(opts.extra.funnel.type="triangle"),金字塔形(opts.extra.funnel.type="pyramid")
- uCharts.js 增加 散点图(opts.type="scatter")、气泡图(opts.type="bubble")
- 后期计划 完善散点图、气泡图,增加markPoints标记点,增加横向条状图。
## 2.0.0-20210502(2021-05-02)
- uCharts.js 修复词云图获取点击索引不正确的bug
## 2.0.0-20210501(2021-05-01)
- 秋云图表组件 修复QQ小程序、百度小程序在关闭动画效果情况下,v-for循环使用图表,显示不正确的bug
## 2.0.0-20210426(2021-04-26)
- 秋云图表组件 修复QQ小程序不支持canvas2d的bug
- 秋云图表组件 修复钉钉小程序某些情况点击坐标计算错误的bug
- uCharts.js 增加 extra.column.categoryGap 参数,柱状图类每个category点位(X轴点)柱子组之间的间距
- uCharts.js 增加 yAxis.data[i].titleOffsetY 参数,标题纵向偏移距离,负数为向上偏移,正数向下偏移
- uCharts.js 增加 yAxis.data[i].titleOffsetX 参数,标题横向偏移距离,负数为向左偏移,正数向右偏移
- uCharts.js 增加 extra.gauge.labelOffset 参数,仪表盘标签文字径向便宜距离,默认13px
## 2.0.0-20210422-2(2021-04-22)
秋云图表组件 修复 formatterAssign 未判断 args[key] == null 的情况导致栈溢出的 bug
## 2.0.0-20210422(2021-04-22)
- 秋云图表组件 修复H5、APP、支付宝小程序、微信小程序canvas2d模式下横屏模式的bug
## 2.0.0-20210421(2021-04-21)
- uCharts.js 修复多行图例的情况下,图例在上方或者下方时,图例float为左侧或者右侧时,第二行及以后的图例对齐方式不正确的bug
## 2.0.0-20210420(2021-04-20)
- 秋云图表组件 修复微信小程序开启canvas2d模式后,windows版微信小程序不支持canvas2d模式的bug
- 秋云图表组件 修改非uni_modules版本为v2.0版本qiun-data-charts组件
## 2.0.0-20210419(2021-04-19)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font>
## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 修复混合图中柱状图单独设置颜色不生效的bug
- uCharts.js 修复多Y轴单独设置fontSize时,开启canvas2d后,未对应放大字体的bug
## 2.0.0-20210418(2021-04-18)
- 秋云图表组件 增加directory配置,修复H5端history模式下如果发布到二级目录无法正确加载echarts.min.js的bug
## 2.0.0-20210416(2021-04-16)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font>
## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复APP端某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
- 示例项目 修复APP端v-for循环某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
- uCharts.js 修复非直角坐标系tooltip提示窗右侧超出未变换方向显示的bug
## 2.0.0-20210415(2021-04-15)
- 秋云图表组件 修复H5端发布到二级目录下echarts无法加载的bug
- 秋云图表组件 修复某些情况下echarts.off('finished')移除监听事件报错的bug
## 2.0.0-20210414(2021-04-14)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font>
## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复H5端在cli项目下ECharts引用地址错误的bug
- 示例项目 增加ECharts的formatter用法的示例(详见示例项目format-e.vue)
- uCharts.js 增加圆环图中心背景色的配置extra.ring.centerColor
- uCharts.js 修复微信小程序安卓端柱状图开启透明色后显示不正确的bug
## 2.0.0-20210413(2021-04-13)
- 秋云图表组件 修复百度小程序多个图表真机未能正确获取根元素dom尺寸的bug
- 秋云图表组件 修复百度小程序横屏模式方向不正确的bug
- 秋云图表组件 修改ontouch时,@getTouchStart@getTouchMove@getTouchEnd的触发条件
- uCharts.js 修复饼图类数据格式series属性不生效的bug
- uCharts.js 增加时序区域图 详见示例项目中ucharts.vue
## 2.0.0-20210412-2(2021-04-12)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX。如仍不好用,请重启电脑,此问题已于DCloud官方确认,HBuilderX下个版本会修复。
## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复uCharts在APP端横屏模式下不能正确渲染的bug
- 示例项目 增加ECharts柱状图渐变色、圆角柱状图、横向柱状图(条状图)的示例
## 2.0.0-20210412(2021-04-12)
- 秋云图表组件 修复created中判断echarts导致APP端无法识别,改回mounted中判断echarts初始化
- uCharts.js 修复2d模式下series.textOffset未乘像素比的bug
## 2.0.0-20210411(2021-04-11)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册<qiun-data-charts>组件,请重启HBuilderX,并清空小程序开发者工具缓存。
## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 折线图区域图增加connectNulls断点续连的功能,详见示例项目中ucharts.vue
- 秋云图表组件 变更初始化方法为created,变更type2d默认值为true,优化2d模式下组件初始化后dom获取不到的bug
- 秋云图表组件 修复左右布局时,右侧图表点击坐标错误的bug,修复tooltip柱状图自定义颜色显示object的bug
## 2.0.0-20210410(2021-04-10)
- 修复左右布局时,右侧图表点击坐标错误的bug,修复柱状图自定义颜色tooltip显示object的bug
- 增加标记线及柱状图自定义颜色的demo
## 2.0.0-20210409(2021-04-08)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
## 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 修复钉钉小程序百度小程序measureText不准确的bug,修复2d模式下饼图类activeRadius为按比例放大的bug
- 修复组件在支付宝小程序端点击位置不准确的bug
## 2.0.0-20210408(2021-04-07)
- 修复组件在支付宝小程序端不能显示的bug(目前支付宝小程不能点击交互,后续修复)
- uCharts.js 修复高分屏下柱状图类,圆弧进度条 自定义宽度不能按比例放大的bug
## 2.0.0-20210407(2021-04-06)
## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
## 增加 通过tofix和unit快速格式化y轴的demo add by `howcode`
## 增加 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
## 2.0.0-20210406(2021-04-05)
# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页
## 2.0.0(2021-04-05)
# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页

1614
components/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue

File diff suppressed because it is too large

46
components/qiun-data-charts/components/qiun-error/qiun-error.vue

File diff suppressed because one or more lines are too long

162
components/qiun-data-charts/components/qiun-loading/loading1.vue

@ -0,0 +1,162 @@
<template>
<view class="container loading1">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading1',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading1 {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading1 .shape1 {
-webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
animation: animation1shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
@keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
.loading1 .shape2 {
-webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
animation: animation1shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
@keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
.loading1 .shape3 {
-webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
animation: animation1shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
@keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
.loading1 .shape4 {
-webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
animation: animation1shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
@keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
</style>

170
components/qiun-data-charts/components/qiun-loading/loading2.vue

@ -0,0 +1,170 @@
<template>
<view class="container loading2">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading2',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading2 {
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
.container.loading2 .shape {
border-radius: 5px;
}
.container.loading2{
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading2 .shape1 {
-webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
animation: animation2shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
@keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
.loading2 .shape2 {
-webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
animation: animation2shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
@keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
.loading2 .shape3 {
-webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
animation: animation2shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
@keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
.loading2 .shape4 {
-webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
animation: animation2shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
@keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
</style>

173
components/qiun-data-charts/components/qiun-loading/loading3.vue

@ -0,0 +1,173 @@
<template>
<view class="container loading3">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading3',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading3 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading3 .shape1 {
border-top-left-radius: 10px;
}
.container.loading3 .shape2 {
border-top-right-radius: 10px;
}
.container.loading3 .shape3 {
border-bottom-left-radius: 10px;
}
.container.loading3 .shape4 {
border-bottom-right-radius: 10px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading3 .shape1 {
-webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
animation: animation3shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
@keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
.loading3 .shape2 {
-webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
animation: animation3shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
@keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
.loading3 .shape3 {
-webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
animation: animation3shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
@keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
.loading3 .shape4 {
-webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
animation: animation3shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
@keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
</style>

222
components/qiun-data-charts/components/qiun-loading/loading4.vue

@ -0,0 +1,222 @@
<template>
<view class="container loading5">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading5',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading5 .shape {
width: 15px;
height: 15px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading5 .shape1 {
animation: animation5shape1 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
@keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
.loading5 .shape2 {
animation: animation5shape2 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
@keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
.loading5 .shape3 {
animation: animation5shape3 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
@keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
.loading5 .shape4 {
animation: animation5shape4 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
@keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
</style>

229
components/qiun-data-charts/components/qiun-loading/loading5.vue

@ -0,0 +1,229 @@
<template>
<view class="container loading6">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading6',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading6 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading6 .shape {
width: 12px;
height: 12px;
border-radius: 2px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading6 .shape1 {
-webkit-animation: animation6shape1 2s linear 0s infinite normal;
animation: animation6shape1 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
@keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
.loading6 .shape2 {
-webkit-animation: animation6shape2 2s linear 0s infinite normal;
animation: animation6shape2 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
@keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
.loading6 .shape3 {
-webkit-animation: animation6shape3 2s linear 0s infinite normal;
animation: animation6shape3 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
@keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
.loading6 .shape4 {
-webkit-animation: animation6shape4 2s linear 0s infinite normal;
animation: animation6shape4 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
@keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
</style>

36
components/qiun-data-charts/components/qiun-loading/qiun-loading.vue

@ -0,0 +1,36 @@
<template>
<view>
<Loading1 v-if="loadingType==1"/>
<Loading2 v-if="loadingType==2"/>
<Loading3 v-if="loadingType==3"/>
<Loading4 v-if="loadingType==4"/>
<Loading5 v-if="loadingType==5"/>
</view>
</template>
<script>
import Loading1 from "./loading1.vue";
import Loading2 from "./loading2.vue";
import Loading3 from "./loading3.vue";
import Loading4 from "./loading4.vue";
import Loading5 from "./loading5.vue";
export default {
components:{Loading1,Loading2,Loading3,Loading4,Loading5},
name: 'qiun-loading',
props: {
loadingType: {
type: Number,
default: 2
},
},
data() {
return {
};
},
}
</script>
<style>
</style>

422
components/qiun-data-charts/js_sdk/u-charts/config-echarts.js

@ -0,0 +1,422 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 通用配置项
// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
const cfe = {
//demotype为自定义图表类型
"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
//instance为实例变量承载属性,option为eopts承载属性,不要删除
"instance": {},
"option": {},
//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
"formatter":{
"tooltipDemo1":function(res){
let result = ''
for (let i in res) {
if (i == 0) {
result += res[i].axisValueLabel + '年销售额'
}
let value = '--'
if (res[i].data !== null) {
value = res[i].data
}
// #ifdef H5
result += '\n' + res[i].seriesName + ':' + value + ' 万元'
// #endif
// #ifdef APP-PLUS
result += '<br/>' + res[i].marker + res[i].seriesName + ':' + value + ' 万元'
// #endif
}
return result;
},
legendFormat:function(name){
return "自定义图例+"+name;
},
yAxisFormatDemo:function (value, index) {
return value + '元';
},
seriesFormatDemo:function(res){
return res.name + '年' + res.value + '元';
}
},
//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在eopts参数,会将demotype与eopts中option合并后渲染图表。
"demotype":{
"color": color,
//在这里填写echarts的option即可
},
//下面是自定义配置,请添加项目所需的通用配置
"column": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'bar',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"line": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"area": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"areaStyle": {},
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"pie": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": '50%',
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"ring": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": ['40%', '70%'],
"avoidLabelOverlap": false,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
"labelLine": {
"show": true
},
},
},
"rose": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": "55%",
"center": ['50%', '50%'],
"roseType": 'area',
},
},
"funnel": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item',
"formatter": "{b} : {c}%"
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'funnel',
"left": '10%',
"top": 60,
"bottom": 60,
"width": '80%',
"min": 0,
"max": 100,
"minSize": '0%',
"maxSize": '100%',
"sort": 'descending',
"gap": 2,
"label": {
"show": true,
"position": 'inside'
},
"labelLine": {
"length": 10,
"lineStyle": {
"width": 1,
"type": 'solid'
}
},
"itemStyle": {
"bordercolor": '#fff',
"borderwidth": 1
},
"emphasis": {
"label": {
"fontSize": 20
}
},
"data": [],
},
},
"gauge": {
"color": color,
"tooltip": {
"formatter": '{a} <br/>{b} : {c}%'
},
"seriesTemplate": {
"name": '业务指标',
"type": 'gauge',
"detail": {"formatter": '{value}%'},
"data": [{"value": 50, "name": '完成率'}]
},
},
"candle": {
"xAxis": {
"data": []
},
"yAxis": {},
"color": color,
"title": {
"text": ''
},
"dataZoom": [{
"type": 'inside',
"xAxisIndex": [0, 1],
"start": 10,
"end": 100
},
{
"show": true,
"xAxisIndex": [0, 1],
"type": 'slider',
"bottom": 10,
"start": 10,
"end": 100
}
],
"seriesTemplate": {
"name": '',
"type": 'k',
"data": [],
},
}
}
export default cfe;

606
components/qiun-data-charts/js_sdk/u-charts/config-ucharts.js

@ -0,0 +1,606 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
//事件转换函数,主要用作格式化x轴为时间轴,根据需求自行修改
const formatDateTime = (timeStamp, returnType)=>{
var date = new Date();
date.setTime(timeStamp * 1000);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if(returnType == 'full'){return y + '-' + m + '-' + d + ' '+ h +':' + minute + ':' + second;}
if(returnType == 'y-m-d'){return y + '-' + m + '-' + d;}
if(returnType == 'h:m'){return h +':' + minute;}
if(returnType == 'h:m:s'){return h +':' + minute +':' + second;}
return [y, m, d, h, minute, second];
}
const cfu = {
//demotype为自定义图表类型,一般不需要自定义图表类型,只需要改根节点上对应的类型即可
"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","mount","bar","area","radar","gauge","candle","mix","tline","tarea","scatter","bubble","demotype"],
"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","山峰图","条状图","区域图","雷达图","仪表盘","K线图","混合图","时间轴折线","时间轴区域","散点图","气泡图","自定义类型"],
//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型,例如最后的"demotype"
//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴(矢量x轴)类图表,没有categories,不需要加入categories
"categories":["line","column","mount","bar","area","radar","gauge","candle","mix","demotype"],
//instance为实例变量承载属性,不要删除
"instance":{},
//option为opts及eopts承载属性,不要删除
"option":{},
//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
"formatter":{
"yAxisDemo1":function(val, index, opts){return val+'元'},
"yAxisDemo2":function(val, index, opts){return val.toFixed(2)},
"xAxisDemo1":function(val, index, opts){return val+'年';},
"xAxisDemo2":function(val, index, opts){return formatDateTime(val,'h:m')},
"seriesDemo1":function(val, index, series, opts){return val+'元'},
"tooltipDemo1":function(item, category, index, opts){
if(index==0){
return '随便用'+item.data+'年'
}else{
return '其他我没改'+item.data+'天'
}
},
"pieDemo":function(val, index, series, opts){
if(index !== undefined){
return series[index].name+':'+series[index].data+'元'
}
},
},
//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
"demotype":{
//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2
},
}
},
//下面是自定义配置,请添加项目所需的通用配置
"pie":{
"type": "pie",
"color": color,
"padding": [5,5,5,5],
"extra": {
"pie": {
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
}
},
"ring":{
"type": "ring",
"color": color,
"padding": [5,5,5,5],
"rotate": false,
"dataLabel": true,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"title": {
"name": "收益率",
"fontSize": 15,
"color": "#666666"
},
"subtitle": {
"name": "70%",
"fontSize": 25,
"color": "#7cb5ec"
},
"extra": {
"ring": {
"ringWidth":30,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
},
},
"rose":{
"type": "rose",
"color": color,
"padding": [5,5,5,5],
"legend": {
"show": true,
"position": "left",
"lineHeight": 25,
},
"extra": {
"rose": {
"type": "area",
"minRadius": 50,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": false,
"borderWidth": 2,
"borderColor": "#FFFFFF"
},
}
},
"word":{
"type": "word",
"color": color,
"extra": {
"word": {
"type": "normal",
"autoColors": false
}
}
},
"funnel":{
"type": "funnel",
"color": color,
"padding": [15,15,0,15],
"extra": {
"funnel": {
"activeOpacity": 0.3,
"activeWidth": 10,
"border": true,
"borderWidth": 2,
"borderColor": "#FFFFFF",
"fillOpacity": 1,
"labelAlign": "right"
},
}
},
"map":{
"type": "map",
"color": color,
"padding": [0,0,0,0],
"dataLabel": true,
"extra": {
"map": {
"border": true,
"borderWidth": 1,
"borderColor": "#666666",
"fillOpacity": 0.6,
"activeBorderColor": "#F04864",
"activeFillColor": "#FACC14",
"activeFillOpacity": 1
},
}
},
"arcbar":{
"type": "arcbar",
"color": color,
"title": {
"name": "百分比",
"fontSize": 25,
"color": "#00FF00"
},
"subtitle": {
"name": "默认标题",
"fontSize": 15,
"color": "#666666"
},
"extra": {
"arcbar": {
"type": "default",
"width": 12,
"backgroundColor": "#E9E9E9",
"startAngle": 0.75,
"endAngle": 0.25,
"gap": 2
}
}
},
"line":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "straight",
"width": 2,
"activeType": "hollow"
},
}
},
"tline":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": false,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2,
"activeType": "hollow"
},
}
},
"tarea":{
"type": "area",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"area": {
"type": "curve",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": true,
"activeType": "hollow"
},
}
},
"column":{
"type": "column",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"column": {
"type": "group",
"width": 30,
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"mount":{
"type": "mount",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"mount": {
"type": "mount",
"widthRatio": 1.5,
},
}
},
"bar":{
"type": "bar",
"color": color,
"padding": [15,30,0,5],
"xAxis": {
"boundaryGap":"justify",
"disableGrid":false,
"min":0,
"axisLine":false
},
"yAxis": {
},
"legend": {
},
"extra": {
"bar": {
"type": "group",
"width": 30,
"meterBorde": 1,
"meterFillColor": "#FFFFFF",
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"area":{
"type": "area",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"area": {
"type": "straight",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": false,
"activeType": "hollow"
},
}
},
"radar":{
"type": "radar",
"color": color,
"padding": [5,5,5,5],
"dataLabel": false,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"extra": {
"radar": {
"gridType": "radar",
"gridColor": "#CCCCCC",
"gridCount": 3,
"opacity": 0.2,
"max": 200,
"labelShow": true
},
}
},
"gauge":{
"type": "gauge",
"color": color,
"title": {
"name": "66Km/H",
"fontSize": 25,
"color": "#2fc25b",
"offsetY": 50
},
"subtitle": {
"name": "实时速度",
"fontSize": 15,
"color": "#1890ff",
"offsetY": -50
},
"extra": {
"gauge": {
"type": "default",
"width": 30,
"labelColor": "#666666",
"startAngle": 0.75,
"endAngle": 0.25,
"startNumber": 0,
"endNumber": 100,
"labelFormat": "",
"splitLine": {
"fixRadius": 0,
"splitNumber": 10,
"width": 30,
"color": "#FFFFFF",
"childNumber": 5,
"childWidth": 12
},
"pointer": {
"width": 24,
"color": "auto"
}
}
}
},
"candle":{
"type": "candle",
"color": color,
"padding": [15,15,0,15],
"enableScroll": true,
"enableMarkLine": true,
"dataLabel": false,
"xAxis": {
"labelCount": 4,
"itemCount": 40,
"disableGrid": true,
"gridColor": "#CCCCCC",
"gridType": "solid",
"dashLength": 4,
"scrollShow": true,
"scrollAlign": "left",
"scrollColor": "#A6A6A6",
"scrollBackgroundColor": "#EFEBEF"
},
"yAxis": {
},
"legend": {
},
"extra": {
"candle": {
"color": {
"upLine": "#f04864",
"upFill": "#f04864",
"downLine": "#2fc25b",
"downFill": "#2fc25b"
},
"average": {
"show": true,
"name": ["MA5","MA10","MA30"],
"day": [5,10,20],
"color": ["#1890ff","#2fc25b","#facc14"]
}
},
"markLine": {
"type": "dash",
"dashLength": 5,
"data": [
{
"value": 2150,
"lineColor": "#f04864",
"showLabel": true
},
{
"value": 2350,
"lineColor": "#f04864",
"showLabel": true
}
]
}
}
},
"mix":{
"type": "mix",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"disabled": false,
"disableGrid": false,
"splitNumber": 5,
"gridType": "dash",
"dashLength": 4,
"gridColor": "#CCCCCC",
"padding": 10,
"showTitle": true,
"data": []
},
"legend": {
},
"extra": {
"mix": {
"column": {
"width": 20
}
},
}
},
"scatter":{
"type": "scatter",
"color":color,
"padding":[15,15,0,15],
"dataLabel":false,
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
},
"legend": {
},
"extra": {
"scatter": {
},
}
},
"bubble":{
"type": "bubble",
"color":color,
"padding":[15,15,0,15],
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0,
"max":250
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
"data":[{
"min":0,
"max":150
}]
},
"legend": {
},
"extra": {
"bubble": {
"border":2,
"opacity": 0.5,
},
}
}
}
export default cfu;

5
components/qiun-data-charts/js_sdk/u-charts/readme.md

@ -0,0 +1,5 @@
# uCharts JSSDK说明
1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`120kb`。
2、如果120kb的体积仍需压缩,请手到uCharts官网通过在线定制选择您需要的图表。
3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
4、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

7706
components/qiun-data-charts/js_sdk/u-charts/u-charts.js

File diff suppressed because it is too large

18
components/qiun-data-charts/js_sdk/u-charts/u-charts.min.js

File diff suppressed because one or more lines are too long

201
components/qiun-data-charts/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.

80
components/qiun-data-charts/package.json

@ -0,0 +1,80 @@
{
"id": "qiun-data-charts",
"displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
"version": "2.5.0-20230101",
"description": "uCharts 新增正负柱状图!支持H5及APP用 ucharts echarts 渲染图表,uniapp可视化首选组件",
"keywords": [
"ucharts",
"echarts",
"f2",
"图表",
"可视化"
],
"repository": "https://gitee.com/uCharts/uCharts",
"engines": {
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": "474119"
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/~qiun",
"type": "component-vue"
},
"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"
}
}
}
}
}

84
components/qiun-data-charts/readme.md

@ -0,0 +1,84 @@
![logo](https://img-blog.csdnimg.cn/4a276226973841468c1be356f8d9438b.png)
[![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
[![fork](https://gitee.com/uCharts/uCharts/badge/fork.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/members)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![npm package](https://img.shields.io/npm/v/@qiun/ucharts.svg?style=flat-square)](https://www.npmjs.com/~qiun)
## uCharts简介
`uCharts`是一款基于`canvas API`开发的适用于所有前端应用的图表库,开发者编写一套代码,可运行到 Web、iOS、Android(基于 uni-app / taro )、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等更多支持 canvas API 的平台。
## 官方网站
## [https://www.ucharts.cn](https://www.ucharts.cn)
## 快速体验
一套代码编到多个平台,依次扫描二维码,亲自体验uCharts图表跨平台效果!其他平台请自行编译。
![](https://www.ucharts.cn/images/web/guide/qrcode20220224.png)
![](https://img-blog.csdnimg.cn/7d0115593ff24ac39a224fb7c6ed72a4.png)
## 致开发者
感谢各位开发者`五年`来对秋云及uCharts的支持,uCharts的进步离不开各位开发者的鼓励与贡献。为更好的帮助各位开发者使用图表工具,我们推出了新版官网,增加了在线定制、问答社区、在线配置等一些增值服务,为确保您能更好的应用图表组件,建议您先`仔细阅读官网指南`以及`常见问题`,而不是下载下来`直接使用`。如仍然不能解决,请到`官网社区`或开通会员后加入`专属VIP会员群`提问将会很快得到回答。
## 视频教程
## [uCharts新手入门教程](https://www.bilibili.com/video/BV1qA411Q7se/?share_source=copy_web&vd_source=42a1242f9aaade6427736af69eb2e1d9)
## 社群支持
uCharts官方拥有5个2000人的QQ群及专属VIP会员群支持,庞大的用户量证明我们一直在努力,请各位放心使用!uCharts的开源图表组件的开发,团队付出了大量的时间与精力,经过四来的考验,不会有比较明显的bug,请各位放心使用。如果您有更好的想法,可以在`码云提交Pull Requests`以帮助更多开发者完成需求,再次感谢各位对uCharts的鼓励与支持!
#### 官方交流群
- 交流群1:371774600(已满)
- 交流群2:619841586(已满)
- 交流群3:955340127(已满)
- 交流群4:641669795(已满)
- 交流群5:236294809(只能扫码加入)
![](https://www.ucharts.cn/images/web/qq5.jpg)
- 口令`uniapp`
#### 专属VIP会员群
- 开通会员后详见【账号详情】页面中顶部的滚动通知
- 口令`您的用户ID`
## 版权信息
uCharts始终坚持开源,遵循 [Apache Licence 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) 开源协议,意味着您无需支付任何费用,即可将uCharts应用到您的产品中。
注意:这并不意味着您可以将uCharts应用到非法的领域,比如涉及赌博,暴力等方面。如因此产生纠纷或法律问题,uCharts相关方及秋云科技不承担任何责任。
## 合作伙伴
[![DIY官网](https://www.ucharts.cn/images/web/guide/links/diy-gw.png)](https://www.diygw.com/)
[![HasChat](https://www.ucharts.cn/images/web/guide/links/haschat.png)](https://gitee.com/howcode/has-chat)
[![uViewUI](https://www.ucharts.cn/images/web/guide/links/uView.png)](https://www.uviewui.com/)
[![图鸟UI](https://www.ucharts.cn/images/web/guide/links/tuniao.png)](https://ext.dcloud.net.cn/plugin?id=7088)
[![thorui](https://www.ucharts.cn/images/web/guide/links/thorui.png)](https://ext.dcloud.net.cn/publisher?id=202)
[![FirstUI](https://www.ucharts.cn/images/web/guide/links/first.png)](https://www.firstui.cn/)
[![nProUI](https://www.ucharts.cn/images/web/guide/links/nPro.png)](https://ext.dcloud.net.cn/plugin?id=5169)
[![GraceUI](https://www.ucharts.cn/images/web/guide/links/grace.png)](https://www.graceui.com/)
## 更新记录
详见官网指南中说明,[点击此处查看](https://www.ucharts.cn/v2/#/guide/index?id=100)
## 相关链接
- [uCharts官网](https://www.ucharts.cn)
- [DCloud插件市场地址](https://ext.dcloud.net.cn/plugin?id=271)
- [uCharts码云开源托管地址](https://gitee.com/uCharts/uCharts) [![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
- [uCharts npm开源地址](https://www.ucharts.cn)
- [ECharts官网](https://echarts.apache.org/zh/index.html)
- [ECharts配置手册](https://echarts.apache.org/zh/option.html)
- [图表组件在项目中的应用 ReportPlus数据报表](https://www.ucharts.cn/v2/#/layout/info?id=1)

23
components/qiun-data-charts/static/app-plus/echarts.min.js

File diff suppressed because one or more lines are too long

23
components/qiun-data-charts/static/h5/echarts.min.js

File diff suppressed because one or more lines are too long

54
components/ruoyi/DictTag/index.vue

@ -0,0 +1,54 @@
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<span
v-if="item.elTagType == 'default' || item.elTagType == ''"
:key="item.value"
:index="index"
:class="item.elTagClass"
>{{ item.label }}</span>
<uni-tag
v-else
:key="item.value + ''"
:index="index"
:type="elTagType(item.elTagType)"
:class="item.elTagClass"
:text="item.label"
/>
</template>
</template>
</div>
</template>
<script setup>
const props = defineProps({
//
options: {
type: Array,
default: null,
},
//
value: [Number, String, Array],
})
const values = computed(() => {
if (props.value !== null && typeof props.value !== 'undefined') {
return Array.isArray(props.value) ? props.value : [String(props.value)];
} else {
return [];
}
})
const elTagType = (tagType) =>{
tagType === 'danger' ? 'error' : tagType
tagType === 'info' ? 'default' : tagType
}
</script>
<style scoped>
.uni-tag + .uni-tag {
margin-left: 10px;
}
</style>

1
components/u-city-select/area.js

File diff suppressed because one or more lines are too long

1
components/u-city-select/city.js

File diff suppressed because one or more lines are too long

1
components/u-city-select/province.js

@ -0,0 +1 @@
var provinceData=[{"label":"北京市","value":"11"},{"label":"天津市","value":"12"},{"label":"河北省","value":"13"},{"label":"山西省","value":"14"},{"label":"内蒙古自治区","value":"15"},{"label":"辽宁省","value":"21"},{"label":"吉林省","value":"22"},{"label":"黑龙江省","value":"23"},{"label":"上海市","value":"31"},{"label":"江苏省","value":"32"},{"label":"浙江省","value":"33"},{"label":"安徽省","value":"34"},{"label":"福建省","value":"35"},{"label":"江西省","value":"36"},{"label":"山东省","value":"37"},{"label":"河南省","value":"41"},{"label":"湖北省","value":"42"},{"label":"湖南省","value":"43"},{"label":"广东省","value":"44"},{"label":"广西壮族自治区","value":"45"},{"label":"海南省","value":"46"},{"label":"重庆市","value":"50"},{"label":"四川省","value":"51"},{"label":"贵州省","value":"52"},{"label":"云南省","value":"53"},{"label":"西藏自治区","value":"54"},{"label":"陕西省","value":"61"},{"label":"甘肃省","value":"62"},{"label":"青海省","value":"63"},{"label":"宁夏回族自治区","value":"64"},{"label":"新疆维吾尔自治区","value":"65"},{"label":"台湾","value":"66"},{"label":"香港","value":"67"},{"label":"澳门","value":"68"}];export default provinceData;

240
components/u-city-select/u-city-select.vue

@ -0,0 +1,240 @@
<template>
<u-popup :show="modelValue" mode="bottom" :popup="false" :mask="true" :closeable="true" :safe-area-inset-bottom="true"
close-icon-color="#ffffff" :z-index="uZIndex" :maskCloseAble="maskCloseAble" @close="close">
<u-tabs v-if="modelValue" :list="genTabsList" :scrollable="true" :current="tabsIndex" @change="tabsChange"
ref="tabs" />
<view class="area-box">
<view class="u-flex" :class="{ 'change': isChange }">
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group>
<u-cell v-for="(item, index) in provinces" :title="item.label" :arrow="false" :index="index"
:key="index" @click="provinceChange(index)">
<template v-slot:right-icon>
<u-icon v-if="isChooseP && province === index" size="17"
name="checkbox-mark"></u-icon>
</template>
</u-cell>
</u-cell-group>
</scroll-view>
</view>
</view>
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group v-if="isChooseP">
<u-cell v-for="(item, index) in citys" :title="item.label" :arrow="false" :index="index"
:key="index" @click="cityChange(index)">
<template v-slot:right-icon>
<u-icon v-if="isChooseC && city === index" size="17" name="checkbox-mark"></u-icon>
</template>
</u-cell>
</u-cell-group>
</scroll-view>
</view>
</view>
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group v-if="isChooseC">
<u-cell v-for="(item, index) in areas" :title="item.label" :arrow="false" :index="index"
:key="index" @click="areaChange(index)">
<template v-slot:right-icon>
<u-icon v-if="isChooseA && area === index" size="17" name="checkbox-mark"></u-icon>
</template>
</u-cell>
</u-cell-group>
</scroll-view>
</view>
</view>
</view>
</view>
</u-popup>
</template>
<script>
import provinces from "./province.js";
import citys from "./city.js";
import areas from "./area.js";
/**
* city-select 省市区级联选择器
* @property {String Number} z-index 弹出时的z-index值默认1075
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker默认true
* @property {String} default-region 默认选中的地区中文形式
* @property {String} default-code 默认选中的地区编号形式
*/
export default {
name: 'u-city-select',
props: {
//
modelValue: {
type: Boolean,
default: false
},
// ["", "", ""]
defaultRegion: {
type: Array,
default() {
return [];
}
},
// defaultRegionareaCodeareaCode["13", "1303", "130304"]
areaCode: {
type: Array,
default() {
return [];
}
},
// Picker
maskCloseAble: {
type: Boolean,
default: true
},
// z-index
zIndex: {
type: [String, Number],
default: 0
}
},
data() {
return {
cityValue: "",
isChooseP: false, //
province: 0, //
provinces: provinces,
isChooseC: false, //
city: 0, //
citys: citys[0],
isChooseA: false, //
area: 0, //
areas: areas[0][0],
tabsIndex: 0,
}
},
mounted() {
this.init();
},
computed: {
isChange() {
return this.tabsIndex > 1;
},
genTabsList() {
let tabsList = [{
name: "请选择"
}];
if (this.isChooseP) {
tabsList[0]['name'] = this.provinces[this.province]['label'];
tabsList[1] = {
name: "请选择"
};
}
if (this.isChooseC) {
tabsList[1]['name'] = this.citys[this.city]['label'];
tabsList[2] = {
name: "请选择"
};
}
if (this.isChooseA) {
tabsList[2]['name'] = this.areas[this.area]['label'];
}
return tabsList;
},
uZIndex() {
// z-index使
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
}
},
emits: ['city-change'],
methods: {
init() {
if (this.areaCode.length == 3) {
this.setProvince("", this.areaCode[0]);
this.setCity("", this.areaCode[1]);
this.setArea("", this.areaCode[2]);
} else if (this.defaultRegion.length == 3) {
this.setProvince(this.defaultRegion[0], "");
this.setCity(this.defaultRegion[1], "");
this.setArea(this.defaultRegion[2], "");
};
},
setProvince(label = "", value = "") {
this.provinces.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.provinceChange(k);
}
})
},
setCity(label = "", value = "") {
this.citys.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.cityChange(k);
}
})
},
setArea(label = "", value = "") {
this.areas.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.isChooseA = true;
this.area = k;
}
})
},
close() {
this.$emit('update:modelValue', false);
this.$emit('close');
},
tabsChange(value) {
this.tabsIndex = value.index;
},
provinceChange(index) {
this.isChooseP = true;
this.isChooseC = false;
this.isChooseA = false;
this.province = index;
this.citys = citys[index];
this.tabsIndex = 1;
},
cityChange(index) {
this.isChooseC = true;
this.isChooseA = false;
this.city = index;
this.areas = areas[this.province][index];
this.tabsIndex = 2;
},
areaChange(index) {
this.isChooseA = true;
this.area = index;
let result = {};
result.province = this.provinces[this.province];
result.city = this.citys[this.city];
result.area = this.areas[this.area];
this.$emit('city-change', result);
this.close();
}
}
}
</script>
<style lang="scss">
.area-box {
width: 100%;
overflow: hidden;
height: 800rpx;
>view {
width: 150%;
transition: transform 0.3s ease-in-out 0s;
transform: translateX(0);
&.change {
transform: translateX(-33.3333333%);
}
}
.area-item {
width: 33.3333333%;
height: 800rpx;
}
}
</style>

167
components/uni-section/uni-section.vue

@ -0,0 +1,167 @@
<template>
<view class="uni-section">
<view class="uni-section-header" @click="onClick">
<view class="uni-section-header__decoration" v-if="type" :class="type" />
<slot v-else name="decoration"></slot>
<view class="uni-section-header__content">
<text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
<text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
</view>
<view class="uni-section-header__slot-right">
<slot name="right"></slot>
</view>
</view>
<view class="uni-section-content" :style="{padding: _padding}">
<slot />
</view>
</view>
</template>
<script>
/**
* Section 标题栏
* @description 标题栏
* @property {String} type = [line|circle|square] 标题装饰类型
* @value line 竖线
* @value circle 圆形
* @value square 正方形
* @property {String} title 主标题
* @property {String} titleFontSize 主标题字体大小
* @property {String} titleColor 主标题字体颜色
* @property {String} subTitle 副标题
* @property {String} subTitleFontSize 副标题字体大小
* @property {String} subTitleColor 副标题字体颜色
* @property {String} padding 默认插槽 padding
*/
export default {
name: 'UniSection',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
title: {
type: String,
required: true,
default: ''
},
titleFontSize: {
type: String,
default: '14px'
},
titleColor:{
type: String,
default: '#333'
},
subTitle: {
type: String,
default: ''
},
subTitleFontSize: {
type: String,
default: '12px'
},
subTitleColor: {
type: String,
default: '#999'
},
padding: {
type: [Boolean, String],
default: false
}
},
computed:{
_padding(){
if(typeof this.padding === 'string'){
return this.padding
}
return this.padding?'10px':''
}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" >
$uni-primary: #2979ff !default;
.uni-section {
background-color: #fff;
.uni-section-header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 12px 10px;
font-weight: normal;
&__decoration{
margin-right: 6px;
background-color: $uni-primary;
&.line {
width: 4px;
height: 12px;
border-radius: 10px;
}
&.circle {
width: 8px;
height: 8px;
border-top-right-radius: 50px;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
}
&.square {
width: 8px;
height: 8px;
}
}
&__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
flex: 1;
color: #333;
.distraction {
flex-direction: row;
align-items: center;
}
&-sub {
margin-top: 2px;
}
}
&__slot-right{
font-size: 14px;
}
}
.uni-section-content{
font-size: 14px;
}
}
</style>

31
config.js

@ -0,0 +1,31 @@
// 应用全局配置
const config = {
// baseUrl: 'https://vue.ruoyi.vip/prod-api',
// baseUrl: 'http://localhost/prod-api',
// baseUrl: 'http://localhost:8080',
//cloud后台网关地址
baseUrl: 'http://114.55.234.214:8080',
// 应用信息
appInfo: {
// 应用名称
name: "ruoyi-app-vue3",
// 应用版本
version: "1.1.0",
// 应用logo
logo: "/static/logo.png",
// 官方网站
site_url: "http://ruoyi.vip",
// 政策协议
agreements: [{
title: "隐私政策",
url: "https://ruoyi.vip/protocol.html"
},
{
title: "用户服务协议",
url: "https://ruoyi.vip/protocol.html"
}
]
}
}
export default config

79
directive/common/copyText.ts

@ -0,0 +1,79 @@
// #ifdef APP-VUE || H5
/**
* v-copyText
* Copyright (c) 2022 ruoyi
* v-copyText="要复制的文本内容"
* v-copyText:callback="复制成功后的回调函数"
*
*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {
$copyValue: string;
$copyCallback: Function;
$destroyCopy:Function;
}
const vCopyText:Directive = {
beforeMount(el:ElType , binding:DirectiveBinding) {
if (binding.arg === "callback") {
el.$copyCallback = binding.value;
} else {
el.$copyValue = binding.value;
const handler = () => {
copyTextToClipboard(el.$copyValue);
if (el.$copyCallback) {
el.$copyCallback(el.$copyValue);
}
};
el.addEventListener("click", handler);
el.$destroyCopy = () => el.removeEventListener("click", handler);
}
}
}
export default vCopyText;
function copyTextToClipboard(input:string, { target = document.body } = {}) {
const element = document.createElement('textarea');
const previouslyFocusedElement = document.activeElement as HTMLElement;
element.value = input;
// Prevent keyboard from showing on mobile
element.setAttribute('readonly', '');
element.style.contain = 'strict';
element.style.position = 'absolute';
element.style.left = '-9999px';
element.style.fontSize = '12pt'; // Prevent zooming on iOS
const selection = document.getSelection();
if(!selection)return
const originalRange = selection.rangeCount > 0 && selection.getRangeAt(0);
target.append(element);
element.select();
// Explicit selection workaround for iOS
element.selectionStart = 0;
element.selectionEnd = input.length;
let isSuccess = false;
try {
isSuccess = document.execCommand('copy');
} catch { }
element.remove();
if (originalRange) {
selection.removeAllRanges();
selection.addRange(originalRange);
}
// Get the focus back on the previously focused element, if any
if (previouslyFocusedElement) {
previouslyFocusedElement.focus();
}
return isSuccess;
}
// #endif

7
directive/common/focus.ts

@ -0,0 +1,7 @@
import type { Directive } from "vue";
const vFocus: Directive = {
mounted: (el) => el.focus()
}
export default vFocus

50
directive/common/full.ts

@ -0,0 +1,50 @@
import type { Directive } from "vue";
interface ElType extends HTMLElement {
$oldStyle: CSSStyleDeclaration;
$fullStyle: CSSStyleDeclaration;
}
const vFull: Directive = {
mounted: (el: ElType, binding) => {
el.$oldStyle = { ...el.style }
if (binding.arg === 'screen') {
el.$fullStyle = {
...el.style,
left: '0',
top: '0',
zIndex: '8',
position: 'fixed',
height: '100vh',
width: '100vw',
}
} else {
el.$fullStyle = {
...el.style,
left: '0',
top: '0',
zIndex: '8',
position: 'absolute',
height: '100%',
width: '100%',
}
}
},
updated: (el: ElType, binding) => {
function setStyle(el: CSSStyleDeclaration, style: CSSStyleDeclaration) {
el.position = style.position
el.left = style.left
el.top = style.top
el.zIndex = style.zIndex
el.height = style.height
el.width = style.width
}
if (binding.value) {
setStyle(el.style, el.$fullStyle)
} else {
setStyle(el.style, el.$oldStyle)
}
}
}
export default vFull

18
directive/index.ts

@ -0,0 +1,18 @@
// #ifdef APP-VUE || H5
import copyText from './common/copyText'
// #endif
import hasRole from './permission/hasRole'
import hasPermi from './permission/hasPermi'
import focus from './common/focus'
import full from './common/full'
import { App } from 'vue'
export default function directive(app: App) {
// #ifdef APP-VUE || H5
app.directive('copyText', copyText)
// #endif
app.directive('hasRole', hasRole)
app.directive('hasPermi', hasPermi)
app.directive('focus', focus)
app.directive('full', full)
}

30
directive/permission/hasPermi.ts

@ -0,0 +1,30 @@
/**
* v-hasPermi
* Copyright (c) 2019 ruoyi
*/
import useUserStore from '@/store/modules/user'
import type { Directive } from "vue";
const vHasPermi: Directive = {
mounted(el, binding, vnode) {
const { value } = binding
const all_permission = "*:*:*";
const permissions = useUserStore().permissions
if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value
const hasPermissions = permissions.some(permission => {
return all_permission === permission || permissionFlag.includes(permission)
})
if (!hasPermissions) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`请设置操作权限标签值`)
}
}
}
export default vHasPermi

30
directive/permission/hasRole.ts

@ -0,0 +1,30 @@
/**
* v-hasRole
* Copyright (c) 2019 ruoyi
*/
import useUserStore from '@/store/modules/user'
import type { Directive } from "vue";
const vHasRole: Directive = {
mounted(el, binding, vnode) {
const { value } = binding
const super_admin = "admin";
const roles = useUserStore().roles
if (value && value instanceof Array && value.length > 0) {
const roleFlag = value
const hasRole = roles.some(role => {
return super_admin === role || roleFlag.includes(role)
})
if (!hasRole) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`请设置角色权限标签值`)
}
}
}
export default vHasRole;

11
env.d.ts

@ -0,0 +1,11 @@
/// <reference types="vite/client" />
/// <reference types="@dcloudio/types" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
declare module "uview-plus";
declare module 'mqtt/dist/mqtt';

21
index.html

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

38
main.js

@ -0,0 +1,38 @@
import App from './App.vue'
import plugins from './plugins'
import store from './store'
import uviewPlus from 'uview-plus'
import { createSSRApp } from 'vue'
import directive from './directive' // directive
import { useDict } from '@/utils/dict'
import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'
export function createApp() {
const app = createSSRApp(App)
app.use(store)
app.use(uviewPlus)
app.use(plugins)
// #ifndef MP-WEIXIN
// 微信小程序中不支持自定义指令
directive(app)
// #endif
// 全局方法挂载
app.config.globalProperties.useDict = useDict
app.config.globalProperties.parseTime = parseTime
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.handleTree = handleTree
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.selectDictLabel = selectDictLabel
app.config.globalProperties.selectDictLabels = selectDictLabels
return {
app
}
}

72
manifest.json

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

11475
package-lock.json

File diff suppressed because it is too large

86
package.json

@ -0,0 +1,86 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",
"dev:app-ios": "uni -p app-ios",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:app-android": "uni build -p app-android",
"build:app-ios": "uni build -p app-ios",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
"type-check": "vue-tsc --noEmit",
"clean:linux": "rm -rf dist || rm -rf node_modules",
"clean:windows": "rd /s /q dist || rd /s /q node_modules"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4020420240722002",
"@dcloudio/uni-app-harmony": "3.0.0-4020420240722002",
"@dcloudio/uni-app-plus": "3.0.0-4020420240722002",
"@dcloudio/uni-components": "3.0.0-4020420240722002",
"@dcloudio/uni-h5": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-alipay": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-baidu": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-jd": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-lark": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-qq": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-toutiao": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-weixin": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-xhs": "3.0.0-4020420240722002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4020420240722002",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@qiun/wx-ucharts": "2.5.0-20230101",
"@uview-plus/types": "^3.2.5",
"clipboard": "^2.0.11",
"dayjs": "^1.11.13",
"mqtt": "4.1.0",
"pinia": "2.2.2",
"tslib": "^2.7.0",
"uview-plus": "^3.3.32",
"vue": "3.4.21",
"vue-i18n": "^10.0.1"
},
"devDependencies": {
"@dcloudio/types": "^3.4.14",
"@dcloudio/uni-automator": "3.0.0-4020420240722002",
"@dcloudio/uni-cli-shared": "3.0.0-4020420240722002",
"@dcloudio/uni-stacktracey": "3.0.0-4020420240722002",
"@dcloudio/vite-plugin-uni": "3.0.0-4020420240722002",
"@vue/runtime-core": "^3.5.5",
"@vue/tsconfig": "^0.5.1",
"less": "^4.2.0",
"sass": "^1.78.0",
"sass-loader": "^16.0.1",
"typescript": "^5.6.2",
"vite": "5.4.5",
"vue-tsc": "2.1.6"
}
}

280
pages.json

@ -0,0 +1,280 @@
{
"easycom": {
"custom": {
"u-city-select": "@/components/u-city-select/u-city-select.vue",
"geek-(.*)": "@/components/geek-xd/components/geek-$1/geek-$1.vue",
"gx-(.*)": "@/components/geek-xd/components/geek-$1/geek-$1.vue",
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue",
"qiun-(.*)": "@/components/qiun-data-charts/components/qiun-$1/qiun-$1.vue"
}
},
"pages": [
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "若依移动端框架",
"navigationStyle": "custom"
}
},
{
"path": "pages/login",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/work",
"style": {
"navigationBarTitleText": "工作台"
}
},
{
"path": "pages/template",
"style": {
"navigationBarTitleText": "模板"
}
},
{
"path": "pages/mine",
"style": {
"navigationBarTitleText": "我的"
}
},
{
"path": "pages/common/webview/index",
"style": {
"navigationBarTitleText": "浏览网页"
}
},
{
"path": "pages/common/textview/index",
"style": {
"navigationBarTitleText": "浏览文本"
}
}
],
"subPackages": [
{
"root": "pages_mine/pages",
"pages": [
{
"path": "avatar/index",
"style": {
"navigationBarTitleText": "修改头像"
}
},
{
"path": "info/index",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "info/edit",
"style": {
"navigationBarTitleText": "编辑资料"
}
},
{
"path": "pwd/index",
"style": {
"navigationBarTitleText": "修改密码"
}
},
{
"path": "setting/index",
"style": {
"navigationBarTitleText": "应用设置"
}
},
{
"path": "help/index",
"style": {
"navigationBarTitleText": "常见问题"
}
},
{
"path": "about/index",
"style": {
"navigationBarTitleText": "关于我们"
}
}
]
},
{
"root": "pages_template/pages",
"pages": [
{
"path": "wxCenter/index",
"style": {
"navigationBarTitleText": "wxCenter 仿微信个人中心",
"navigationStyle": "custom"
}
},
{
"path": "keyboardPay/index",
"style": {
"navigationBarTitleText": "keyboardPay 自定义键盘支付"
}
},
{
"path": "mallMenu/index2",
"style": {
"navigationBarTitleText": "mallMenu-商城分类"
}
},
{
"path": "mallMenu/index1",
"style": {
"navigationBarTitleText": "mallMenu-商城分类"
}
},
{
"path": "coupon/index",
"style": {
"navigationBarTitleText": "coupon-优惠券"
}
},
{
"path": "login/index1",
"style": {
"navigationBarTitleText": "美团登录"
}
},
{
"path": "login/index2",
"style": {
"navigationBarTitleText": "水滴登录"
}
},
{
"path": "citySelect/index",
"style": {
"navigationBarTitleText": "城市选择"
}
},
{
"path": "submitBar/index",
"style": {
"navigationBarTitleText": "提交订单栏"
}
},
{
"path": "comment/index",
"style": {
"navigationBarTitleText": "评论"
}
},
{
"path": "comment/reply",
"style": {
"navigationBarTitleText": "评论详情"
}
},
{
"path": "order/index",
"style": {
"navigationBarTitleText": "订单"
}
},
{
"path": "login/code",
"style": {
"navigationBarTitleText": "登录获取验证码"
}
},
{
"path": "address/index",
"style": {
"navigationBarTitleText": "用户地址"
}
},
{
"path": "address/addSite",
"style": {
"navigationBarTitleText": "添加用户地址"
}
}
]
},
{
"root": "pages_qiun/pages",
"pages": [
{
"path": "sport/index",
"style": {
"pageOrientation": "auto"
}
},
{
"path": "school/index",
"style": {
"pageOrientation": "auto"
}
},
{
"path": "finance/index",
"style": {
"pageOrientation": "auto"
}
},
{
"path": "main/index",
"style": {
"pageOrientation": "auto"
}
}
]
},
{
"root": "pages_geek/pages",
"pages": [
{
"path": "index/index"
},
{
"path": "code/index"
}
]
}
],
"tabBar": {
"color": "#000000",
"selectedColor": "#000000",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_.png",
"text": "首页"
},
{
"pagePath": "pages/work",
"iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png",
"text": "工作台"
},
{
"pagePath": "pages/template",
"iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png",
"text": "模板"
},
{
"pagePath": "pages/mine",
"iconPath": "static/images/tabbar/mine.png",
"selectedIconPath": "static/images/tabbar/mine_.png",
"text": "我的"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "RuoYi",
"navigationBarBackgroundColor": "#FFFFFF"
}
}

43
pages/common/textview/index.vue

@ -0,0 +1,43 @@
<template>
<view>
<uni-card class="view-title" :title="title">
<text class="uni-body view-content">{{ content }}</text>
</uni-card>
</view>
</template>
<script>
export default {
data() {
return {
title: '',
content: ''
}
},
onLoad(options) {
this.title = options.title
this.content = options.content
uni.setNavigationBarTitle({
title: options.title
})
}
}
</script>
<style scoped>
page {
background-color: #ffffff;
}
.view-title {
font-weight: bold;
}
.view-content {
font-size: 26rpx;
padding: 12px 5px 0;
color: #333;
line-height: 24px;
font-weight: normal;
}
</style>

34
pages/common/webview/index.vue

@ -0,0 +1,34 @@
<template>
<view v-if="params.url">
<web-view :webview-styles="webviewStyles" :src="`${params.url}`"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
params: {},
webviewStyles: {
progress: {
color: "#FF3333"
}
}
}
},
props: {
src: {
type: [String],
default: null
}
},
onLoad(event) {
this.params = event
if (event.title) {
uni.setNavigationBarTitle({
title: event.title
})
}
}
}
</script>

75
pages/index.vue

@ -0,0 +1,75 @@
<template>
<view class="content">
<image class="logo" src="@/static/logo.png"></image>
<view class="text-area">
<text class="title">Hello RuoYi-Vue</text>
</view>
<view class="text-area">
<up-text type="primary" text="uview-plus"></up-text>
</view>
<view class="charts-box">
<qiun-data-charts type="column" :chartData="chartData" />
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const chartData = ref({});
onMounted(() => { getServerData() });
function getServerData() {
//
setTimeout(() => {
let res = {
categories: ['2016', '2017', '2018', '2019', '2020', '2021'],
series: [
{
name: '目标值',
data: [35, 36, 31, 33, 13, 34],
},
{
name: '完成量',
data: [18, 27, 21, 24, 6, 28],
},
],
};
chartData.value = JSON.parse(JSON.stringify(res));
}, 500);
}
</script>
<style scoped>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.charts-box {
width: 100%;
height: 300px;
}
</style>

213
pages/login.vue

@ -0,0 +1,213 @@
<template>
<view class="normal-login-container">
<view class="logo-content align-center justify-center flex">
<image style="width: 100rpx;height: 100rpx;" src="/static/logo.png" mode="widthFix">
</image>
<text class="title">优品物联网卡登录</text>
</view>
<view class="login-form-content">
<view class="input-item flex align-center">
<view class="iconfont icon-user icon"></view>
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
</view>
<view class="input-item flex align-center">
<view class="iconfont icon-password icon"></view>
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
</view>
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
<view class="iconfont icon-code icon"></view>
<input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
<view class="login-code">
<image :src="codeUrl" @click="getCode" class="login-code-img"></image>
</view>
</view>
<view class="action-btn">
<button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button>
</view>
</view>
<view class="xieyi text-center">
<text class="text-grey1">登录即代表同意</text>
<text @click="handleUserAgrement" class="text-blue">用户协议</text>
<text @click="handlePrivacy" class="text-blue">隐私协议</text>
</view>
</view>
</template>
<script setup>
import modal from '@/plugins/modal'
import { getCodeImg } from '@/api/login'
import { ref } from "vue";
import config from '@/config.js'
import useUserStore from '@/store/modules/user'
import { getWxCode } from '@/utils/geek';
import { wxLogin } from '@/api/oauth';
import { setToken } from '@/utils/auth';
const userStore = useUserStore()
const codeUrl = ref("");
const captchaEnabled = ref(true); //
const useWxLogin = ref(false); // 使
const globalConfig = ref(config);
const loginForm = ref({
username: "admin",
password: "123456",
code: "",
uuid: '',
grantType: 'app',
tenantId: '000000',
clientId: '428a8310cd442757ae699df5d894f051',
});
if (useWxLogin.value) {
getWxCode().then(res => {
console.log(res);
wxLogin('miniapp',res).then(res => {
if(res.token != null){
setToken(res.token);
loginSuccess()
}
});
})
}
//
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled
if (captchaEnabled.value) {
codeUrl.value = 'data:image/gif;base64,' + res.data.img
loginForm.value.uuid = res.data.uuid
}
})
};
async function handleLogin() {
if (loginForm.value.username === "") {
modal.msgError("请输入您的账号")
} else if (loginForm.value.password === "") {
modal.msgError("请输入您的密码")
} else if (loginForm.value.code === "" && captchaEnabled.value) {
modal.msgError("请输入验证码")
} else {
modal.loading("登录中,请耐心等待...")
pwdLogin()
}
};
//
async function pwdLogin() {
userStore.login(loginForm.value).then(() => {
modal.closeLoading()
loginSuccess()
}).catch(() => {
if (captchaEnabled.value) {
modal.closeLoading()
getCode()
}
})
};
function loginSuccess(result) {
uni.switchTab({
url: '/pages/mine'
});
// //
// userStore.getInfo().then(res => {
// })
}
//
function handlePrivacy() {
let site = globalConfig.value.appInfo.agreements[0];
uni.navigateTo({
url: `/pages/common/webview/index?title=${site.title}&url=${site.url}`
});
};
//
function handleUserAgrement() {
let site = globalConfig.value.appInfo.agreements[1]
uni.navigateTo({
url: `/pages/common/webview/index?title=${site.title}&url=${site.url}`
});
};
getCode();
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.normal-login-container {
width: 100%;
.logo-content {
width: 100%;
font-size: 21px;
text-align: center;
padding-top: 15%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
}
}
.login-form-content {
text-align: center;
margin: 20px auto;
margin-top: 15%;
width: 80%;
.input-item {
margin: 20px auto;
background-color: #f5f6f7;
height: 45px;
border-radius: 20px;
.icon {
font-size: 38rpx;
margin-left: 10px;
color: #999;
}
.input {
width: 100%;
font-size: 14px;
line-height: 20px;
text-align: left;
padding-left: 15px;
}
}
.login-btn {
margin-top: 40px;
height: 45px;
}
.xieyi {
color: #333;
margin-top: 20px;
}
.login-code {
height: 38px;
float: right;
.login-code-img {
height: 38px;
position: absolute;
margin-left: 10px;
width: 200rpx;
}
}
}
}
</style>

242
pages/mine.vue

@ -0,0 +1,242 @@
<template>
<view class="mine-container" :style="{ height: `${windowHeight}px` }">
<!--顶部个人信息栏-->
<view class="header-section">
<view class="flex padding justify-between">
<view class="flex align-center">
<view v-if="!avatar" class="cu-avatar xl round bg-white">
<view class="iconfont icon-people text-gray icon"></view>
</view>
<image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix">
</image>
<view v-if="!name" @click="handleToLogin" class="login-tip">
点击登录
</view>
<view v-if="name" @click="handleToInfo" class="user-info">
<view class="u_title">
用户名{{ name }}
</view>
</view>
</view>
<view @click="handleToInfo" class="flex align-center">
<text>个人信息</text>
<view class="iconfont icon-right"></view>
</view>
</view>
</view>
<view class="content-section">
<view class="mine-actions grid col-4 text-center">
<view class="action-item" @click="handleJiaoLiuQun">
<view class="iconfont icon-friendfill text-pink icon"></view>
<text class="text">交流群</text>
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-service text-blue icon"></view>
<text class="text">在线客服</text>
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-community text-mauve icon"></view>
<text class="text">反馈社区</text>
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-dianzan text-green icon"></view>
<text class="text">点赞我们</text>
</view>
</view>
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleToEditInfo">
<view class="menu-item-box">
<view class="iconfont icon-user menu-icon"></view>
<view>编辑资料</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleHelp">
<view class="menu-item-box">
<view class="iconfont icon-help menu-icon"></view>
<view>常见问题</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleAbout">
<view class="menu-item-box">
<view class="iconfont icon-aixin menu-icon"></view>
<view>关于我们</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleToSetting">
<view class="menu-item-box">
<view class="iconfont icon-setting menu-icon"></view>
<view>应用设置</view>
</view>
</view>
</view>
</view>
</view>
<!-- <view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog type="info" cancelText="关闭" confirmText="退出"
title="通知" content="确定注销并退出系统吗"
@confirm="dialogConfirm"
@close="dialogClose">
</uni-popup-dialog>
</uni-popup>
</view> -->
</template>
<script setup>
import { ref } from "vue";
import { userBindRechargeNum,getRechargeNum ,getRealNameUrl, getGroupPackage, recharge} from '@/api/card'
import config from '@/config.js'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const name = userStore.name;
const version = config.appInfo.version;
const avatar = ref(userStore.avatar);
const windowHeight = ref(uni.getSystemInfoSync().windowHeight - 50);
const popup = ref(null);
uni.$on('refresh', () => {
avatar.value = userStore.avatar;
})
console.log(avatar.value)
function handleToInfo() {
uni.navigateTo({
url: '/pages_mine/pages/info/index'
});
};
function handleToEditInfo() {
uni.navigateTo({
url: '/pages_mine/pages/info/edit'
});
};
function handleToSetting() {
uni.navigateTo({
url: '/pages_mine/pages/setting/index'
});
};
function handleToLogin() {
uni.reLaunch({
url: '/pages/login'
});
};
function handleToAvatar() {
uni.navigateTo({
url: '/pages_mine/pages/avatar/index'
});
};
function handleLogout() {
popup.value.open();
};
function dialogConfirm() {
//console.log('----------------------------')
userStore.logOut().then(() => {
uni.reLaunch({
url: '/pages/login'
});
})
};
function dialogClose() {
//console.log('')
};
function handleHelp() {
uni.navigateTo({
url: '/pages_mine/pages/help/index'
});
};
function handleAbout() {
const data = {rechargeNum : '1442212701559'}
getRealNameUrl(data).then(res => {
console.log(res,9)
})
};
function handleJiaoLiuQun() {
const data = {rechargeNum : '1442212701559'}
const formData = new FormData();
// formData
formData.append('rechargeNum', data.rechargeNum);
userBindRechargeNum(data).then(res => {
console.log(res,9)
})
};
function handleBuilding() {
const data = {rechargeNum : '1442212701559'}
getRechargeNum(data).then(res => {
console.log(res,91)
})
}
</script>
<style lang="scss">
page {
background-color: #f5f6f7;
}
.mine-container {
width: 100%;
height: 100%;
.header-section {
padding: 15px 15px 45px 15px;
background-color: #3c96f3;
color: white;
.login-tip {
font-size: 18px;
margin-left: 10px;
}
.cu-avatar {
border: 2px solid #eaeaea;
.icon {
font-size: 40px;
}
}
.user-info {
margin-left: 15px;
.u_title {
font-size: 18px;
line-height: 30px;
}
}
}
.content-section {
position: relative;
top: -50px;
.mine-actions {
margin: 15px 15px;
padding: 20px 0px;
border-radius: 8px;
background-color: white;
.action-item {
.icon {
font-size: 28px;
}
.text {
display: block;
font-size: 13px;
margin: 8px 0px;
}
}
}
}
}
</style>

131
pages/template.config.js

@ -0,0 +1,131 @@
export default [
{
groupName: 'geek组件',
groupName_en: 'Page',
list: [
{
path: '/pages_geek/pages/index/index',
icon: 'wxCenter',
title: '组件展示',
title_en: 'index',
},
{
path: '/pages_geek/pages/code/index',
icon: 'wxCenter',
title: '二维码',
title_en: 'index',
}
]
},
{
groupName: '部件',
groupName_en: 'Parts',
list: [
{
path: '/pages_template/pages/coupon/index',
icon: 'coupon',
title: 'Coupon 优惠券',
title_en: 'Coupon',
},
{
path: '/pages_template/pages/citySelect/index',
icon: 'citySelect',
title: 'CitySelect 城市选择',
title_en: 'CitySelect',
},
{
path: '/pages_template/pages/submitBar/index',
icon: 'submitBar',
title: 'SubmitBar 提交订单栏',
title_en: 'SubmitBar',
},
{
path: '/pages_template/pages/keyboardPay/index',
icon: 'keyboardPay',
title: 'KeyboardPay 自定义键盘支付模板',
title_en: 'KeyboardPay',
},
]
},
{
groupName: '报表',
groupName_en: 'Parts',
list: [
{
path: '/pages_qiun/pages/finance/index',
icon: 'coupon',
title: '财务报告',
title_en: 'finace',
},
{
path: '/pages_qiun/pages/main/index',
icon: 'coupon',
title: '数据报表中心',
title_en: 'main',
},
{
path: '/pages_qiun/pages/school/index',
icon: 'coupon',
title: '智慧教育报表中心',
title_en: 'school',
},
{
path: '/pages_qiun/pages/sport/index',
icon: 'coupon',
title: '运动报告',
title_en: 'sport',
},
]
},
{
groupName: '页面',
groupName_en: 'Page',
list: [
{
path: '/pages_template/pages/wxCenter/index',
icon: 'wxCenter',
title: 'WxCenter 仿微信个人中心',
title_en: 'WxCenter',
},
{
path: '/pages_template/pages/mallMenu/index1',
icon: 'mall_menu_1',
title: 'MallMenu 垂直分类(左右独立)',
title_en: 'MallMenu 1',
}, {
path: '/pages_template/pages/mallMenu/index2',
icon: 'mall_menu_2',
title: 'MallMenu 垂直分类(左右联动)',
title_en: 'MallMenu 2',
}, {
path: '/pages_template/pages/comment/index',
icon: 'comment',
title: 'Comment 评论列表',
title_en: 'Comment',
}, {
path: '/pages_template/pages/order/index',
icon: 'order',
title: 'Order 订单列表',
title_en: 'Order',
},
{
path: '/pages_template/pages/login/index1',
icon: 'login',
title: 'Login 登录界面',
title_en: 'Login',
},
{
path: '/pages_template/pages/login/index2',
icon: 'login',
title: 'Login 水滴登录',
title_en: 'Login',
},
{
path: '/pages_template/pages/address/index',
icon: 'address',
title: 'Address 收货地址',
title_en: 'Address',
},
]
},
]

65
pages/template.vue

@ -0,0 +1,65 @@
<template>
<view class="wrap">
<view class="list-wrap">
<u-cell-group title-bg-color="rgb(243, 244, 246)" :title="getGroupTitle(item)" v-for="(item, index) in list"
:key="index">
<u-cell :titleStyle="{ fontWeight: 500 }" @click="openPage(item1.path)" :title="getFieldTitle(item1)"
v-for="(item1, index1) in item.list" :key="index1">
<template v-slot:icon>
<image class="u-cell-icon" :src="getIcon(item1.icon)" mode="widthFix"></image>
</template>
</u-cell>
</u-cell-group>
</view>
<u-gap height="70"></u-gap>
<!-- <u-tabbar :list="vuex_tabbar" :mid-button="true"></u-tabbar> -->
</view>
</template>
<script>
import list from "./template.config.js";
export default {
data() {
return {
list: list,
// desc: ''
}
},
computed: {
getIcon() {
return path => {
return '../static/uview/demo/' + path + '.png';
return 'https://cdn.uviewui.com/uview/example/' + path + '.png';
}
},
},
methods: {
openPage(path) {
this.$u.route({
url: path
})
},
getGroupTitle(item) {
return item.groupName
},
getFieldTitle(item) {
return item.title
}
}
}
</script>
<style>
/* page {
background-color: rgb(240, 242, 244);
} */
</style>
<style lang="scss" scoped>
.u-cell-icon {
width: 36rpx;
height: 36rpx;
margin-right: 8rpx;
}
</style>

184
pages/work.vue

@ -0,0 +1,184 @@
<template>
<view class="work-container">
<!-- 轮播图 -->
<uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">
<swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">
<swiper-item v-for="(item, index) in data" :key="index">
<view class="swiper-item" @click="clickBannerItem(item)">
<image :src="item.image" mode="aspectFill" :draggable="false" />
</view>
</swiper-item>
</swiper>
</uni-swiper-dot>
<!-- 宫格组件 -->
<uni-section title="系统管理" type="line"></uni-section>
<view class="grid-body">
<uni-grid :column="4" :showBorder="false" @change="changeGrid">
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="person-filled" size="30"></uni-icons>
<text class="text">用户管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="staff-filled" size="30"></uni-icons>
<text class="text">角色管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="color" size="30"></uni-icons>
<text class="text">菜单管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="settings-filled" size="30"></uni-icons>
<text class="text">部门管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="heart-filled" size="30"></uni-icons>
<text class="text">岗位管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="bars" size="30"></uni-icons>
<text class="text">字典管理</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="gear-filled" size="30"></uni-icons>
<text class="text">参数设置</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="chat-filled" size="30"></uni-icons>
<text class="text">通知公告</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="wallet-filled" size="30"></uni-icons>
<text class="text">日志管理</text>
</view>
</uni-grid-item>
</uni-grid>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
import modal from "@/plugins/modal"
const current=ref(0);
const swiperDotIndex=ref(0);
const data=ref([{
image: '/static/images/banner/banner01.jpg'
},
{
image: '/static/images/banner/banner02.jpg'
},
{
image: '/static/images/banner/banner03.jpg'
}
]);
function clickBannerItem(item) {
console.info(item)
};
function changeSwiper(e) {
current.value = e.detail.current
}
function changeGrid(e) {
modal.showToast({
title: '模块建设中',
mask: false,
icon:'loading',
duration: 1000
});
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #fff;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.text {
text-align: center;
font-size: 26rpx;
margin-top: 10rpx;
}
.grid-item-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
padding: 15px 0;
}
.uni-margin-wrap {
width: 690rpx;
width: 100%;
;
}
.swiper {
height: 300rpx;
}
.swiper-box {
height: 150px;
}
.swiper-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
height: 300rpx;
line-height: 300rpx;
}
@media screen and (min-width: 500px) {
.uni-swiper-dot-box {
width: 400px;
/* #ifndef APP-NVUE */
margin: 0 auto;
/* #endif */
margin-top: 8px;
}
.image {
width: 100%;
}
}
</style>

130
pages_geek/pages/code/index.vue

@ -0,0 +1,130 @@
<template xlang="wxml">
<view class="container">
<view class="qrimg">
<view class="qrimg-i">
<geek-qrcode v-if="ifShow" cid="qrcode1" ref="qrcode" :val="val" :size="size" :unit="unit"
:background="background" :foreground="foreground" :pdground="pdground" :icon="icon" :iconSize="iconsize"
:lv="lv" :onval="onval" :loadMake="loadMake" :usingComponents="true" @result="qrR" />
</view>
<view class="qrimg-i">
<geek-qrcode v-if="ifShow" cid="qrcode2" ref="qrcode2" val="第二个二维码" :size="size" :onval="onval"
:loadMake="loadMake" :usingComponents="true" @result="qrR" />
</view>
</view>
<view class="uni-padding-wrap">
<view class="uni-title">请输入要生成的二维码内容</view>
</view>
<view class="uni-list">
<input class="uni-input" placeholder="请输入要生成的二维码内容" v-model="val" />
</view>
<view class="uni-padding-wrap uni-common-mt">
<view class="uni-title">设置二维码大小</view>
</view>
<view class="body-view">
<slider :value="size" @change="sliderchange" min="50" max="500" show-value />
</view>
<view class="uni-padding-wrap">
<view class="btns">
<button type="primary" @tap="selectIcon">选择二维码图标</button>
<button type="primary" @tap="creatQrcode">生成二维码</button>
<button type="primary" @tap="saveQrcode">保存到图库</button>
<button type="warn" @tap="clearQrcode">清除二维码</button>
<button type="warn" @tap="ifQrcode">显示隐藏二维码</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
ifShow: true,
val: '二维码', //
size: 200, //
unit: 'upx', //
background: '#b4e9e2', //
foreground: '#309286', //
pdground: '#32dbc6', //
icon: '', //
iconsize: 40, //
lv: 3, //
onval: false, // val
loadMake: true, //
src: '' // base64
}
},
methods: {
sliderchange(e) {
this.size = e.detail.value
},
creatQrcode() {
this.$refs.qrcode._makeCode()
},
saveQrcode() {
this.$refs.qrcode._saveCode()
},
qrR(res) {
this.src = res
},
clearQrcode() {
this.$refs.qrcode._clearCode()
this.val = ''
},
ifQrcode() {
this.ifShow = !this.ifShow
},
selectIcon() {
let that = this
uni.chooseImage({
count: 1, //9
sizeType: ['original', 'compressed'], //
sourceType: ['album'], //
success: function (res) {
that.icon = res.tempFilePaths[0]
setTimeout(() => {
that.creatQrcode()
}, 100);
// console.log(res.tempFilePaths);
}
});
}
}
}
</script>
<style>
/* @import "../../../common/icon.css"; */
.container {
display: flex;
flex-direction: column;
width: 100%;
}
.qrimg {
display: flex;
justify-content: center;
}
.qrimg-i {
margin-right: 10px;
}
slider {
width: 100%;
}
input {
width: 100%;
margin-bottom: 20upx;
}
.btns {
display: flex;
flex-direction: column;
width: 100%;
}
button {
width: 100%;
margin-top: 10upx;
}</style>

120
pages_geek/pages/index/index.vue

@ -0,0 +1,120 @@
<template>
<uni-section class="mb-10" title="数值板" sub-title="statistic" type="line"></uni-section>
<u-row gutter="0">
<u-col span="6">
<geek-statistic label="订单数量(个)" labelColor="#1f1f1f" :number="0" numberColor="red" />
</u-col>
<u-col span="6">
<geek-statistic label="交易金额(元)" labelColor="#1f1f1f" :number="0" numberColor="red" />
</u-col>
</u-row>
<uni-section class="mb-10" title="菜单" sub-title="menu" type="line"></uni-section>
<u-row>
<u-col :span="2.1" :offset="0.3" v-for="menu, index in menus" :key="index">
<geek-menu v-bind=menu :size="60" @click="modal.msg(menu.label)" type="circle" />
</u-col>
</u-row>
<u-row>
<u-col :span="2.1" :offset="0.3" v-for="menu, index in menus" :key="index">
<geek-menu :icon="menu.icon" :label="menu.label" :size="60" @click="modal.msg(menu.label)" type="rect" />
</u-col>
</u-row>
<uni-section class="mb-10" title="商品列表" sub-title="commodity" type="line"></uni-section>
<geek-commodity v-for="item, index in commodityList" :key="index" v-bind="item" type="line"
@click="modal.msg(item.title)" />
<geek-commodity v-for="item, index in commodityList" :key="index" v-bind="item" type="rect"
@click="modal.msg(item.title)" />
<uni-section class="mb-10" title="订单列表" sub-title="order" type="line"></uni-section>
<geek-order v-for="item, index in orderList" :key="index" v-bind="item" @more="modal.msg('更多')"
@again="modal.msg('再次购买')" @return="modal.msg('退换')" @sell="modal.msg('卖了换钱')"></geek-order>
<uni-section class="mb-10" title="颜色选择器" sub-title="order" type="line"></uni-section>
<geek-color-picker ref="gk" @confirm="getcolor"></geek-color-picker>
<button @click="open()">打开颜色选择器</button>
<uni-section class="mb-10" title="二维码" sub-title="order" type="line"></uni-section>
<geek-qrcode cid="qrcode2" ref="qrcode2" val="二维码" :loadMake="true" />
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import modal from '@/plugins/modal'
import { Commodity, CommodityOrder, Menu } from "@/components/geek-xd/types"
const gk = ref(null)
function open() {
//@ts-ignore
gk.value.open()
}
function getcolor(color: { hex: string, rgba: { r: number, g: number, b: number, a: number } }) {
console.log(color)
}
const menus: Array<Menu> = reactive([
{ icon: "/static/images/icon/rocket.png", label: '抢单' },
{ icon: "/static/images/icon/phone.png", label: '回访' },
{ icon: "/static/images/icon/message.png", label: '消息' },
{ icon: "/static/images/icon/dialogue.png", label: '公告' },
{ icon: "/static/images/icon/knowledge.png", label: '知识库' }
]);
const commodityList: Array<Commodity> = reactive([
{
img: '/static/images/banner/banner01.jpg',
title: '商品1',
subTitle: '商品1简介',
price: 100,
},
{
img: '/static/images/banner/banner02.jpg',
title: '商品2',
subTitle: '商品2简介',
price: 300,
},
{
img: '/static/images/banner/banner03.jpg',
title: '商品3',
subTitle: '商品3简介',
price: 200,
}
])
const orderList: Array<CommodityOrder> = [
{
shop: 'geek自营旗舰店',
status: '完成',
img: '/static/images/banner/banner01.jpg',
title: '商品1',
label: '商品1简介',
price: 100.32,
num: 10
},
{
shop: 'geek自营旗舰店',
status: '已取消',
img: '/static/images/banner/banner03.jpg',
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
label: '商品3简介',
price: 2000.67,
num: 10
},
{
shop: 'geek自营旗舰店',
status: '已取消',
img: '/static/images/banner/banner03.jpg',
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
label: '商品3简介',
price: 10.67,
num: 10
}
]
</script>
<style lang="scss" scoped></style>

71
pages_mine/pages/about/index.vue

@ -0,0 +1,71 @@
<template>
<view class="about-container">
<view class="header-section text-center">
<image style="width: 150rpx;height: 150rpx;" src="/static/logo200.png" mode="widthFix">
</image>
<uni-title type="h2" title="若依移动端"></uni-title>
</view>
<view class="content-section">
<view class="menu-list">
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>版本信息</view>
<view class="text-right">v{{version}}</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>官方邮箱</view>
<view class="text-right">ruoyi@xx.com</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>服务热线</view>
<view class="text-right">400-999-9999</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>公司网站</view>
<view class="text-right">
<uni-link :href="url" :text="url" showUnderLine="false"></uni-link>
</view>
</view>
</view>
</view>
</view>
<view class="copyright">
<view>Copyright &copy; 2022 ruoyi.vip All Rights Reserved.</view>
</view>
</view>
</template>
<script setup>
import config from '@/config.js'
const url=config.appInfo.site_url;
const version=config.appInfo.version;
</script>
<style lang="scss">
page {
background-color: #f8f8f8;
}
.copyright {
margin-top: 50rpx;
text-align: center;
line-height: 60rpx;
color: #999;
}
.header-section {
display: flex;
padding: 30rpx 0 0;
flex-direction: column;
align-items: center;
}
</style>

642
pages_mine/pages/avatar/index.vue

@ -0,0 +1,642 @@
<template>
<view class="container">
<view class="page-body uni-content-info">
<view class='cropper-content'>
<view v-if="isShowImg" class="uni-corpper"
:style="'width:' + cropperInitW + 'px;height:' + cropperInitH + 'px;background:#000'">
<view class="uni-corpper-content"
:style="'width:' + cropperW + 'px;height:' + cropperH + 'px;left:' + cropperL + 'px;top:' + cropperT + 'px'">
<image :src="imageSrc" :style="'width:' + cropperW + 'px;height:' + cropperH + 'px'"></image>
<view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove"
@touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd"
:style="'left:' + cutL + 'px;top:' + cutT + 'px;right:' + cutR + 'px;bottom:' + cutB + 'px'">
<view class="uni-cropper-view-box">
<view class="uni-cropper-dashed-h"></view>
<view class="uni-cropper-dashed-v"></view>
<view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-tr" data-drag="topTight"></view>
<view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-rb" data-drag="rightBottom"
@touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart"
@touchmove.stop="dragMove" @touchend.stop="dragEnd"></view>
<view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view>
<view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart"
@touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-lt" data-drag="leftTop"></view>
</view>
</view>
</view>
</view>
</view>
<view class='cropper-config'>
<button type="primary reverse" @click="getImage" style='margin-top: 30rpx;'> 选择头像 </button>
<button type="warn" @click="getImageInfo" style='margin-top: 30rpx;'> 提交 </button>
</view>
<canvas canvas-id="myCanvas"
:style="'position:absolute;border: 1px solid red; width:' + imageW + 'px;height:' + imageH + 'px;top:-9999px;left:-9999px;'"></canvas>
</view>
</view>
</template>
<script>
import config from '@/config'
import { uploadAvatar } from "@/api/system/user"
import useUserStore from '@/store/modules/user'
const baseUrl = config.baseUrl
let sysInfo = uni.getSystemInfoSync()
let SCREEN_WIDTH = sysInfo.screenWidth
let PAGE_X, // x
PAGE_Y, // y
PR = sysInfo.pixelRatio, // dpi
T_PAGE_X, // x
T_PAGE_Y, // Y
CUT_L, // left
CUT_T, // top
CUT_R, //
CUT_B, //
CUT_W, //
CUT_H, //
IMG_RATIO, //
IMG_REAL_W, //
IMG_REAL_H, //
DRAFG_MOVE_RATIO = 1, //,
INIT_DRAG_POSITION = 100, //
DRAW_IMAGE_W = sysInfo.screenWidth //
export default {
/**
* 页面的初始数据
*/
data() {
return {
imageSrc: useUserStore().avatar,
isShowImg: false,
//
cropperInitW: SCREEN_WIDTH,
cropperInitH: SCREEN_WIDTH,
//
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH,
// left top
cropperL: 0,
cropperT: 0,
transL: 0,
transT: 0,
//
scaleP: 0,
imageW: 0,
imageH: 0,
//
cutL: 0,
cutT: 0,
cutB: SCREEN_WIDTH,
cutR: '100%',
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: DRAFG_MOVE_RATIO
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
this.loadImage()
},
methods: {
setData: function (obj) {
let that = this
Object.keys(obj).forEach(function (key) {
that.$set(that.$data, key, obj[key])
})
},
getImage: function () {
var _this = this
uni.chooseImage({
success: function (res) {
_this.setData({
imageSrc: res.tempFilePaths[0],
})
_this.loadImage()
},
})
},
loadImage: function () {
var _this = this
uni.getImageInfo({
src: _this.imageSrc,
success: function success(res) {
IMG_RATIO = 1 / 1
if (IMG_RATIO >= 1) {
IMG_REAL_W = SCREEN_WIDTH
IMG_REAL_H = SCREEN_WIDTH / IMG_RATIO
} else {
IMG_REAL_W = SCREEN_WIDTH * IMG_RATIO
IMG_REAL_H = SCREEN_WIDTH
}
let minRange = IMG_REAL_W > IMG_REAL_H ? IMG_REAL_W : IMG_REAL_H
INIT_DRAG_POSITION = minRange > INIT_DRAG_POSITION ? INIT_DRAG_POSITION : minRange
//
if (IMG_RATIO >= 1) {
let cutT = Math.ceil((SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - INIT_DRAG_POSITION)) / 2)
let cutB = cutT
let cutL = Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH + INIT_DRAG_POSITION) / 2)
let cutR = cutL
_this.setData({
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH / IMG_RATIO,
// left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
//
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
} else {
let cutL = Math.ceil((SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO)) / 2)
let cutR = cutL
let cutT = Math.ceil((SCREEN_WIDTH - INIT_DRAG_POSITION) / 2)
let cutB = cutT
_this.setData({
cropperW: SCREEN_WIDTH * IMG_RATIO,
cropperH: SCREEN_WIDTH,
// left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
//
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
}
_this.setData({
isShowImg: true
})
uni.hideLoading()
}
})
},
// touchStart
contentStartMove(e) {
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
// touchMove
contentMoveing(e) {
var _this = this
var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
//
if (dragLengthX > 0) {
if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL
} else {
if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR
}
if (dragLengthY > 0) {
if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT
} else {
if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB
}
this.setData({
cutL: this.cutL - dragLengthX,
cutT: this.cutT - dragLengthY,
cutR: this.cutR + dragLengthX,
cutB: this.cutB + dragLengthY
})
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
contentTouchEnd() {
},
//
getImageInfo() {
var _this = this
uni.showLoading({
title: '图片生成中...',
})
//
const ctx = uni.createCanvasContext('myCanvas')
ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H)
ctx.draw(true, () => {
// * canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W
var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H
var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W
var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H
uni.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW,
destHeight: canvasH,
quality: 0.5,
canvasId: 'myCanvas',
success: function (res) {
uni.hideLoading()
let data = { name: 'avatarfile', filePath: res.tempFilePath }
uploadAvatar(data).then(response => {
// userStore.avatar = response.imgUrl
/*cloud*/
useUserStore().avatar = baseUrl + response.imgUrl
uni.showToast({ title: "修改成功", icon: 'success' })
uni.$emit('refresh');
uni.navigateBack();
})
}
})
})
},
// touchStart
dragStart(e) {
T_PAGE_X = e.touches[0].pageX
T_PAGE_Y = e.touches[0].pageY
CUT_L = this.cutL
CUT_R = this.cutR
CUT_B = this.cutB
CUT_T = this.cutT
},
// touchMove
dragMove(e) {
var _this = this
var dragType = e.target.dataset.drag
switch (dragType) {
case 'right':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_R + dragLength < 0) dragLength = -CUT_R
this.setData({
cutR: CUT_R + dragLength
})
break
case 'left':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_L - dragLength < 0) dragLength = CUT_L
if ((CUT_L - dragLength) > (this.cropperW - this.cutR)) dragLength = CUT_L - (this.cropperW - this.cutR)
this.setData({
cutL: CUT_L - dragLength
})
break
case 'top':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_T - dragLength < 0) dragLength = CUT_T
if ((CUT_T - dragLength) > (this.cropperH - this.cutB)) dragLength = CUT_T - (this.cropperH - this.cutB)
this.setData({
cutT: CUT_T - dragLength
})
break
case 'bottom':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLength < 0) dragLength = -CUT_B
this.setData({
cutB: CUT_B + dragLength
})
break
case 'rightBottom':
var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B
if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R
let cutB = CUT_B + dragLengthY
let cutR = CUT_R + dragLengthX
this.setData({
cutB: cutB,
cutR: cutR
})
break
default:
break
}
}
}
}
</script>
<style>
/* pages/uni-cropper/index.wxss */
.cropper-config {
padding: 20rpx 40rpx;
}
.cropper-content {
min-height: 750rpx;
width: 100%;
}
.uni-corpper {
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
box-sizing: border-box;
}
.uni-corpper-content {
position: relative;
}
.uni-corpper-content image {
display: block;
width: 100%;
min-width: 0 !important;
max-width: none !important;
height: 100%;
min-height: 0 !important;
max-height: none !important;
image-orientation: 0deg !important;
margin: 0 auto;
}
/* 移动图片效果 */
.uni-cropper-drag-box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: move;
background: rgba(0, 0, 0, 0.6);
z-index: 1;
}
/* 内部的信息 */
.uni-corpper-crop-box {
position: absolute;
background: rgba(255, 255, 255, 0.3);
z-index: 2;
}
.uni-corpper-crop-box .uni-cropper-view-box {
position: relative;
display: block;
width: 100%;
height: 100%;
overflow: visible;
outline: 1rpx solid #69f;
outline-color: rgba(102, 153, 255, .75)
}
/* 横向虚线 */
.uni-cropper-dashed-h {
position: absolute;
top: 33.33333333%;
left: 0;
width: 100%;
height: 33.33333333%;
border-top: 1rpx dashed rgba(255, 255, 255, 0.5);
border-bottom: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 纵向虚线 */
.uni-cropper-dashed-v {
position: absolute;
left: 33.33333333%;
top: 0;
width: 33.33333333%;
height: 100%;
border-left: 1rpx dashed rgba(255, 255, 255, 0.5);
border-right: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 四个方向的线 为了之后的拖动事件*/
.uni-cropper-line-t {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
top: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: n-resize;
}
.uni-cropper-line-t::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-r {
position: absolute;
display: block;
background-color: #69f;
top: 0;
right: 0rpx;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: e-resize;
}
.uni-cropper-line-r::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-line-b {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
bottom: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: s-resize;
}
.uni-cropper-line-b::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-l {
position: absolute;
display: block;
background-color: #69f;
top: 0;
left: 0;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: w-resize;
}
.uni-cropper-line-l::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-point {
width: 5rpx;
height: 5rpx;
background-color: #69f;
opacity: .75;
position: absolute;
z-index: 3;
}
.point-t {
top: -3rpx;
left: 50%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-tr {
top: -3rpx;
left: 100%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-r {
top: 50%;
left: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-rb {
left: 100%;
top: 100%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
cursor: n-resize;
width: 36rpx;
height: 36rpx;
background-color: #69f;
position: absolute;
z-index: 1112;
opacity: 1;
}
.point-b {
left: 50%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-bl {
left: 0%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-l {
left: 0%;
top: 50%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-lt {
left: 0%;
top: 0%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
/* 裁剪框预览内容 */
.uni-cropper-viewer {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.uni-cropper-viewer image {
position: absolute;
z-index: 2;
}
</style>

109
pages_mine/pages/help/index.vue

@ -0,0 +1,109 @@
<template>
<view class="help-container">
<view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title">
<view class="text-title">
<view :class="item.icon"></view>{{ item.title }}
</view>
<view class="childList">
<view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover"
@click="handleText(child)">
<view class="text-item">{{ child.title }}</view>
<view class="line" v-if="zindex !== item.childList.length - 1"></view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
const list =ref([{
icon: 'iconfont icon-github',
title: '若依问题',
childList: [{
title: '若依开源吗?',
content: '开源'
}, {
title: '若依可以商用吗?',
content: '可以'
}, {
title: '若依官网地址多少?',
content: 'http://ruoyi.vip'
}, {
title: '若依文档地址多少?',
content: 'http://doc.ruoyi.vip'
}]
},
{
icon: 'iconfont icon-help',
title: '其他问题',
childList: [{
title: '如何退出登录?',
content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录',
}, {
title: '如何修改用户头像?',
content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像',
}, {
title: '如何修改登录密码?',
content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码',
}]
}
])
function handleText(item) {
uni.navigateTo({
url: `/pages/common/textview/index?title=${item.title}&content=${item.content}`
});
}
</script>
<style lang="scss" scoped>
page {
background-color: #f8f8f8;
}
.help-container {
margin-bottom: 100rpx;
padding: 30rpx;
}
.list-title {
margin-bottom: 30rpx;
}
.childList {
background: #ffffff;
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
border-radius: 16rpx;
margin-top: 10rpx;
}
.line {
width: 100%;
height: 1rpx;
background-color: #F5F5F5;
}
.text-title {
color: #303133;
font-size: 32rpx;
font-weight: bold;
margin-left: 10rpx;
.iconfont {
font-size: 16px;
margin-right: 10rpx;
}
}
.text-item {
font-size: 28rpx;
padding: 24rpx;
}
.question {
color: #606266;
font-size: 28rpx;
}
</style>

132
pages_mine/pages/info/edit.vue

@ -0,0 +1,132 @@
<template>
<view class="container">
<view class="example">
<uni-forms ref="form" :model="user" labelWidth="80px">
<uni-forms-item label="用户昵称" name="nickName">
<uni-easyinput v-model="user.nickName" placeholder="请输入昵称" />
</uni-forms-item>
<uni-forms-item label="手机号码" name="phonenumber">
<uni-easyinput v-model="user.phonenumber" placeholder="请输入手机号码" />
</uni-forms-item>
<uni-forms-item label="邮箱" name="email">
<uni-easyinput v-model="user.email" placeholder="请输入邮箱" />
</uni-forms-item>
<uni-forms-item label="性别" name="sex" required>
<uni-data-checkbox v-model="user.sex" :localdata="sexs" />
</uni-forms-item>
</uni-forms>
<button type="primary" @click="submit">提交</button>
</view>
</view>
</template>
<script>
import { getUserProfile } from "@/api/system/user"
import { updateUserProfile } from "@/api/system/user"
export default {
data() {
return {
user: {
nickName: "",
phonenumber: "",
email: "",
sex: ""
},
sexs: [{
text: '男',
value: "0"
}, {
text: '女',
value: "1"
}],
rules: {
nickName: {
rules: [{
required: true,
errorMessage: '用户昵称不能为空'
}]
},
phonenumber: {
rules: [{
required: true,
errorMessage: '手机号码不能为空'
}, {
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
errorMessage: '请输入正确的手机号码'
}]
},
email: {
rules: [{
required: true,
errorMessage: '邮箱地址不能为空'
}, {
format: 'email',
errorMessage: '请输入正确的邮箱地址'
}]
}
}
}
},
onLoad() {
this.getUser()
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
getUser() {
getUserProfile().then(response => {
this.user = response.data
})
},
submit(ref) {
this.$refs.form.validate().then(res => {
updateUserProfile(this.user).then(response => {
uni.showToast({
title: '修改成功',
mask: false,
duration: 1000
});
uni.navigateBack();
})
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.example {
padding: 15px;
background-color: #fff;
}
.segmented-control {
margin-bottom: 15px;
}
.button-group {
margin-top: 15px;
display: flex;
justify-content: space-around;
}
.form-item {
display: flex;
align-items: center;
flex: 1;
}
.button {
display: flex;
align-items: center;
height: 35px;
line-height: 35px;
margin-left: 10px;
}
</style>

53
pages_mine/pages/info/index.vue

@ -0,0 +1,53 @@
<template>
<view class="container">
<uni-list>
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'person-filled' }" title="昵称" :rightText="user.nickName" />
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'phone-filled' }" title="手机号码"
:rightText="user.phonenumber" />
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'email-filled' }" title="邮箱" :rightText="user.email" />
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'auth-filled' }" title="岗位" :rightText="postGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'staff-filled' }" title="角色" :rightText="roleGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{ type: 'calendar-filled' }" title="创建日期"
:rightText="user.createTime" />
</uni-list>
<u-button @click="register()">绑定微信</u-button>
</view>
</template>
<script setup>
import { getUserProfile } from "@/api/system/user"
import { ref } from "vue";
import modal from "@/plugins/modal"
const user = ref({})
const roleGroup = ref("")
const postGroup = ref("")
function getUser() {
getUserProfile().then(response => {
user.value = response.data
roleGroup.value = response.roleGroup
postGroup.value = response.postGroup
})
}
getUser()
import { wxRegister } from "@/api/oauth"
import { getWxCode } from "@/utils/geek"
function register(){
modal.loading('绑定微信中...')
getWxCode().then(res=>{
wxRegister('miniapp',res).then(res=>{
modal.closeLoading()
})
})
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
</style>

91
pages_mine/pages/pwd/index.vue

@ -0,0 +1,91 @@
<template>
<view class="pwd-retrieve-container">
<uni-forms ref="form" :value="user" labelWidth="80px">
<uni-forms-item name="oldPassword" label="旧密码">
<uni-easyinput type="password" v-model="user.oldPassword" placeholder="请输入旧密码" />
</uni-forms-item>
<uni-forms-item name="newPassword" label="新密码">
<uni-easyinput type="password" v-model="user.newPassword" placeholder="请输入新密码" />
</uni-forms-item>
<uni-forms-item name="confirmPassword" label="确认密码">
<uni-easyinput type="password" v-model="user.confirmPassword" placeholder="请确认新密码" />
</uni-forms-item>
<button type="primary" @click="submit">提交</button>
</uni-forms>
</view>
</template>
<script>
import { updateUserPwd } from "@/api/system/user"
export default {
data() {
return {
user: {
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
},
rules: {
oldPassword: {
rules: [{
required: true,
errorMessage: '旧密码不能为空'
}]
},
newPassword: {
rules: [{
required: true,
errorMessage: '新密码不能为空',
},
{
minLength: 6,
maxLength: 20,
errorMessage: '长度在 6 到 20 个字符'
}
]
},
confirmPassword: {
rules: [{
required: true,
errorMessage: '确认密码不能为空'
}, {
validateFunction: (rule, value, data) => data.newPassword === value,
errorMessage: '两次输入的密码不一致'
}
]
}
}
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
submit() {
this.$refs.form.validate().then(res => {
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
uni.showToast({
title: '修改成功',
mask: false,
duration: 1000
});
uni.navigateBack();
})
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.pwd-retrieve-container {
padding-top: 36rpx;
padding: 15px;
}
</style>

104
pages_mine/pages/setting/index.vue

@ -0,0 +1,104 @@
<template>
<view class="setting-container" :style="{ height: `${windowHeight}px` }">
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleToPwd">
<view class="menu-item-box">
<view class="iconfont icon-password menu-icon"></view>
<view>修改密码</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleToUpgrade">
<view class="menu-item-box">
<view class="iconfont icon-refresh menu-icon"></view>
<view>检查更新</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleCleanTmp">
<view class="menu-item-box">
<view class="iconfont icon-clean menu-icon"></view>
<view>清理缓存</view>
</view>
</view>
</view>
<view class="cu-list menu">
<view class="cu-item item-box">
<view class="content text-center" @click="handleLogout">
<text class="text-black">退出登录</text>
</view>
</view>
</view>
</view>
<view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog type="info" cancelText="关闭" confirmText="退出" title="通知" content="确定注销并退出系统吗"
@confirm="dialogConfirm" @close="dialogClose">
</uni-popup-dialog>
</uni-popup>
</view>
</template>
<script setup>
import { ref } from "vue";
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const windowHeight = ref(uni.getSystemInfoSync().windowHeight);
const popup = ref(null);
function handleToPwd() {
uni.navigateTo({
url: '/pages/mine/pwd/index'
});
};
function handleToUpgrade() {
uni.showToast({
title: '模块建设中~',
mask: false,
icon: "none",
duration: 1000
});
};
function handleCleanTmp() {
uni.showToast({
title: '模块建设中~',
mask: false,
icon: "none",
duration: 1000
});
};
function handleLogout() {
popup.value.open();
};
function dialogConfirm() {
//console.log('----------------------------')
userStore.logOut().then(() => {
uni.reLaunch({
url: '/pages/login'
});
})
};
function dialogClose() {
//console.log('')
};
</script>
<style lang="scss" scoped>
.page {
background-color: #f8f8f8;
}
.item-box {
background-color: #FFFFFF;
margin: 30rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 10rpx;
border-radius: 8rpx;
color: #303133;
font-size: 32rpx;
}
</style>

148
pages_qiun/components/card-swiper/card-swiper.vue

@ -0,0 +1,148 @@
<template>
<view>
<view class="top-swiper">
<view class="box">
<view style="height: 44px;"></view>
<swiper class="swiper" :previous-margin="swiper.margin" :next-margin='swiper.margin' :circular="true"
@change="swiperChange">
<swiper-item v-for="(item,index) in card_menu" :key="index" @click="toUrl(item.url)">
<!-- <image class='le-img' :src='item' :class="{'le-active':swiper.index == index}"></image> -->
<view class="le-img" :class="{'le-active':swiper.index == index}">
<view class="img_box">
<image class="card_img" :src="item.img" mode="aspectFill"></image>
</view>
<view class="detail_box">
<view class="title_box">{{item.title}}</view>
<view class="author_box">By:{{item.author}}</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
</view>
</template>
<script>
import Common from '../../static/js/common'
export default {
props: {
card_menu: {
type: Array,
default: []
}
},
data() {
return {
swiper: {
margin: "150rpx",
index: 0,
list: [
"/static/images/douyin/0.jpg",
"/static/images/douyin/4.jpg",
"/static/images/douyin/7.jpg",
]
}
}
},
components: {
},
mounted() {
},
methods: {
//swiper
swiperChange: function(e) {
this.swiper.index = e.detail.current;
},
toUrl(url){
Common.navigateTo(url);
}
}
}
</script>
<style lang="scss">
.top-swiper {
margin-bottom: 30rpx;
.box {
padding-top: var(--status-bar-height);
box-sizing: content-box;
position: absolute;
z-index: 5;
top: 0;
left: 0;
width: 100%;
height: auto;
}
.swiper {
height: 600rpx;
margin: 0 20rpx;
.le-img {
width: 100%;
height: 100%;
display: block;
transform: scale(0.9);
transition: transform 0.3s ease-in-out 0s;
border-radius: 10px;
background-color: #fff;
overflow: hidden;
&.le-active {
transform: scale(1);
}
.img_box {
width: 100%;
height: 65%;
overflow: hidden;
.card_img {
height: 100%;
width: 100%;
}
}
.detail_box {
width: 100%;
height: 35%;
overflow: hidden;
.title_box {
width: 100%;
text-align: center;
font-size: 40rpx;
margin: 30rpx 0;
}
.author_box {
width: 100%;
text-align: center;
font-size: 30rpx;
position: relative;
height: 80rpx;
line-height: 80rpx;
&::before {
content: "";
height: 1px;
width: 150rpx;
position: absolute;
transform: translateX(-50%);
left: 50%;
top: 0;
background: #000;
}
}
}
}
}
}
</style>

141
pages_qiun/components/data-center/user-healthy.vue

@ -0,0 +1,141 @@
<template>
<view class="content">
<scroll-view v-if="true" scroll-y class="data_body" :style="{height:scrollHeight}">
<!--数据进度条-->
<view class="progress">
<data-progress :progressList="userHealthyLineBar" :borderRadius="20" padMiddle="true"></data-progress>
</view>
<view class="split_line"></view>
<!-- 新增小程序会员趋势-->
<view class="friend_operate">
<text-block :content="baseData"></text-block>
<view class="trend_title">新增小程序会员趋势</view>
<view class="charts-box">
<qiun-data-charts
type="mix"
canvasId="three_a"
:canvas2d="isCanvas2d"
:reshow="delayload"
:opts="{yAxis:{data:[{position: 'left',title: '销售额/万',max:userTrand?userTrand.yAxis[0].max:0,min:userTrand?userTrand.yAxis[0].min:0},{position: 'right',title: '',max:userTrand?userTrand.yAxis[1].max:0,min:userTrand?userTrand.yAxis[1].min:0,unit:'%'}]}}"
:chartData="userTrand"/>
</view>
</view>
<view class="split_line"></view>
<!-- 会员扫码率趋势-->
<view class="friend_operate">
<text-block :content="scanTrand"></text-block>
<view class="trend_title">会员扫码率趋势</view>
<view class="charts-box">
<qiun-data-charts
type="mix"
canvasId="three_b"
:canvas2d="isCanvas2d"
:reshow="delayload"
:opts="{yAxis:{data:[{position: 'left',title: '',max:scanTrandPrecent?scanTrandPrecent.yAxis[0].max:0,min:scanTrandPrecent?scanTrandPrecent.yAxis[0].min:0,unit:'%'}]}}"
:chartData="scanTrandPrecent"/>
</view>
</view>
<view class="split_line"></view>
<!-- 小程序活跃会员占比-->
<view class="friend_operate">
<text-block :content="miniActive"></text-block>
<view class="charts-box">
<qiun-data-charts
type="mix"
canvasId="three_c"
:canvas2d="isCanvas2d"
:reshow="delayload"
:opts="{yAxis:{data:[{position: 'left',title: '销售额/万',max:miniActivePrecent?miniActivePrecent.yAxis[0].max:0,min:miniActivePrecent?miniActivePrecent.yAxis[0].min:0},{position: 'right',title: '',max:miniActivePrecent?miniActivePrecent.yAxis[1].max:0,min:miniActivePrecent?miniActivePrecent.yAxis[1].min:0,unit:'%'}]}}"
:chartData="miniActivePrecent"
/>
</view>
</view>
</scroll-view>
<view v-else class="container padding_stand-big normal_color">
<li class="iconfont icon-cry cry"></li>暂无数据
</view>
</view>
</template>
<script>
import DataProgress from "../data-progress/data-progress.vue"
import userHealthyLineBar from '../../static/json/user-healthy/1.json';
import baseData from '../../static/json/user-healthy/2.json';
import userTrand from '../../static/json/user-healthy/3.json';
import scanTrand from '../../static/json/user-healthy/4.json';
import scanTrandPrecent from '../../static/json/user-healthy/5.json';
import miniActive from '../../static/json/user-healthy/6.json';
import miniActivePrecent from '../../static/json/user-healthy/7.json';
import Config from '../../static/js/config'
var _self;
export default {
name:'user-healthy',
props: {
scrollHeight:{
type:String,
default:"600px"
}
},
components:{
DataProgress
},
data() {
return {
userHealthyLineBar,
baseData,
userTrand,
scanTrand,
scanTrandPrecent,
miniActive,
miniActivePrecent,
delayload:false,
isCanvas2d:Config.ISCANVAS2D,
}
},
mounted() {
this.getData();
},
methods:{
async getData(){
uni.showLoading();
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
}
}
}
</script>
<style scoped lang="less">
.content{
padding-top: 10rpx;
.progress,.firend_operate{
padding: 0 10rpx;
}
.progress{
margin-bottom: 20rpx;
}
.friend_operate{
padding: 30rpx 10rpx;
.title{
text-align:left;
margin-bottom: 20rpx;
}
.trend_title{
text-align: right;
font-size: 22rpx;
color: #ff9900;
margin-top: 20rpx;
}
}
}
</style>

200
pages_qiun/components/data-center/user-operate.vue

@ -0,0 +1,200 @@
<template>
<view class="content">
<scroll-view v-if="true" scroll-y class="data_body" :style="{height:scrollHeight}">
<!--数据进度条-->
<view class="progress">
<data-progress :progressList="userOperateLineBar" :borderRadius="20" padMiddle="true"></data-progress>
</view>
<view class="split_line"></view>
<!-- 活跃会员-->
<view class="friend_operate">
<view class="title">活跃会员</view>
<text-block :content="userActive"></text-block>
</view>
<!-- 会员消费 -->
<view class="friend_operate" style="padding-bottom: 30rpx;">
<view class="title">会员消费</view>
<text-block :content="userConsume"></text-block>
</view>
<view class="split_line"></view>
<!-- 会员ARPU -->
<view class="friend_operate">
<view class="title">会员ARPU
<text class="font-small">(会员年度平均销售金额)</text>
<text class="trend_title">目标增量{{userARPU.targetAdd}}</text>
</view>
<view class="charts-box">
<qiun-data-charts type="mix"
:chartData="userARPU"
:reshow="delayload"
:canvas2d="isCanvas2d"
canvasId="two_a"
:opts="{yAxis:{data:[{title: '',max:userARPU?userARPU.yAxis[0].max:0,min:userARPU?userARPU.yAxis[0].min:0},{title: '',unit:'%',max:userARPU?userARPU.yAxis[1].max:0,min:userARPU?userARPU.yAxis[1].min:0,position:'right'}]},extra:{markLine:{data:[{value:userARPU?userARPU.target:'',LineColor:'#ff9900',showLabel:true}]}}}"/>
</view>
</view>
<view class="split_line"></view>
<!-- 会员消费频次 -->
<view class="friend_operate">
<view class="title">会员消费频次
<text class="font-middle">()</text>
<text class="trend_title">目标增量{{userARPU.targetAdd}}</text>
</view>
<view class="charts-box">
<qiun-data-charts type="mix"
:chartData="userARPU"
:reshow="delayload"
:canvas2d="isCanvas2d"
canvasId="two_b"
:opts="{yAxis:{data:[{title: '',max:userARPU?userARPU.yAxis[0].max:0,min:userARPU?userARPU.yAxis[0].min:0},{title: '',unit:'%',max:userARPU?userARPU.yAxis[1].max:0,min:userARPU?userARPU.yAxis[1].min:0,position:'right'}]},extra:{markLine:{data:[{value:userARPU?userARPU.target:'',LineColor:'#ff9900',showLabel:true}]}}}"/>
</view>
</view>
<view class="split_line"></view>
<!-- 微客群运营-->
<view class="friend_operate">
<view class="title">活跃会员分布
<text class="font-middle">(最近活跃时间)</text>
</view>
<senior-table :headers="dataTable.headers" :contents="dataTable.contents" :urlCol="dataTable.urlCol" :firstLineFixed="true" :sortCol="dataTable.sortCol" :computedCol="dataTable.computedCol" :formatCol="dataTable.formatCol"></senior-table>
</view>
<view class="split_line"></view>
<!-- X商品脱落率-->
<view class="friend_operate">
<view class="title">
X慢病 商品脱落率
</view>
<view style="display: flex;justify-content: space-between;">
<view v-for="(item,index) in xProductDropPrecent" class="charts-box" style="height: 130px;width: 45%;">
<qiun-data-charts
type="arcbar"
:chartData="item"
:canvasId="'two_c_'+ index"
:canvas2d="true"
:reshow="delayload"
:opts="{title:{name:item.series[0].data * 100 + '%',color:item.series[0].color,fontSize:25},subtitle:{name:item.series[0].name,color:'#666666',fontSize:12}}" />
</view>
</view>
</view>
<!-- 慢病病种脱落率-->
<view class="friend_operate">
<view class="title">慢病病种脱落率
</view>
<view class="charts-box">
<qiun-data-charts type="mix"
:chartData="illnessDropPrecent"
:reshow="delayload"
:canvas2d="true"
canvasId="two_d"
:opts="{yAxis:{data:[{title: ''}]}}"/>
</view>
</view>
<!-- W商品脱落率-->
<view class="friend_operate">
<view class="title">
W保健 商品脱落率
</view>
<view style="display: flex;justify-content: space-between;">
<view v-for="(item,index) in wProductDropPrecent" class="charts-box" style="height: 130px;width: 45%;">
<qiun-data-charts
type="arcbar"
:chartData="item"
:canvasId="'two_e_'+index"
:canvas2d="true"
:reshow="delayload"
:opts="{title:{name:item.series[0].data * 100 + '%',color:item.series[0].color,fontSize:25},subtitle:{name:item.series[0].name,color:'#666666',fontSize:12}}" />
</view>
</view>
</view>
</scroll-view>
<view v-else class="container padding_stand-big normal_color">
<li class="iconfont icon-cry cry"></li>暂无数据
</view>
</view>
</template>
<script>
import DataProgress from "../data-progress/data-progress.vue"
import SeniorTable from "../data-table/senior-table.vue"
import userOperateLineBar from '../../static/json/user-operate/1.json';
import userActive from '../../static/json/user-operate/2.json';
import userConsume from '../../static/json/user-operate/3.json';
import userARPU from '../../static/json/user-operate/4.json';
import dataTable from "../../static/json/user-operate/6.json"
import xProductDropPrecent from '../../static/json/user-operate/7.json';
import wProductDropPrecent from '../../static/json/user-operate/9.json';
import illnessDropPrecent from '../../static/json/user-operate/8.json';
export default {
name:'user-operate',
props: {
scrollHeight:{
type:String,
default:"600px"
}
},
components:{
DataProgress,SeniorTable
},
data() {
return {
userOperateLineBar,
userActive,
userConsume,
userARPU,
xProductDropPrecent,
wProductDropPrecent,
illnessDropPrecent,
dataTable,
delayload:false,
isCanvas2d:Config.ISCANVAS2D
}
},
mounted() {
this.getData();
},
methods:{
async getData(){
uni.showLoading();
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
}
}
}
</script>
<style scoped lang="less">
.content{
padding-top: 10rpx;
.progress,.firend_operate{
padding: 0 10rpx;
}
.progress{
margin-bottom: 20rpx;
}
.friend_operate{
padding: 30rpx 20rpx;
.title{
text-align:left;
margin-bottom: 30rpx;
font-size: 40rpx;
}
.trend_title{
float: right;
font-size: 22rpx;
color: #ff9900;
margin-top: 20rpx;
}
}
}
</style>

385
pages_qiun/components/data-center/user-server.vue

@ -0,0 +1,385 @@
<template>
<view class="content">
<scroll-view class="data_body" scroll-y :style="{height:scrollHeight}">
<template v-if="true">
<!-- 会员成长数据-->
<view class="view_item">
<view class="title">会员成长数据</view>
<view class="progress_circle">
<view v-for="(item,index) in CircleData" :key="index" :class="['progress_block','block_'+index]">
<view class="name">{{item.series[0].name}}</view>
<view class="value">{{item.series[0].value}}</view>
<view class="charts-box arcbar" style="height: 180rpx;width: 60%;">
<qiun-data-charts type="arcbar" :chartData="item" :canvasId="'four_a_'+index" :canvas2d="isCanvas2d"
:resshow="delayload"
:opts="{title:{name:item.series[0].precent,color:item.series[0].color,fontSize:15},subtitle:{name:'',color:'#666666',fontSize:12},extra:{arcbar:{backgroundColor:item.series[0].backgroundColor}}}" />
</view>
<view class="planet">
<view class="planet_shadow"></view>
<view class="crater1"></view>
<view class="crater2"></view>
<view class="crater3"></view>
<view class="crater4"></view>
</view>
<view class="star" :class="['star'+index]"></view>
<view class="star pink" :class="['star'+index]"></view>
<view class="star blue" :class="['star'+index]"></view>
<view class="star yellow" :class="['star'+index]"></view>
</view>
</view>
</view>
<view class="split_line"></view>
<!-- 会员数据来源 -->
<view class="friend_operate">
<view class="title">会员数据来源
<text class="font-small" style="color: #ff9900;">(Top5访问来源)</text>
</view>
<view v-if="delayload" class="charts-box">
<qiun-data-charts
type="ring"
canvasId="four_b"
:canvas2d="isCanvas2d"
:resshow="delayload"
:opts="{legend:{position: 'bottom'},title:{name: '',},subtitle: {name: ''}}"
:chartData="ProductRateData"/>
</view>
</view>
<view class="split_line"></view>
<!-- 服务评价概览-->
<view class="friend_operate">
<view class="title">服务评价概览</view>
<text-block :content="ServiceComment"></text-block>
</view>
<!-- 本周会员访问趋势图 -->
<view class="friend_operate">
<view class="title">本周会员访问趋势图</view>
<view v-if="delayload" class="charts-box" style="height: 300px;">
<qiun-data-charts
type="mix"
canvasId="four_c"
:canvas2d="isCanvas2d"
:resshow="delayload"
:opts="{yAxis:{data:[{position: 'left',title: '',min:0,unit:'万'}]}}"
:chartData="TrendData"
/>
</view>
</view>
<view class="split_line"></view>
<!-- 新增会员排行榜 -->
<view class="friend_operate">
<view class="title">新增会员排行榜</view>
<progress-bar :isRank="isRank" :content="RankData" />
</view>
</template>
<template v-else>
<view class="container padding_stand-big normal_color">
<li class="iconfont icon-cry cry"></li>暂无数据
</view>
</template>
</scroll-view>
</view>
</template>
<script>
import ProgressBar from "../progress-bar/progress-bar.vue"
import CircleData from "../../static/json/user-server/1.json"
import ProductRateData from '../../static/json/user-server/2.json';
import TrendData from '../../static/json/user-server/3.json';
import ServiceComment from '../../static/json/user-server/4.json';
import RankData from '../../static/json/user-server/5.json';
import Config from '../../static/js/config'
export default {
name:"user-server",
props:{
scrollHeight:{
type:String,
default:"600px"
}
},
components:{
ProgressBar
},
data(){
return {
CircleData,
TrendData,
ProductRateData,
ServiceComment,
RankData,
isRank:true,
isCanvas2d:Config.ISCANVAS2D,
delayload: false, //
}
},
methods:{
async getData(){
uni.showLoading();
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
}
},
mounted() {
this.getData();
}
}
</script>
<style scoped lang="scss">
.content{
padding-top: 10rpx;
}
.data_body{
height: 100%;
text-align: center;
color: #333333;
background-repeat: repeat;
background-color: #ffffff;
.friend_operate{
padding: 30rpx 20rpx;
.title{
text-align:left;
margin-bottom: 30rpx;
font-size: 40rpx;
}
}
.view_item{
padding: 30rpx 20rpx;
.title{
text-align:left;
margin-bottom: 30rpx;
font-size: 40rpx;
}
}
.progress_circle{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
height: 450rpx;
.progress_block{
width: 45%;
border-radius: 20rpx;
height: 180rpx;
position: relative;
overflow: hidden;
.name{
color: #fff;
font-size: 24rpx;
position: absolute;
top: 20rpx;
left: 10rpx;
max-width: 144rpx;
}
.value{
color: #fff;
font-size: 40rpx;
position: absolute;
top: 64rpx;
left: 10rpx;
max-width: 144rpx;
}
.circle{
position: absolute;
right: 8rpx;
top: 16rpx;
}
.arcbar{
position: absolute;
right: -4rpx;
top: 8rpx;
}
}
.block_0{
background-color: #0FC3FF;
}
.block_1{
background-color: #FF6B8B;
}
.block_2{
background-color: #FFCB1D;
}
.block_3{
background-color: #3BDCAA;
}
}
}
.planet {
width: 60px;
height: 60px;
border-radius: 50%;
background: #333;
position: absolute;
left: -13px;
bottom: -26px;
overflow: hidden;
opacity: 0.5;
z-index: 0;
}
.planet_shadow {
position: absolute;
border-radius: 50%;
height: 100%;
width: 100%;
top: -40%;
right: -10%;
border: 35px solid rgba(0, 0, 0, .15);
}
.crater1,
.crater2,
.crater3,
.crater4 {
position: absolute;
border-radius: 50%;
background: rgba(0, 0, 0, .3);
box-shadow: inset 3px 3px 0 rgba(0, 0, 0, .2);
}
.crater1 {
width: 20px;
height: 20px;
left: 25%;
top: 20%;
}
.crater2 {
width: 10px;
height: 10px;
left: 50%;
top: 60%;
}
.crater3 {
width: 15px;
height: 15px;
left: 30%;
top: 65%;
}
.crater4 {
width: 15px;
height: 15px;
left: 60%;
top: 35%;
}
.star {
display: block;
width: 5px;
height: 5px;
border-radius: 50%;
background: #FFF;
top: 10px;
left: 50px;
position: relative;
transform-origin: 100% 0;
box-shadow: 0 0 5px 5px rgba(255, 255, 255, .3);
opacity: 0;
z-index: 2;
}
.star0{
animation: star-ani 4s infinite ease-out;
}
.star1{
animation: star-ani 5s infinite ease-out;
}
.star2{
animation: star-ani 6s infinite ease-out;
}
.star3{
animation: star-ani 7s infinite ease-out;
}
.star:after {
content: '';
display: block;
top: 20px;
left: 60px;
border: 0px solid #fff;
border-width: 0px 90px 2px 90px;
border-color: transparent transparent transparent rgba(255, 255, 255, .3);
transform: rotate(-45deg) translate3d(1px, 3px, 0);
box-shadow: 0 0 1px 0 rgba(255, 255, 255, .1);
transform-origin: 0% 100%;
animation: shooting-ani 100s infinite ease-out;
}
.pink {
top: 10px;
left: 60px;
background: #ff5a99;
animation-delay: 5s;
-webkit-animation-delay: 5s;
-moz-animation-delay: 5s;
}
.pink:after {
border-color: transparent transparent transparent #ff5a99;
animation-delay: 5s;
-webkit-animation-delay: 5s;
-moz-animation-delay: 5s;
}
.blue {
top: 15px;
left: 70px;
background: cyan;
animation-delay: 7s;
-webkit-animation-delay: 7s;
-moz-animation-delay: 7s;
}
.blue:after {
border-color: 'transpareanimation-delay: 12s';
-webkit-animation-delay: 7s;
-moz-animation-delay: 7s;
animation-delay: 7s;
}
.yellow {
top: 0px;
left: 80px;
background: #ffcd5c;
animation-delay: 5.8s;
}
.yellow:after {
border-color: transparent transparent transparent #ffcd5c;
animation-delay: 5.8s;
}
@keyframes star-ani {
0% {
opacity: 0;
transform: scale(0) rotate(0) translate3d(0, 0, 0);
-webkit-transform: scale(0) rotate(0) translate3d(0, 0, 0);
-moz-transform: scale(0) rotate(0) translate3d(0, 0, 0);
}
50% {
opacity: 0.5;
transform: scale(1) rotate(0) translate3d(-20px, 20px, 0);
-webkit-transform: scale(1) rotate(0) translate3d(-20px, 20px, 0);
-moz-transform: scale(1) rotate(0) translate3d(-20px, 20px, 0);
}
100% {
opacity: 0;
transform: scale(1) rotate(0) translate3d(-30px, 30px, 0);
-webkit-transform: scale(1) rotate(0) translate3d(-30px, 30px, 0);
-moz-transform: scale(1) rotate(0) translate3d(-30px, 30px, 0);
}
}
</style>

132
pages_qiun/components/data-center/wechat.vue

@ -0,0 +1,132 @@
<template>
<view class="content">
<scroll-view v-if="true" scroll-y class="data_body" :style="{height:scrollHeight}">
<!--数据进度条-->
<view class="progress">
<data-progress :progressList="wechatLineBar" :borderRadius="20" padMiddle="true"></data-progress>
</view>
<view class="split_line"></view>
<!-- 微好友运营-->
<view class="friend_operate">
<view class="title">微好友运营</view>
<text-block :content="friendTextBlock"></text-block>
<view style="display: flex;justify-content: space-around;">
<view v-for="(item,index) in panelData" :key="index" class="charts-box"
style="width: 45%;height: 200px;">
<qiun-data-charts type="gauge"
:opts="{title:{name: item.series[0].data * 100 + '%',color: '#24ABFD',offsetY:30},subtitle: {name: item.series[0].name,color: '#666666',fontSize: 15,offsetY:70},extra:{gauge:{type:'progress',width:20,splitLine:{fixRadius:-10,width:15,},}}}"
:chartData="item" :reshow="delayload" :canvas2d="isCanvas2d" :canvasId="'one_a_' + index" />
</view>
</view>
<view class="trend_title">新增微好友&小程序会员趋势</view>
<view class="charts-box">
<qiun-data-charts type="mix" :chartData="friendTrand" :reshow="delayload"
:canvas2d="isCanvas2d" canvasId="one_b" :opts="{yAxis:{data:[{title: ''}]}}" />
</view>
</view>
<view class="split_line"></view>
<!-- 微客群运营-->
<view class="friend_operate">
<view class="title">微客群运营</view>
<text-block :content="friendTextBlock"></text-block>
<view class="trend_title">新增人群&退群人数趋势</view>
<view class="charts-box">
<qiun-data-charts type="mix" :chartData="teamTrand" :reshow="delayload" :canvas2d="isCanvas2d"
canvasId="one_c" :opts="{yAxis:{data:[{title: '',max:teamTrand?teamTrand.yAxis[0].max:0,min:teamTrand?teamTrand.yAxis[0].min:0}]}}" />
</view>
</view>
<view class="split_line"></view>
<!-- 客户联系-->
<view class="friend_operate">
<view class="title">客户联系1对1运营执行</view>
<senior-table :headers="dataTable.headers" :contents="dataTable.contents" :urlCol="dataTable.urlCol" :firstLineFixed="true" :sortCol="dataTable.sortCol"></senior-table>
</view>
</scroll-view>
<view v-else class="container padding_stand-big normal_color">
<li class="iconfont icon-cry cry"></li>暂无数据
</view>
</view>
</template>
<script>
import DataProgress from "../data-progress/data-progress.vue"
import SeniorTable from "../data-table/senior-table.vue"
import wechatLineBar from '../../static/json/wechat/1.json';
import friendTextBlock from '../../static/json/wechat/2.json';
import panelData from '../../static/json/wechat/3.json';
import friendTrand from '../../static/json/wechat/4.json';
import teamTrand from '../../static/json/wechat/5.json';
import dataTable from "../../static/json/wechat/6.json"
import Config from '../../static/js/config'
export default {
name:'wechat',
props: {
scrollHeight:{
type:String,
default:"600px"
}
},
components:{
DataProgress,
SeniorTable,
},
data() {
return {
wechatLineBar,
friendTextBlock,
friendTrand,
panelData,
teamTrand,
dataTable,
scrollTop: 0,
delayload: false,
isCanvas2d: Config.ISCANVAS2D,
}
},
mounted() {
this.getData();
},
methods:{
async getData() {
uni.showLoading();
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
}
}
}
</script>
<style scoped lang="less">
.content{
padding-top: 10rpx;
.progress,.firend_operate{
padding: 0 10rpx;
}
.progress{
margin-bottom: 20rpx;
}
.friend_operate{
padding: 30rpx 20rpx;
.title{
text-align:left;
margin-bottom: 30rpx;
font-size: 40rpx;
}
.trend_title{
text-align: right;
font-size: 22rpx;
color: #ff9900;
margin-top: 50rpx;
}
}
}
</style>

93
pages_qiun/components/data-progress/data-progress.vue

@ -0,0 +1,93 @@
<template>
<view class="column">
<view v-for="(item,index) in progressList" :key="index" :class="['row','font-small','progress',padMiddle?'paddingMiddle':'']">
<text class="title">{{item.name}}</text>
<view class="body">
<view class="number">{{item.now?item.now+"/":""}}{{item.expect}} [{{item.value}}%]</view>
<progress :percent="item.value" backgroundColor="#C9C9C9"
:border-radius="borderRadius?borderRadius+'rpx':'0px'"
:color="time"
stroke-width="16" />
</view>
</view>
</view>
</template>
<script>
export default {
name:'data-progress',
props: {
progressList: {
type: Array,
default: ()=> {
return []
}
},
borderRadius:{
type:Number,
default:0
},
padMiddle:{
type:String,
default:"false"
}
},
data() {
return {
time:0
}
},
watch:{
"progressList":{
deep: true,
handler: function(newVal, oldVal) {
this.time = newVal.filter(x=>x.name=="时间进度")[0].value;
}
}
},
created() {
this.time = this.progressList.filter(x=>x.name=="时间进度")[0].value;
}
}
</script>
<style lang="scss">
.paddingMiddle{
padding: 18rpx 10rpx;
}
.progress{
.title{
font-size: 28rpx;
width: 170rpx;
display: flex;
align-items: center;
}
.body{
position: relative;
flex: 1;
.number{
color: #fff;
position: absolute;
z-index: 2;
left: 26rpx;
height: 100%;
display: flex;
align-items: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
height: 44rpx;
}
progress{
padding: 6rpx 0;
}
}
}
</style>

1117
pages_qiun/components/data-table/senior-table.vue

File diff suppressed because it is too large

218
pages_qiun/components/drop-down/drop-down.vue

@ -0,0 +1,218 @@
<template>
<div class="dropdown-item">
<!-- selected -->
<view :class="['dropdown-item__selected',listWidth!='150rpx'?'dropdown-item__right':'dropdown-item__left']"
@click="changePopup" :style="{maxWidth:selectWidth}">
<view class="selected__name">{{selectItem.text}}</view>
<view class="selected__icon"
:class="showClass === 'show'? 'up' : 'down'"
>
<li class="iconfont icon-caretdown"></li>
</view>
</view>
<view class="dropdown-item__content" :style="{top: contentTop + 'rpx'}" v-if="showList">
<!-- dropdown -->
<view :class="['list', showClass]" :style="{left: contentLeft>0?contentLeft + 'rpx':'auto',right: contentRight>0?contentRight + 'rpx':'auto',}">
<view class="list__option"
v-for="(item, index) in list" :key="index"
@click="choose(item)">
<view>{{item.text}}</view>
<icon v-if="item.value === value" type="success_no_circle" size="20"/>
</view>
</view>
<!-- dropdown-mask -->
<view :class="['dropdown-mask', showClass]" v-if="showList" @click="closePopup"></view>
</view>
</div>
</template>
<script>
export default {
components: {
},
props: {
value: [Number, String, Object],
list: {
type: Array,
default: ()=> {
return []
}
},
contentTop:{
type:String,
default:"185"
},
contentLeft:{
type:String,
default:"0"
},
contentRight:{
type:String,
default:"0"
},
listWidth:{
type:String,
default:'150rpx'
},
selectWidth:{
type:String,
default:'150rpx'
}
},
data() {
return {
showList: "",
showClass: '',
selectItem: {},
}
},
watch: {
list(newVal,oldVal){
this.selectItem = newVal[0];
}
},
mounted() {
this.showList = this.active;
this.selectItem = this.list[0];
},
methods: {
choose(item) {
if(item.value != "auto"){
this.selectItem = item
}
this.$emit('changeItem', item);
this.closePopup();
},
selectAuto(){
this.selectItem = {text: '指定日期',value: 'auto'};
},
changePopup() {
if(this.showList) {
this.closePopup()
} else {
this.openPopup()
}
},
openPopup() {
setTimeout(() => {
this.showClass = 'show';
this.showList = true;
}, 100);
},
closePopup() {
this.showClass = ''
setTimeout(() => {
this.showList = false
}, 200);
},
close() {
this.showClass = ''
this.showList = false
},
}
}
</script>
<style lang="scss">
li{
list-style-type:none;
}
.dropdown-item__content{
z-index: 10!important;
}
.dropdown-item {
width: 100%;
flex:1;
position: relative;
&__selected {
position: relative;
padding: 10rpx 0;
box-sizing: border-box;
color: #fff;
.selected__name {
font-size: 28rpx;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.selected__icon {
margin-left: 20rpx;
&.down {
transition: transform .3s;
transform: rotateZ(0);
}
&.up {
transition: transform .3s;
transform: rotateZ(-180deg);
}
}
}
&__left{
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
&__right{
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
&__content {
position: fixed;
left: 0;
right: 0;
overflow: hidden;
top: 0;
bottom: 0;
z-index: 1;
.list {
max-height: 400px;
text-align: center;
overflow-y: auto;
position: absolute;
z-index: 1200;
background: #fff;
transform: translateY(-100%);
transition: all .3s;
&.show {
transform: translateY(0);
}
&__option {
font-size:30rpx;
padding: 18rpx;
display: flex;
justify-content: space-between;
color: #303133;
&:not(:last-child) {
border-bottom: 1rpx solid #DDDDDD;
}
}
}
.dropdown-mask {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
transition: all .3s;
z-index: 1100;
&.show {
background:rgba(0,0,0,0.5);
}
}
}
&:not(:last-child):after {
content: ' ';
position: absolute;
width: 2rpx;
top: 36rpx;
bottom: 36rpx;
right: 0;
background: $uni-border-color;
}
}
</style>

125
pages_qiun/components/progress-bar/progress-bar.vue

@ -0,0 +1,125 @@
<template>
<view>
<view v-if="copyContent.length > 0" class="ranking">
<view class="ranking-item" v-for="(content,index) in copyContent" :key="index" :style="{padding:progressPadding+'rpx'}">
<view class="name">{{content.name}}</view>
<view class="progress" >
<text :style="{background:content.background,width:content.width + '%',height:progressWidth+'rpx'}"></text>
</view>
<view class="num">{{content.num}}</view>
</view>
</view>
</view>
</template>
<script>
export default{
name:'ranking-list',
props:{
content:{
type: Array,
default() {
return []
}
},
isPC:{
type:Boolean,
default:false
},
isRank:{
type:Boolean,
default:false
}
},
data(){
return{
progressWidth:24,
progressPadding:10,
maxNumber:0,
culCount:0,
copyContent:[]
}
},
watch:{
content(newV){
this.init()
}
},
methods:{
init(){
this.copyContent = this.deepClone(this.content)
if(this.copyContent && this.copyContent.length >0){
if(this.isRank){
this.copyContent = this.copyContent.sort((a,b) => b.num - a.num);
this.maxNumber = this.copyContent[0].num;
}else{
this.maxNumber = Math.max.apply(Math,this.copyContent.map(item => { return item.num }));
}
this.copyContent.map((item,index) =>{
item.width = this.computeWidth(this.maxNumber,item.num);
});
}
},
computeWidth(max,current){
let num = (current / max) * 100;
return num.toFixed(2);
},
deepClone(obj) {
var cloneObj = new obj.constructor()
if(obj === null) return obj
if(obj instanceof Date) return new Date(obj)
if(obj instanceof RegExp) return new RegExp(obj)
if (typeof obj !== 'object') return obj
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
cloneObj[i] = this.deepClone(obj[i])
}
}
return cloneObj
}
},
mounted() {
if(this.isPC){
this.progressWidth = 40;
this.progressPadding = 30;
}
this.init();
}
}
</script>
<style scoped lang="scss">
.ranking-item{
display: flex;
margin-bottom: 13rpx;
align-content: center;
height: 50rpx;
.name{
padding-right: 10rpx;
color: #868688;
font-size: 20rpx;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.progress{
flex:5;
text-align: left;
padding-right: 10rpx;
text{
display: inline-block;
border-radius: 30rpx;
vertical-align:top;
}
}
.num{
font-size: 26rpx;
color: #3EB2F5;
flex: 1;
}
}
</style>

93
pages_qiun/components/ranking-list/ranking-list.vue

@ -0,0 +1,93 @@
<template>
<view>
<view class="ranking">
<view class="ranking-item" v-for="(content,index) in content" :key="index">
<view class="name">{{content.name}}</view>
<view class="progress" >
<text :style="{backgroundImage:'linear-gradient(to top right,'+getColor(0,index)+','+getColor(1,index)+')',width:content.width + '%'}"></text>
</view>
<view class="num">{{content.num}}</view>
</view>
</view>
</view>
</template>
<script>
export default{
name:'ranking-list',
props:{
content:{
type: Array,
default() {
return []
}
}
},
methods:{
init(){
if(this.content && this.content.length >0){
this.content = this.content.sort((a,b) => b.num - a.num);
let max = this.content[0].num;
this.content.map((item,index) =>{
item.width = this.computeWidth(max,item.num);
});
this.$emit("updateRanking",this.content)
}
},
computeWidth(max,current){
let num = (current / max) * 100;
return num.toFixed(2);
},
getColor(id,index){
let color = "";
switch(index){
case 0:
color = id == 0 ? "#fff":"#A80BFC";
break;
case 1:
color = id == 0 ? "#fff":"#740CFF";
break;
case 2:
color = id == 0 ? "#fff":"#4A08DC";
break;
default :
color = id == 0 ? "#fff":"#1936DA";
break;
}
return color;
},
},
mounted() {
this.init();
}
}
</script>
<style scoped lang="scss">
.ranking-item{
display: flex;
margin-bottom: 13rpx;
padding: 10rpx;
align-content: center;
.name{
padding-right: 10rpx;
color: #868688;
}
.progress{
flex:5;
text-align: left;
padding-right: 10rpx;
text{
display: inline-block;
height: 100%;
}
}
.num{
font-size: 26rpx;
color: #3EB2F5;
}
}
</style>

186
pages_qiun/components/text-block/text-block.vue

@ -0,0 +1,186 @@
<template>
<view class="text_block">
<template v-for="(item,index) in content">
<view v-if="item.kind == 1" :key="index" :style="{backgroundImage:'linear-gradient(to top right,'+item.background[0]+','+item.background[1]+')'}" :class="[(index+1)%3==0 ? '':'marginRight','kind','kind_one','breathe-blue']">
<view class="view_100" :style="{fontSize:item.content[0].size,color:item.content[0].colorvalue}">{{item.content[0].value}}</view>
<view class="view_100" :style="{fontSize:item.content[1].size,color:item.content[1].colortext}">{{item.content[1].text}}</view>
</view>
<view v-else-if="item.kind == 2" :class="[(index+1)%3==0 ? '':'marginRight','kind','kind_two','breathe-blue']" :style="{backgroundImage:'linear-gradient(to top right,'+item.background[0]+','+item.background+')' ,marginRight:(index+1)%3==0?'0rpx':'40rpx'}">
<view v-for="(content,i) in item.content" :key="i" class="two_1">
<text :style="{fontSize:content.size,color:content.colortext}">{{content.text}}:</text>
<text :style="{fontSize:content.size,color:content.colorvalue}">{{content.value}}</text>
</view>
</view>
<view v-else-if="item.kind == 3" class="kind kind_three breathe-blue" :style="{backgroundImage:'linear-gradient(to top right,'+item.background[0]+','+item.background+')'}">
<view class="view_100" :style="{fontSize:item.content[0].size,color:item.content[0].colorvalue}">{{item.content[0].value}}</view>
<view class="view_100" :style="{fontSize:item.content[1].size,color:item.content[1].colortext}">{{item.content[1].text}}</view>
<view class="three_3 view_100">
<view v-for="(j,i) in 2" :key="i">
<text :style="{fontSize:item.content[i+2].size,color:item.content[i+2].colortext}">{{item.content[i+2].text}}:</text>
<text :style="{fontSize:item.content[i+2].size,color:item.content[i+2].colorvalue}">{{item.content[i+2].value}}</text>
</view>
</view>
</view>
<view v-else-if="item.kind == 4" :class="[(index+1)%3==0 ? '':'marginRight','kind','kind_four','breathe-blue']" :style="{backgroundImage:'linear-gradient(to top right,'+item.background[0]+','+item.background[1]+')',marginRight:(index+1)%3==0?'0rpx':'40rpx'}">
<view class="view_100" :style="{fontSize:item.content[0].size,color:item.content[0].colortext}">{{item.content[0].text}}</view>
<view class="view_100" :style="{fontSize:item.content[1].size,color:item.content[1].colorvalue}">{{item.content[1].value}}</view>
<view class="four_3" :style="{fontSize:item.content[2].size,color:item.content[2].colorvalue}">
<text :style="{fontSize:item.content[3].size,color:item.content[3].colorvalue}">{{item.content[2].text}}</text>
<li v-if="item.content[3].text == 'up'" class="iconfont icon-up icon li_1" :style="{color:item.content[3].colortext}"></li>
<li v-else class="iconfont icon-down icon li_1" :style="{color:item.content[3].colortext}"></li>
<text :style="{fontSize:item.content[3].size,color:item.content[3].colorvalue}">{{item.content[3].value}}</text>
</view>
</view>
<view v-else-if="item.kind == 5" :class="[(index+1)%3==0 ? '':'marginRight','kind','kind_five','breathe-red']" :style="{backgroundImage:'linear-gradient(to top right,'+item.background[0]+','+item.background[1]+')',marginRight:(index+1)%3==0?'0rpx':'40rpx'}">
<view class="view_100" :style="{fontSize:item.content[0].size,color:item.content[0].colortext}">{{item.content[0].text}}</view>
<view class="view_100" :style="{fontSize:item.content[1].size,color:item.content[1].colorvalue}">{{item.content[1].value}}</view>
<view class="five_3 view_100">
<view v-for="(j,i) in 2" :key="i">
<text :style="{fontSize:item.content[j+2].size,color:item.content[j+2].colortext}">{{item.content[j+2].text}}</text>
<text :style="{fontSize:item.content[j+2].size,color:item.content[j+2].colorvalue}">{{item.content[j+2].value}}</text>
</view>
</view>
<view class="five_4">
<text :style="{fontSize:item.content[4].size,color:item.content[4].colortext}">{{item.content[4].text}}</text>
<text :style="{fontSize:item.content[4].size,color:item.content[4].colorvalue}">{{item.content[4].value}}</text>
</view>
</view>
</template>
</view>
</template>
<script>
export default {
props:{
content: {
type: Array,
default: []
},
},
data() {
return {
}
},
methods: {
},
mounted() {
uni.onWindowResize((res) => {
console.log('变化后的窗口宽度=' + res.size.windowWidth)
console.log('变化后的窗口高度=' + res.size.windowHeight)
})
}
}
</script>
<style lang="scss">
.text_block{
display: flex;
width: 100%;
flex-wrap: wrap;
.marginRight{
margin-right: 36rpx!important;
}
.view_100{
width: 100%;
}
.CPT_DYBG {
overflow: hidden;
position: relative;
}
.kind{
width: 24%;
padding: 10rpx;
margin-bottom: 40rpx;
display: flex;
justify-content: center;
flex-wrap: wrap;
border-radius: 16rpx;
margin-left: 16rpx;
box-shadow: -4px 4px 4px #ccc;
position: relative;
}
.kind_one{
border-radius: 10rpx;
}
.kind_two{
border-radius: 10rpx;
}
.kind_three{
border-radius: 16rpx;
width: 300rpx;
margin: 0 auto;
.three_3{
display: flex;
justify-content: space-around;
}
}
.kind_four{
border-radius: 10rpx;
.four_3{
display: flex;
.li_1 {
list-style-type:none;
}
.icon{
margin-top: -8rpx;
transform: scale(0.8);
}
}
}
.kind_five{
border-radius: 20rpx;
.five_3{
view{
width: 100%;
}
}
}
}
// .breathe-blue {
// position:relative;
// color:#fff;
// text-align:center;
// cursor:pointer;
// box-shadow:0 1px 2px rgba(0,0,0,.3);
// overflow:hidden;
// -webkit-animation-timing-function:ease-in-out;
// -webkit-animation-name:breatheblue;
// -webkit-animation-duration:2000ms;
// -webkit-animation-iteration-count:infinite;
// -webkit-animation-direction:alternate;
// }
// @keyframes breatheblue {
// 0% {
// opacity:.8;
// box-shadow:0 1px 2px rgba(62,178,245,0.5);
// }
// 100% {
// opacity:1;
// box-shadow:0 1px 30px rgba(147,116,247,0.6);
// }
// }
// .breathe-red {
// position:relative;
// color:#fff;
// text-align:center;
// cursor:pointer;
// box-shadow:0 1px 2px rgba(0,0,0,.3);
// overflow:hidden;
// -webkit-animation-timing-function:ease-in-out;
// -webkit-animation-name:breathered;
// -webkit-animation-duration:2000ms;
// -webkit-animation-iteration-count:infinite;
// -webkit-animation-direction:alternate;
// }
// @keyframes breathered {
// 0% {
// opacity:.8;
// box-shadow:0 1px 2px rgba(247,126,137,0.5);
// }
// 100% {
// opacity:1;
// box-shadow:0 1px 30px rgba(247,149,59,0.9);
// }
// }
</style>

600
pages_qiun/components/uni-calendar/calendar.js

@ -0,0 +1,600 @@
/**
* @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 2033hexAttribution 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 (02930)
* @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 (-12930)
* @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 (-128293031)
* @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

170
pages_qiun/components/uni-calendar/uni-calendar-item.vue

@ -0,0 +1,170 @@
<template>
<view class="uni-calendar-item__weeks-box" :class="{
'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}"
@click="choiceDate(weeks)">
<view class="uni-calendar-item__weeks-box-item">
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text" :class="{
'uni-calendar-item--isDay-text': weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.date}}</text>
<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}">今天</text>
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.isDay?'今天': (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--extra':weeks.extraInfo.info,
'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">{{weeks.extraInfo.info}}</text>
</view>
</view>
</template>
<script>
export default {
props: {
weeks: {
type: Object,
default () {
return {}
}
},
calendar: {
type: Object,
default: () => {
return {}
}
},
selected: {
type: Array,
default: () => {
return []
}
},
lunar: {
type: Boolean,
default: false
}
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
}
}
}
</script>
<style lang="scss" scoped>
.uni-calendar-item__weeks-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
}
.uni-calendar-item__weeks-box-text {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar-item__weeks-lunar-text {
font-size: $uni-font-size-sm;
color: $uni-text-color;
}
.uni-calendar-item__weeks-box-item {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: $uni-color-error;
}
.uni-calendar-item--disable {
background-color: rgba(249, 249, 249, $uni-opacity-disabled);
color: $uni-text-color-disable;
}
.uni-calendar-item--isDay-text {
color: $uni-color-primary;
}
.uni-calendar-item--isDay {
background-color: $uni-color-primary;
opacity: 0.8;
color: #fff;
}
.uni-calendar-item--extra {
color: $uni-color-error;
opacity: 0.8;
}
.uni-calendar-item--checked {
background-color: $uni-color-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--multiple {
background-color: $uni-color-primary;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--before-checked {
background-color: #ff5a5f;
color: #fff;
}
.uni-calendar-item--after-checked {
background-color: #ff5a5f;
color: #fff;
}
</style>

512
pages_qiun/components/uni-calendar/uni-calendar.vue

@ -0,0 +1,512 @@
<template>
<view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">取消</text>
</view>
<view class="uni-calendar__header-btn-box" @click="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">确定</text>
</view>
</view>
<view class="uni-calendar__header">
<view class="uni-calendar__header-btn-box" @click.stop="pre">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +'年'+( nowDate.month||'') +'月'}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<text class="uni-calendar__backtoday" @click="backtoday">回到今天</text>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import Calendar from './util.js';
import calendarItem from './uni-calendar-item.vue'
/**
* Calendar 日历
* @description 日历组件可以查看日期选择任意范围内的日期打点操作常用场景如酒店日期预订火车机票选择购买日期上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间默认为今天
* @property {Boolean} lunar 显示农历
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @event {Function} change 日期改变`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
calendarItem
},
props: {
date: {
type: String,
default: ''
},
selected: {
type: Array,
default () {
return []
}
},
lunar: {
type: Boolean,
default: false
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: '',
aniMaskShow: false
}
},
watch: {
date(newVal) {
this.cale.setDate(newVal)
this.init(this.cale.selectDate.fullDate)
},
startDate(val){
this.cale.resetSatrtDate(val)
},
endDate(val){
this.cale.resetEndDate(val)
},
selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
}
},
created() {
//
this.cale = new Calendar({
// date: new Date(),
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
//
this.cale.setDate(this.date)
this.init(this.cale.selectDate.fullDate)
// this.setDay
},
methods: {
// 穿
clean() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.cale.setDate(value)
this.init(value)
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
this.weeks = this.cale.weeks
this.nowDate = this.calendar = this.cale.getInfo(date)
},
/**
* 打开日历弹窗
*/
open() {
//
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
this.cale.setDate(this.date)
this.init(this.cale.selectDate.fullDate)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change() {
if (!this.insert) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
let {
year,
month,
date,
fullDate,
lunar,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
fulldate: fullDate,
lunar,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
//
this.cale.setMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
this.change()
},
/**
* 回到今天
*/
backtoday() {
console.log(this.cale.getDate(new Date()).fullDate);
let date = this.cale.getDate(new Date()).fullDate
this.cale.setDate(date)
this.init(date)
this.change()
},
/**
* 上个月
*/
pre() {
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
this.setDate(preDate)
this.monthSwitch()
},
/**
* 下个月
*/
next() {
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
this.setDate(nextDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss" scoped>
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
// padding: 0 15px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: $uni-text-color;
background-color: $uni-bg-color-hover;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 10px;
height: 10px;
border-left-color: $uni-text-color-placeholder;
border-left-style: solid;
border-left-width: 2px;
border-top-color: $uni-color-subtitle;
border-top-style: solid;
border-top-width: 2px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 45px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 14px;
}
.uni-calendar__box {
position: relative;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: $uni-text-color-grey;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
</style>

357
pages_qiun/components/uni-calendar/util.js

@ -0,0 +1,357 @@
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)
}
if (this.endDate) {
let dateCompAfter = this.dateCompare(fullDate, this.endDate)
disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
}
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

134
pages_qiun/components/wuc-tab/wuc-tab.vue

@ -0,0 +1,134 @@
<template>
<scroll-view class="wuc-tab" :class="tabClass" :style="tabStyle" scroll-with-animation scroll-x :scroll-left="scrollLeft">
<div v-if="!textFlex">
<div class="wuc-tab-item" :class="[index === tabCur ? selectClass + ' cur':'']" v-for="(item,index) in tabList" :key="index" :id="index" @tap="tabSelect(index,$event)">
<text :class="item.icon"></text>
<span>{{item.name}}</span>
</div>
</div>
<div class="flex text-center" v-if="textFlex">
<div class="wuc-tab-item flex-sub" :class="index === tabCur ? selectClass + ' cur':''" v-for="(item,index) in tabList" :key="index" :id="index" @tap="tabSelect(index,$event)">
<text :class="item.icon"></text>
<span>{{item.name}}</span>
</div>
</div>
</scroll-view>
</template>
<script>
export default {
name: 'wuc-tab',
data() {
return {};
},
props: {
tabList: {
type: Array,
default() {
return [];
}
},
tabCur: {
type: Number,
default() {
return 0;
}
},
tabClass: {
type: String,
default() {
return '';
}
},
tabStyle: {
type: String,
default() {
return '';
}
},
textFlex: {
type: Boolean,
default() {
return false;
}
},
selectClass: {
type: String,
default() {
return 'text-blue';
}
}
},
methods: {
tabSelect(index, e) {
if (this.currentTab === index) return false;
this.$emit('update:tabCur', index);
this.$emit('changeTab', this.tabList[index]);
}
},
computed: {
scrollLeft() {
return (this.tabCur - 1) * 60;
}
}
};
</script>
<style>
div,
scroll-view,
swiper {
box-sizing: border-box;
}
.wuc-tab {
white-space: nowrap;
}
.wuc-tab-item {
height: 90rpx;
display: inline-block;
line-height: 90rpx;
margin: 0 10upx;
padding: 0 20upx;
}
.wuc-tab-item.cur {
color: #40A2ED;
background-color: #fff;
}
.wuc-tab.fixed {
position: fixed;
width: 100%;
top: 0;
z-index: 1024;
box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1);
}
.flex {
display: flex;
}
.text-center {
text-align: center;
}
.flex-sub {
flex: 1;
}
.text-blue{
color:#40A2ED;
}
.text-white{
color:#ffffff;
}
.bg-white{
background-color: #ffffff;
}
.bg-blue{
background-color: #40A2ED;
}
.text-orange{
color: #f37b1d
}
.text-xl {
font-size: 36upx;
}
</style>

585
pages_qiun/pages/finance/index.vue

@ -0,0 +1,585 @@
<template>
<view class="body">
<!-- <view class="topLine" :style="{height: topBar+'px'}"></view> -->
<view class="nav row_align_center" id="nav">
<li class="li_4" style="color: #fff;z-index: 999;" :class="['iconfont icon-zuojiantou back']" @click="gotoBack()"></li>
</view>
<view class="top_head">
<view class="text_des">
<text class="month_num">{{ nowTime.month }}</text>
<text class="month_text"></text>
<text class="month_year">{{ nowTime.year }}</text>
<text class="point">.</text>
<text class="title">财务报告</text>
</view>
<view class="top_desc">
<view class="text-gray">结余</view>
<view class="remaining">{{ myWallet.remaining }}</view>
<view class="row head_block">
<view class="flex_1">
<text class="text-gray">支出</text>
<text class="text_green">{{ myWallet.expend }}</text>
</view>
<view class="flex_1">
<text class="text-gray">收入</text>
<text class="income">{{ myWallet.income }}</text>
</view>
</view>
</view>
</view>
<view class="main">
<view class="row_block">
<view class="the_title" style="justify-content: space-between;">
<view class="left_title">
<view class="title_icon"></view>
<text class="margin_stand-samll font-big wide">历史趋势</text>
</view>
<view class="right_btn">
<view v-for="(item, index) in historyBtn" :key="index" :class="item.state ? 'active_btn' : ''"
@click="changeHistoryBtn(item.type)">{{ item.name }}</view>
</view>
</view>
<view class="charts-box" style="height: 200px;">
<qiun-data-charts type="line" canvasId="finance_a" :canvas2d="isCanvas2d" :reshow="delayload"
:opts="{ xAxis: { itemCount: 12, disableGrid: true }, yAxis: { disableGrid: true, data: [{ disabled: true }] } }"
:chartData="historyData" />
</view>
</view>
<view class="row_block">
<view class="the_title">
<view class="title_icon"></view>
<text class="margin_stand-samll font-big wide">钱都去哪了</text>
</view>
<view v-if="delayload" class="charts-box">
<qiun-data-charts type="ring" canvasId="finance_b" :canvas2d="isCanvas2d" :reshow="delayload"
:opts="{ padding: [15, 0, 4, 0], legend: { position: 'bottom' }, title: { name: expendCount }, subtitle: { name: '支出', fontSize: '20' } }"
:chartData="expendDetail" />
</view>
<view class="the_title">
<text class="margin_stand-samll font-middle wide">支出单笔最贵</text>
</view>
<view class="extend_rank">
<view class="rank_item" v-for="(item, index) in extendRank" :key="index">
<image :src="getImage(index)" mode="widthFix"></image>
<text class="name">{{ item.name }}</text>
<text class="desc">{{ item.desc }}</text>
<text class="text_green money">{{ item.money }}</text>
</view>
</view>
</view>
<view class="row_block">
<view class="the_title">
<view class="title_icon"></view>
<text class="margin_stand-samll font-big wide">{{ nowTime.month }}月明细</text>
</view>
<view class="detail_list">
<view v-for="(item, index) in detail_list" :key="index" class="detail_item">
<view>
<view class="font-middle">{{ item.date }}</view>
<view class="font-small">{{ item.time }}</view>
</view>
<view class="icon">
<li class="li_2" :class="['iconfont', item.type == 'income' ? 'icon-income' : 'icon-expend']"></li>
</view>
<view class="right_content">
<view class="money">{{ item.type == 'income' ? '+' : '-' }}{{ item.money }}</view>
<view class="text-gray font-middle">{{ item.desc }}</view>
</view>
</view>
</view>
</view>
<view class="end_block">
<view class="the_title" style="margin-bottom: 40rpx;">
<view class="title_icon"></view>
<text class="margin_stand-samll font-big wide">我的支出水平</text>
</view>
<view class="level_bar">
<view v-for="(item, index) in extend_level_bar" :key="index" :style="{ width: item.width }"
:class="item.state ? 'text_green font-middle' : ''">{{ item.name }}</view>
</view>
<view class="level_bar">
<view v-for="(item, index) in extend_level_bar" :key="index" :style="{ width: item.width }"
:class="item.state ? 'active_bar' : 'default_bar'"></view>
</view>
<view class="level_bar">
<view v-for="(item, index) in extend_level_bar" :key="index" :style="{ width: item.width }"
:class="item.state ? 'text_green font-middle' : ''">{{ item.range }}</view>
</view>
<view class="extend_message">
<li style="color: #ccc;" :class="['iconfont icon-message']"></li>
<view>
我的支出水平已超过
<text>{{ extend_morethan }}</text>
的乡镇居民
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import ProgressBar from "../../components/progress-bar/progress-bar.vue"
import dataOne from '../../static/json/finance/1.json';
import expendDetail from '../../static/json/finance/2.json';
import Config from '../../static/js/config'
import Common from '../../static/js/common'
let _now = new Date();
let now_time = {};
now_time.year = _now.getFullYear()
now_time.month = _now.getMonth() + 1
now_time.day = _now.getDay()
export default {
components: {
ProgressBar
},
data() {
return {
info: '大便超人', //
scrollHeight: "600px", //
isCanvas2d: Config.ISCANVAS2D,
historyData: {},
dataOne,
expendDetail,
expendCount: 0,
delayload: false,
nowTime: {
year: now_time.year,
month: now_time.month,
day: now_time.day
},
historyBtn: [{
name: "支出",
state: 1,
type: "expend"
},
{
name: "收入",
state: 0,
type: "income"
},
{
name: "结余",
state: 0,
type: "remaining"
},
],
myWallet: {
remaining: 3000.34,
expend: 5240.32,
income: 8240.66
},
extendRank: [{
name: "腐败聚会",
desc: now_time.month + "月6日12:34-跨界空间轰趴",
money: "422.12"
},
{
name: "沐浴按摩",
desc: now_time.month + "月12日21:34-乔杉沐浴城",
money: "318.00"
},
{
name: "食品酒水",
desc: now_time.month + "月1日21:34-school酒馆",
money: "289.50"
},
],
extend_level_bar: [
{ name: "低消费", range: "<2000元", width: "20%" },
{ name: "中间消费", range: "2000-5000元", width: "35%" },
{ name: "较高消费", range: "5000-8000元", width: "25%", state: 1 },
{ name: "高消费", range: ">8000元", width: "20%" },
],
extend_morethan: "68%",
detail_list: [
{ date: now_time.month + "-01", time: "11:01", "type": "extend", money: "10.00", desc: "银行卡转出" },
{ date: now_time.month + "-01", time: "13:45", "type": "income", money: "18.00", desc: "银行卡收入" },
{ date: now_time.month + "-02", time: "06:21", "type": "extend", money: "123.45", desc: "信用卡转出" },
{ date: now_time.month + "-03", time: "07:38", "type": "income", money: "23.00", desc: "银行卡收入" },
{ date: now_time.month + "-08", time: "16:28", "type": "extend", money: "23.56", desc: "信用卡转出" },
{ date: now_time.month + "-09", time: "15:25", "type": "income", money: "850.12", desc: "银行卡收入" },
{ date: now_time.month + "-09", time: "18:52", "type": "income", money: "1.88", desc: "银行卡收入" },
{ date: now_time.month + "-11", time: "21:12", "type": "extend", money: "220.21", desc: "银行卡转出" },
{ date: now_time.month + "-12", time: "13:08", "type": "income", money: "32.28", desc: "银行卡收入" },
{ date: now_time.month + "-12", time: "12:41", "type": "extend", money: "122.12", desc: "信用卡转出" },
{ date: now_time.month + "-13", time: "17:21", "type": "income", money: "10.00", desc: "银行卡收入" },
]
};
},
watch: {
"historyBtn": {
deep: true,
handler: function (newVal, oldVal) {
this.filterHistoryData();
}
}
},
methods: {
async getData() {
uni.showLoading();
this.filterHistoryData();
for (let i = 0; i < this.expendDetail.series.length; i++) {
this.expendDetail.series[i].format = "pieDemo"
}
let length = this.expendDetail.series[0].data.length
for (let i = 0; i < length; i++) {
this.expendCount += this.expendDetail.series[0].data[i].value
}
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
},
changeHistoryBtn(type) {
for (let i = 0; i < this.historyBtn.length; i++) {
if (this.historyBtn[i].type == type) {
this.historyBtn[i].state = 1
} else {
this.historyBtn[i].state = 0
}
}
},
filterHistoryData() {
let type = this.historyBtn.filter(x => x.state == 1)[0].type;
switch (type) {
case "expend":
this.historyData = this.dataOne.expend;
break;
case "income":
this.historyData = this.dataOne.income;
break;
case "remaining":
this.historyData = this.dataOne.remaining;
break;
}
},
gotoBack() {
Common.navigateBack("/index/index");
},
getImage(index) {
switch (index) {
case 0:
return "https://s1.ax1x.com/2023/03/31/ppRYrfP.png";
break;
case 1:
return "https://s1.ax1x.com/2023/03/31/ppRYySf.png";
break;
case 2:
return "https://s1.ax1x.com/2023/03/31/ppRY6l8.png";
break;
}
}
},
onReady() {
//#ifndef H5
uni.showShareMenu();
//#endif
this.getData()
}
}
</script>
<style scoped lang="scss">
.body {
height: 100%;
background-color: #560594;
margin: 0;
padding-bottom: 20rpx;
.li_4 {
list-style-type: none;
}
.nav {
position: fixed;
top: 50rpx;
left: 20rpx;
}
.text_green {
color: #4ECDB6;
}
.main {
width: 100%;
padding: 0 10rpx;
box-sizing: border-box;
margin-top: 20rpx;
.detail_list {
height: 700rpx;
overflow: auto;
color: #9E9E9E;
.detail_item {
display: flex;
margin: 20rpx 0;
align-items: center;
.icon {
width: 30%;
text-align: center;
.li_2 {
font-size: 80rpx;
}
}
.right_content {
width: 50%;
text-align: center;
}
.icon-income {
color: #4AABF9;
}
.icon-expend {
color: #E45521;
}
.money {
color: #000;
}
}
}
.extend_message {
margin-top: 20rpx;
color: #ccc;
display: flex;
text {
color: #ff9900;
}
}
.level_bar {
width: 100%;
height: 40rpx;
border-radius: 40rpx;
overflow: hidden;
display: flex;
color: #ccc;
font-size: 20rpx;
text-align: right;
line-height: 40rpx;
view {
border-right: 2rpx solid #fff;
position: relative;
}
.name {
position: absolute;
top: -30rpx;
right: -40rpx;
}
.range {
position: absolute;
bottom: 30rpx;
right: -40rpx;
}
.default_bar {
background-color: #A0DFCD;
}
.active_bar {
background-color: #02AE7A;
}
}
.right_btn {
float: right;
display: flex;
color: #ccc;
font-size: 22rpx;
view {
line-height: 50rpx;
height: 50rpx;
margin: 0 20rpx;
}
.active_btn {
padding: 0rpx 20rpx;
border: 1px solid #ccc;
border-radius: 40rpx;
}
}
.end_block {
width: 100%;
box-sizing: border-box;
background-color: #fff;
border-radius: 12rpx;
position: relative;
padding: 20rpx;
}
.row_block {
width: 100%;
box-sizing: border-box;
background-color: #fff;
border-radius: 12rpx;
position: relative;
padding: 20rpx;
&::after {
content: "";
height: 0px;
width: 92%;
position: absolute;
transform: translateX(-50%);
left: 50%;
bottom: 0;
border-top: 1px dashed #ccc;
}
}
.the_title {
display: flex;
align-items: center;
.left_title {
display: flex;
align-items: center;
}
.title_icon {
background-color: #7E7E7E;
height: 40rpx;
width: 10rpx;
border-radius: 10rpx;
margin-right: 20rpx;
font-size: 16px;
font-weight: 600;
}
}
.extend_rank {
width: 100%;
background-color: #F5F5F5;
box-sizing: border-box;
padding: 10rpx;
.rank_item {
width: 100%;
margin: 20rpx 0;
box-sizing: border-box;
display: flex;
font-size: 26rpx;
justify-content: space-between;
align-items: center;
image {
width: 10%;
}
text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: block;
}
.name {
margin: 0 10rpx;
color: #7D7D7D;
width: 20%;
}
.desc {
width: 50%;
color: #ccc;
}
.money {
width: 20%;
text-align: right;
}
}
}
}
.top_head {
height: 435rpx;
width: 100%;
padding: 110rpx 10rpx 0rpx 10rpx;
background: url("https://img1.qunarzz.com/travel/d3/1704/db/34de73c353d44db5.jpg_r_640x426x70_53f464ca.jpg") no-repeat center 0px;
background-size: 100% 100%;
box-sizing: border-box;
.top_desc {
width: 100%;
border-radius: 20rpx;
background-color: #fff;
margin-top: 20rpx;
padding: 20rpx;
box-sizing: border-box;
.text-gray {
font-size: 28rpx;
color: #ccc;
margin-right: 10rpx;
}
.remaining {
font-size: 46rpx;
}
.flex_1 {
flex: 1;
}
.head_block {
margin-top: 20rpx;
.income {
color: #E34B5E;
}
}
}
.text_des {
height: 100rpx;
color: #fff;
font-weight: 900;
position: relative;
margin-left: 60rpx;
text {
display: inline-block;
height: 100%;
}
.month_num {
font-size: 90rpx;
}
.month_text {
font-size: 56rpx;
}
.month_year {
font-size: 22rpx;
position: absolute;
left: 60rpx;
top: 20rpx;
}
.point {
font-size: 40rpx;
}
.title {
font-size: 40rpx;
}
}
}
}
</style>

348
pages_qiun/pages/main/index.vue

@ -0,0 +1,348 @@
<template>
<view class="window">
<!-- #ifndef H5 -->
<view class="topLine" :style="{ height: topBar + 'px' }"></view>
<!-- #endif -->
<view class="nav row_align_center" id="nav">
<li class="li_5" :class="['iconfont icon-zuojiantou back']" @click="gotoBack()"></li>
<text class="title li_5">{{ title ? title : '' }}</text>
<li class="iconfont icon-zuojiantou back hidden"></li>
</view>
<view class="row_align_center head" id="head">
<!-- 日期下拉列表 -->
<drop-down ref="caleDrop" @tap="changDrop(1)" @changeItem="changeTime" :list="timeArray" :contentTop="top"
selectWidth="260rpx" contentLeft="0"></drop-down>
<!-- 日历选择日期 -->
<view v-if="showCalendar"
:class="['dropdown-item__selected', listWidth != '150rpx' ? 'dropdown-item__right' : 'dropdown-item__left']"
@click="openCalendar" class="calendar_drag">
<view class="selected__name">{{ nowDate }}</view>
<li class="iconfont icon-calendar" style="margin-left: 10rpx;"></li>
</view>
<!-- 公司区域下拉列表 -->
<drop-down ref="companyDrop" @tap="changDrop(2)" @changeItem="changeLocation" :list="locationArray"
:contentTop="top" contentRight="10" :selectWidth="showCalendar ? '200rpx' : '300rpx'" listWidth="75%">
</drop-down>
</view>
<uni-calendar ref="calendar" :insert="false" :start-date="startDate" :end-date="endDate" :clearDate="false"
@confirm="confirm">
</uni-calendar>
<!--滑动列表头-->
<wuc-tab id="wuctab" :tab-list="tabList" :tabCur.sync="tabCur" tab-class="text-center text-white bg-blue"
select-class="text-white"></wuc-tab>
<!--主体内容-->
<view class="data_body" :style="{ height: scrollHeight }">
<view v-if="tabCur == 0">
<wechat :scrollHeight="scrollHeight" />
</view>
<view v-else-if="tabCur == 1">
<user-operate :scrollHeight="scrollHeight" />
</view>
<view v-else-if="tabCur == 2">
<user-healthy :scrollHeight="scrollHeight" />
</view>
<view v-else-if="tabCur == 3">
<user-server :scrollHeight="scrollHeight"></user-server>
</view>
</view>
<!--水印-->
<view class="water-mark-mask row_wrap" :style="{ height: scrollHeight }">
<text class="container" v-for="(count, index) in 10" :key="index">{{ info.name }}</text>
</view>
</view>
</template>
<script>
import Wechat from "../../components/data-center/wechat.vue"
import UserOperate from "../../components/data-center/user-operate.vue"
import UserHealthy from "../../components/data-center/user-healthy.vue"
import UserServer from "../../components/data-center/user-server.vue"
import WucTab from '../../components/wuc-tab/wuc-tab.vue'
import DropDown from '../../components/drop-down/drop-down.vue'
import UniCalendar from '../../components/uni-calendar/uni-calendar.vue'
import Config from '../../static/js/config'
import Common from "../../static/js/common"
export default {
components: {
WucTab,
DropDown,
UniCalendar,
Wechat,
UserOperate,
UserHealthy,
UserServer,
},
data() {
return {
tabList: Config.TABLIST, //
timeArray: Config.TIMEARRAY, //
info: '大便超人', //
title: "数据报表中心", //
showDataTime: "today", //
tabCur: 0, //
topBar: 17, //
top: '180', //
scrollHeight: "100%", //
nowDate: Common.getNowDate(), //
endDate: Common.getNowDate(), //
startDate: Common.getPreMonth(Common.getNowDate()), //,
showCalendar: false,
};
},
computed: {
locationArray() {
return [{
value: "GDBJ-ENTRY-1",
text: "天猫"
}, {
value: "GDBJ-ENTRY-201",
text: "京东"
}];
}
},
methods: {
gotoBack() {
Common.navigateBack("/index/index");
},
changDrop(index) {
if (index == 1 && this.$refs.companyDrop.showList) {
this.$refs.companyDrop.closePopup()
} else if (index == 2 && this.$refs.caleDrop.showList) {
this.$refs.caleDrop.closePopup()
}
},
//
openCalendar() {
this.$refs.calendar.open();
},
//
confirm(e) {
if (this.nowDate != e.fulldate || !this.showCalendar) {
this.showCalendar = true;
this.$refs.caleDrop.selectAuto();
this.nowDate = e.fulldate;
this.showDataTime = e.fulldate.replace(/-/g, "");
Common.tipMsg("当前时间:" + this.showDataTime)
}
},
//
changeTime(e) {
if (e.value == "auto") {
this.openCalendar();
} else if (this.showDataTime != e.value) {
this.showDataTime = e.value;
this.showCalendar = false;
Common.tipMsg("当前时间:" + this.showDataTime)
}
},
changeLocation(e) {
Common.tipMsg("当前选中平台:" + e.text)
},
//
async getTelephoneInfo() {
var telephoneInfo = await Common.getTelephoneInfo();
let hasHeight = 0;
if (telephoneInfo.top >= 40) {
this.top = telephoneInfo.statusBarHeight * 2 + 150;
this.topBar = telephoneInfo.statusBarHeight;
}
//
const query = wx.createSelectorQuery();
query.select('#nav').boundingClientRect();
query.select('#head').boundingClientRect();
query.select('#wuctab').boundingClientRect();
query.exec(res => {
res.map((item, index) => {
hasHeight += item.height;
})
this.scrollHeight = (telephoneInfo.screenHeight - hasHeight - this.topBar) + 'px';
})
},
getH5Info() {
uni.getSystemInfo({
success: e => {
let hasHeight = 0;
let element = wx.createSelectorQuery().in(this);
element.select('#nav').boundingClientRect();
element.select('#head').boundingClientRect();
element.select('#wuctab').boundingClientRect();
element.exec(res => {
res.map((item, index) => {
hasHeight += item.height;
})
this.scrollHeight = (e.screenHeight - hasHeight) + 'px';
})
},
fail: (err) => {
reject(err);
}
})
}
},
onReady() {
//#ifndef H5
uni.showShareMenu();
this.getTelephoneInfo();
//#endif
//#ifdef H5
this.getH5Info();
//#endif
}
};
</script>
<style lang="scss">
page,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.li_5 {
list-style-type: none;
}
.window {
height: 100vh;
overflow: hidden;
.topLine {
background-color: #40A2ED;
width: 100%;
}
scroll-view {
box-sizing: border-box;
}
.swiper {
box-sizing: border-box;
}
.nav {
background-image: url(http://photo.gdbjyy.cn/image/BCAI/top_bg.jpg);
background-size: 100% 100%;
.back {
font-size: 54rpx;
padding: 20rpx 14rpx 15rpx 14rpx;
color: #fff;
}
.title {
color: #fff;
font-size: 30rpx;
flex: 1;
text-align: center;
}
.hidden {
visibility: hidden;
}
}
.head {
padding: 0 16rpx 14rpx 16rpx;
color: #fff;
background-color: #40A2ED;
justify-content: space-between;
font-size: 26rpx !important;
.calendar_drag {
width: 340rpx;
display: flex;
justify-content: center;
align-items: center;
.calendar_name {
margin-right: 10rpx;
}
.icon-calendar {
font-size: 26rpx;
margin-top: 4rpx;
}
}
}
.data_body {
overflow: auto;
text-align: center;
color: #333333;
background-repeat: repeat;
background-color: #ffffff;
position: relative;
.item {
padding: 0 20rpx;
margin-bottom: 20rpx;
.name {
font-weight: 600;
font-size: 36rpx;
}
.operate {
view {
padding: 5rpx 12rpx;
color: #fff;
}
.bg-blue {
background-color: #40A2ED;
}
.bg-yellow {
background-color: #FFC300;
}
}
.tip {
margin-bottom: 30rpx;
.update {
color: #C4100A;
margin-left: auto;
font-size: 30rpx;
}
}
}
.cry {
font-size: 96rpx;
margin-bottom: 10rpx;
}
}
}
.water-mark-mask {
width: 100%;
position: fixed;
left: 0;
bottom: 0;
z-index: 1000;
justify-content: space-between;
pointer-events: none; //
flex: 1;
overflow: hidden;
text {
width: 50%;
color: #909399;
opacity: 0.25;
transform: rotate(-15deg);
}
}
.histogram {
height: 100%;
width: 100%;
canvas {
margin-top: 40rpx;
}
}
</style>

259
pages_qiun/pages/school/index.vue

@ -0,0 +1,259 @@
<template>
<view class="body window">
<view class="topLine" :style="{ height: topBar + 'px' }"></view>
<view class="nav row_align_center" id="nav">
<li class="li_6" :class="['iconfont icon-zuojiantou back']" @click="gotoBack()"></li>
<text class="title">{{ title ? title : '' }}</text>
<li class="iconfont icon-zuojiantou back hidden li_6"></li>
</view>
<view class="data_body">
<scroll-view class="scroll_list" scroll-y :style="{ height: scrollHeight }">
<!-- 教学科研情况 -->
<view class="view_block">
<view class="title">教学科研情况</view>
<progress-bar :content="RankData" @updateRanking="updateRanking"></progress-bar>
</view>
<!-- 学历分布状况 -->
<view class="view_block">
<view class="title">学历分布状况
<text class="font-small" style="color: #ccc;">(教职工)</text>
</view>
<view class="charts-box" style="height: 300px;">
<qiun-data-charts type="rose" :chartData="ProductRateData" canvasId="school_a"
:canvas2d="isCanvas2d" :resshow="delayload" />
</view>
</view>
<!-- 学业成绩 -->
<view class="view_block">
<view class="title">学业成绩分布图
<text class="font-small" style="color: #ccc;">(班级)</text>
</view>
<view class="charts-box" style="height: 300px;">
<qiun-data-charts type="radar" :chartData="RadarModel" background="none" canvasId="school_b"
:animation="false" :canvas2d="isCanvas2d" :resshow="delayload" />
</view>
</view>
<!-- 图书借阅情况 -->
<view class="view_block">
<view class="title">图书借阅情况</view>
<view class="charts-box" style="height: 300px;">
<qiun-data-charts type="line" canvasId="school_c" :canvas2d="isCanvas2d" :resshow="delayload"
:ontouch="true"
:opts="{ enableScroll: true, xAxis: { scrollShow: true, itemCount: 4, disableGrid: true }, series: { style: 'curve' } }"
:chartData="friendTrand" />
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import ProgressBar from "../../components/progress-bar/progress-bar.vue"
import RankData from '../../static/json/school/1.json';
import ProductRateData from '../../static/json/school/2.json';
import RadarModel from '../../static/json/school/3.json';
import friendTrand from '../../static/json/school/4.json';
import Config from '../../static/js/config'
import Common from '../../static/js/common'
export default {
components: {
ProgressBar
},
data() {
return {
info: "大便超人", //
title: "智慧教育报表中心", //
showDataTime: "today", //
tabCur: 0, //
topBar: 17, //
top: '180', //
scrollHeight: "1400rpx", //
friendTrand,
RankData,
ProductRateData,
RadarModel,
isCanvas2d: Config.ISCANVAS2D,
delayload: false, //
};
},
computed: {
locationArray() {
return [{ value: "GDBJ-ENTRY-1", text: "天猫" }, { value: "GDBJ-ENTRY-201", text: "京东" }];
}
},
methods: {
async getData() {
uni.showLoading();
await setTimeout(() => {
this.delayload = true;
uni.hideLoading();
}, 1000)
},
gotoBack() {
Common.navigateBack("/index/index");
},
//
async getTelephoneInfo() {
var telephoneInfo = await Common.getTelephoneInfo();
let hasHeight = 0;
if (telephoneInfo.top >= 40) {
this.top = telephoneInfo.statusBarHeight * 2 + 150;
this.topBar = telephoneInfo.statusBarHeight;
}
//
const query = wx.createSelectorQuery();
query.select('#nav').boundingClientRect();
query.exec(res => {
res.map((item, index) => {
hasHeight += item.height;
})
this.scrollHeight = (telephoneInfo.screenHeight - hasHeight - this.topBar) + 'px';
})
},
updateRanking(nVal) {
this.RankData = nVal;
},
},
onLoad() {
//#ifndef H5
uni.showShareMenu();
//#endif
this.getData()
this.getTelephoneInfo();
}
}
</script>
<style scoped lang="scss">
.body {
height: 100vh;
margin: 0;
padding: 0 20rpx;
font-family: "montserrat";
background-image: linear-gradient(125deg, #CB9FFE, #5894F7, #ABCDFA, #74A3F6, #CB9FFE);
background-size: 400%;
animation: bganimation 15s infinite;
}
.li_6 {
list-style-type: none;
}
page,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.window {
height: 100vh;
overflow: hidden;
.topLine {
width: 100%;
}
scroll-view {
box-sizing: border-box;
}
.swiper {
box-sizing: border-box;
}
.nav {
background-size: 100% 100%;
.back {
font-size: 54rpx;
padding: 20rpx 14rpx 15rpx 14rpx;
color: #fff;
}
.title {
color: #fff;
font-size: 30rpx;
flex: 1;
text-align: center;
}
.hidden {
visibility: hidden;
}
}
.head {
padding: 0 16rpx 14rpx 16rpx;
color: #fff;
background-color: #40A2ED;
justify-content: space-between;
font-size: 26rpx !important;
.calendar_drag {
width: 340rpx;
display: flex;
justify-content: center;
align-items: center;
.calendar_name {
margin-right: 10rpx;
}
.icon-calendar {
font-size: 26rpx;
margin-top: 4rpx;
}
}
}
.data_body {
overflow: auto;
text-align: center;
color: #333333;
background-repeat: repeat;
height: 100%;
.scroll_list {
height: 100%;
.view_block {
background-color: #fff;
padding: 16rpx 20rpx 10rpx 20rpx;
border-radius: 20rpx;
margin-bottom: 40rpx;
.title {
text-align: left;
margin-bottom: 30rpx;
font-size: 30rpx;
}
.trend_title {
text-align: right;
font-size: 22rpx;
color: #ff9900;
margin-top: 50rpx;
}
}
}
}
}
@keyframes bganimation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
</style>

762
pages_qiun/pages/sport/index.vue

@ -0,0 +1,762 @@
<template>
<view class="body">
<view class="nav row_align_center" id="nav">
<li class="li_7" style="z-index: 999;font-size: 50rpx;" :class="['iconfont icon-zuojiantou back']" @click="gotoBack()">
</li>
</view>
<view class="head">
<view class="title">运动报告</view>
<view class="customer_img">
<!-- <open-data type="userAvatarUrl" class="img"></open-data> -->
<image class="img" src="https://s1.ax1x.com/2022/11/16/zZUoK1.jpg" mode="widthFix"></image>
</view>
</view>
<view class="score_view">
<view class="title">本次评分</view>
<view class="detail">
<view class="socre">98</view>
<li class="li_7" :class="['iconfont icon-up text-green']" @click="gotoBack()"></li>
<view class="up_socre">0.4</view>
</view>
</view>
<view class="census_view">
<view class="left">
<view class="text_gray small_text">消耗(千卡)</view>
<view class="middle_text text_wide_900">165</view>
</view>
<view class="right">
<view class="text_gray small_text">心率主要集中在</view>
<view style="font-size: 30rpx;">燃烧脂肪</view>
</view>
</view>
<view class="census_view">
<view class="left">
<view class="text_gray small_text">时长(分钟)</view>
<view class="middle_text text_wide_900">75</view>
</view>
<view class="center">
<view class="text_gray small_text">累计打卡()</view>
<view class="middle_text text_wide_900">24</view>
</view>
<view class="right">
<view class="text_gray small_text">平均心率(/分钟)</view>
<view class="middle_text text_wide_900">98</view>
</view>
</view>
<view class="consume_view">
<view class="wrap"><span class="consume_tip">身体消耗</span></view>
<li class="li_7" :class="['iconfont icon-niunai consume_icon']"></li>
<view class="desc">
<view class="small_text">约消耗</view>
<view class="text_wide_900"><text class="left">1000</text><text class="right">毫升牛奶</text></view>
</view>
</view>
<view class="heart_rate_view">
<view class="left">
<li class="li_7" :class="['iconfont icon-zhexiantu']"></li>
<text class="title">心率变化曲线</text>
</view>
<view class="right text_gray">心率变化</view>
</view>
<view v-if="heartRateData.series" class="heart_rate_chart">
<view class="charts-box">
<qiun-data-charts type="tline" canvasId="sport_a" :canvas2d="isCanvas2d" :resshow="delayload"
:opts="{ padding: [0, 20, 10, 0], legend: { position: 'top', lineHeight: 20 }, xAxis: { disableGrid: true, format: 'xAxisDemo3' }, yAxis: { data: [{ min: 0, max: 175 }], gridType: 'solid' }, dataLabel: false, dataPointShape: false }"
:chartData="heartRateData" />
</view>
</view>
<view class="title_view">
<view class="left">
<li class="li_7" :class="['iconfont icon-xinlv']"></li>
<text class="title">心率区间</text>
</view>
</view>
<view class="heart_rate_range">
<view class="top">
<view class="item" v-for="(item, index) in heatRateRange" :key="index">
<view class="name text_gray">{{ item.name }}</view>
<view class="data">{{ item.type }}{{ item.data }}<text class="unit text_gray">分钟</text></view>
</view>
</view>
<view v-if="heartRateRangeData" class="charts-box">
<qiun-data-charts type="ring" canvasId="sport_b" :canvas2d="isCanvas2d" :resshow="delayload"
:opts="{ legend: { position: 'bottom' }, extra: { ring: { border: false, centerColor: '#312C34' } }, title: { name: '' }, subtitle: { name: '' } }"
:chartData="heartRateRangeData" />
</view>
</view>
<view class="title_view">
<view class="left">
<li class="li_7" :class="['iconfont icon-pie']"></li>
<text class="title">运动分析</text>
</view>
</view>
<view class="sport_analysis_view">
<view class="top">
<li class="iconfont icon-feiji li_7"></li>
<text class="title font-s-34">跑步机</text>
</view>
<view class="middle">
<view class="left">
<li class="iconfont icon-clock li_7"></li>
<view>3.24P.M</view>
</view>
<view class="right">
<li class="iconfont icon-huo li_7"></li>
<view>热量消耗(千卡)</view>
</view>
</view>
<view class="bottom">
<view class="left">
<li class="iconfont icon-kongxinyuan li_7"></li>
<view>燃烧脂肪</view>
</view>
<view class="right">
<view class="text_wide_600 font-s-40">637</view>
</view>
</view>
</view>
<view class="box_view speed_rank_view">
<view class="top">
<view class="item" v-for="(item, index) in speedRank" :key="index">
<view class="name text_gray">{{ item.name }}</view>
<view class="data">{{ item.data }}<text class="unit text_gray">{{ item.unit }}</text></view>
</view>
</view>
<view v-if="speedRankData" class="charts-box">
<qiun-data-charts type="bar" canvasId="sport_c" :canvas2d="isCanvas2d" :resshow="delayload"
:chartData="speedRankData" background="none"
:opts="{ xAxis: { disabled: true, disableGrid: true }, extra: { bar: { barBorderCircle: true, width: 20 } }, legend: { show: false } }" />
</view>
</view>
<view class="box_view">
<view v-if="speedAndRateData.series" class="charts-box">
<qiun-data-charts type="tline" canvasId="sport_d" :canvas2d="isCanvas2d" :resshow="delayload"
:opts="{ padding: [0, 20, 10, 0], legend: { position: 'top', lineHeight: 20 }, xAxis: { disableGrid: true, format: 'xAxisDemo3' }, yAxis: { data: [{ position: 'left', min: 0, max: 25 }, { position: 'right', min: 50, max: 175 }], gridType: 'solid' }, dataLabel: false, dataPointShape: false }"
:chartData="speedAndRateData" />
</view>
</view>
</view>
</template>
<script>
import heartRateData from "../../static/json/sport/1.json"
import heartRateRangeData from "../../static/json/sport/2.json"
import speedRankData from "../../static/json/sport/3.json"
import speedAndRateData from "../../static/json/sport/4.json"
import Config from '../../static/js/config'
import Common from '../../static/js/common'
export default {
components: {
},
data() {
return {
info: '大便超人', //
isCanvas2d: Config.ISCANVAS2D,
heartRateData: {},
speedRankData: {},
speedAndRateData: {},
delayload: null,
heartRateRangeData: {},
heatRateRange: [{
name: "激活放松",
data: "5",
type: "≤"
},
{
name: "动态热身",
data: "13",
type: ""
},
{
name: "脂肪燃烧",
data: "24",
type: ""
},
{
name: "糖分消耗",
data: "8",
type: "≤"
},
{
name: "心肺训练",
data: "7",
type: ""
},
{
name: "极限锻炼",
data: "16",
type: ""
},
],
speedRank: [{
name: "距离",
data: "5",
unit: "公里"
},
{
name: "时长",
data: "12",
unit: "分钟"
},
{
name: "平均配速",
data: "6\'05\"",
unit: ""
}
]
};
},
watch: {
},
methods: {
async getData() {
uni.showLoading();
/*将钟点时间随机转成某一天的具体时间戳*/
if (typeof heartRateData.series[0].data[0][0] == 'string') {
for (let i = 0; i < heartRateData.series.length; i++) {
heartRateData.series[i].data.map(x => {
x[0] = "2018/08/08 " + x[0];
x[0] = this.tranTimestamp(x[0]);
return x[0];
})
}
}
if (typeof speedAndRateData.series[0].data[0][0] == 'string') {
for (let i = 0; i < speedAndRateData.series.length; i++) {
speedAndRateData.series[i].data.map(x => {
x[0] = "2018/08/08 " + x[0];
x[0] = this.tranTimestamp(x[0]);
return x[0];
})
}
}
this.heartRateData = heartRateData;
this.heartRateRangeData = heartRateRangeData;
this.speedRankData = speedRankData;
this.speedAndRateData = speedAndRateData;
this.delayload = true;
uni.hideLoading();
},
tranTimestamp(date) {
return new Date(date).getTime()
},
gotoBack() {
Common.navigateBack("/index/index");
},
},
onReady() {
//#ifndef H5
uni.showShareMenu();
//#endif
this.getData()
}
}
</script>
<style scoped lang="scss">
.body {
height: 100%;
background-color: #1C191F;
margin: 0;
color: #fff;
padding: 80rpx 20rpx 0 20rpx;
width: 100%;
box-sizing: border-box;
padding-bottom: 50rpx;
.box_view {
width: 100%;
padding: 20rpx;
position: relative;
background-color: #312C34;
color: #FFFFFF;
box-sizing: border-box;
border-radius: 20rpx;
overflow: hidden;
margin-top: 30rpx;
}
.speed_rank_view {
.top {
width: 100%;
&:after {
content: "";
clear: both;
display: block;
}
.item {
float: left;
width: 33%;
box-sizing: border-box;
padding: 30rpx 20rpx;
text-align: left;
.name {
font-size: 26rpx;
}
.data {
font-size: 40rpx;
margin-top: 10rpx;
.unit {
font-size: 24rpx;
margin-left: 14rpx;
}
}
}
}
}
.sport_analysis_view {
width: 100%;
padding: 20rpx;
position: relative;
background-color: #312C34;
color: #FFFFFF;
box-sizing: border-box;
border-radius: 20rpx;
overflow: hidden;
.top {
width: 100%;
height: 120rpx;
display: flex;
align-items: center;
.icon-feiji {
margin-top: 10rpx;
}
.title {
margin-left: 10rpx;
}
}
.middle {
width: 100%;
display: flex;
justify-content: space-between;
font-size: 28rpx;
.iconfont {
font-size: 28rpx;
margin-right: 10rpx;
margin-top: 4rpx;
}
.left {
width: 50%;
height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-start;
}
.right {
width: 50%;
height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.bottom {
width: 100%;
display: flex;
justify-content: space-between;
font-size: 28rpx;
.iconfont {
font-size: 28rpx;
margin-right: 10rpx;
margin-top: 4rpx;
}
.left {
width: 50%;
height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-start;
.icon-kongxinyuan {
color: #6FCEF7;
}
}
.right {
width: 50%;
height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.heart_rate_range {
width: 100%;
position: relative;
background-color: #312C34;
color: #FFFFFF;
box-sizing: border-box;
border-radius: 20rpx;
overflow: hidden;
.top {
width: 100%;
&:after {
content: "";
clear: both;
display: block;
}
.item {
float: left;
width: 33%;
box-sizing: border-box;
padding: 30rpx 20rpx;
text-align: center;
.name {
font-size: 26rpx;
}
.data {
font-size: 40rpx;
margin-top: 10rpx;
.unit {
font-size: 24rpx;
margin-left: 14rpx;
}
}
}
}
}
.heart_rate_chart {
display: flex;
justify-content: center;
width: 100%;
position: relative;
background-color: #312C34;
color: #FFFFFF;
box-sizing: border-box;
border-radius: 20rpx;
overflow: hidden;
}
.title_view {
display: flex;
width: 100%;
align-items: center;
height: 150rpx;
.left {
display: flex;
align-items: center;
.iconfont {
font-size: 40rpx !important;
}
.title {
font-size: 34rpx;
margin-left: 20rpx;
}
}
}
.heart_rate_view {
display: flex;
width: 100%;
justify-content: space-around;
align-items: center;
height: 150rpx;
.left {
display: flex;
align-items: center;
.icon-zhexiantu {
font-size: 26rpx;
}
.title {
font-size: 34rpx;
margin-left: 20rpx;
}
}
.right {
font-size: 22rpx;
padding: 10rpx 30rpx;
border-radius: 40rpx;
background-color: #342E39;
}
}
.consume_view {
display: flex;
justify-content: center;
width: 100%;
height: 190rpx;
position: relative;
margin-top: 100rpx;
background-color: #312C34;
color: #FFFFFF;
box-sizing: border-box;
border-radius: 10rpx;
.consume_img {
width: 240rpx;
height: auto;
position: absolute;
top: -80rpx;
left: 20rpx;
}
.consume_icon {
font-size: 220rpx;
position: absolute;
top: -80rpx;
left: 20rpx;
}
.desc {
position: absolute;
right: 80rpx;
top: 20rpx;
view {
padding: 10rpx 0;
display: flex;
align-items: center;
}
.left {
font-size: 50rpx;
}
.right {
font-size: 30rpx;
margin-left: 10rpx;
font-weight: 400;
}
}
}
.text-green {
color: #10A764;
}
.text_gray {
color: #8E8B8B;
}
.small_text {
font-size: 24rpx;
}
.font-s-34 {
font-size: 34rpx;
}
.font-s-36 {
font-size: 36rpx;
}
.font-s-38 {
font-size: 38rpx;
}
.font-s-40 {
font-size: 40rpx;
}
.middle_text {
font-size: 36rpx;
}
.text_wide_900 {
font-weight: 900;
}
.text_wide_600 {
font-weight: 600;
}
.census_view {
width: 100%;
display: flex;
justify-content: space-around;
.left {
text-align: left;
view {
padding: 10rpx 0;
}
}
.center {
text-align: center;
view {
padding: 10rpx 0;
}
}
.right {
text-align: right;
view {
padding: 10rpx 0;
}
}
}
.score_view {
width: 100%;
.title {
color: #8E8B8B;
font-size: 24rpx;
}
.detail {
height: 120rpx;
width: 100%;
display: flex;
align-items: flex-end;
.icon-up {
margin-left: 40rpx;
height: 54rpx;
font-weight: 600;
}
.socre {
font-size: 80rpx;
font-weight: 900;
}
.up_socre {
color: #10A764;
height: 50rpx;
font-size: 24rpx;
font-weight: 600;
}
}
}
.head {
height: 140rpx;
line-height: 140rpx;
position: relative;
.title {
font-size: 40rpx;
margin-left: 20rpx;
}
.customer_img {
position: absolute;
bottom: 0rpx;
right: 20rpx;
width: 100rpx;
height: 100rpx;
margin: 0;
padding: 0;
background-size: 100% 100%;
border-radius: 100%;
overflow: hidden;
.img {
height: auto;
width: 100%;
}
}
}
.li_7 {
list-style-type: none;
}
.nav {
position: fixed;
top: 50rpx;
left: 20rpx;
}
}
.consume_view:nth-child(even) {
margin-right: 4%;
}
.consume_tip {
display: inline-block;
text-align: center;
width: 188rpx;
height: 30rpx;
line-height: 30rpx;
position: absolute;
top: 36rpx;
right: -44rpx;
z-index: 2;
overflow: hidden;
transform: rotate(45deg);
-ms-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
border: 1px dashed;
box-shadow: 0 0 0 3px #10A764, 0px 21px 5px -18px rgba(0, 0, 0, 0.6);
background: #10A764;
font-size: 16rpx;
}
.wrap {
width: 100%;
height: 100%;
position: absolute;
top: -12rpx;
left: 12rpx;
overflow: hidden;
}
.wrap:before {
content: "";
display: block;
border-radius: 8px 8px 0px 0px;
width: 80rpx;
height: 14rpx;
position: absolute;
right: 68rpx;
top: -1px;
background: #4D6530;
}
.wrap:after {
content: "";
display: block;
border-radius: 0px 8px 8px 0px;
width: 14rpx;
height: 80rpx;
position: absolute;
right: -1px;
top: 66rpx;
background: #4D6530;
}</style>

170
pages_qiun/static/js/common.js

@ -0,0 +1,170 @@
let isReadyLogin = 1
let loginFlag = 1
export default {
//提示窗
tipMsg: function (title, icon, time, mask,callback) {
title = title == undefined ? "系统繁忙" : title;
icon = icon == undefined ? "none" : icon;
time = time == undefined ? 1300 : time;
mask = mask == undefined ? true : mask;
uni.showToast({
title: title,
icon: icon,
mask: mask,
duration: time,
success() {
if(callback){
setTimeout(()=>{
callback()
},time);
}
}
})
},
getTelephoneInfo(){
return new Promise((resolve, reject) => {
var data = uni.getStorageSync("telephoneInfo");
if(!data){
// 获取右上角胶囊的位置信息
//#ifndef H5
let btn = wx.getMenuButtonBoundingClientRect();
uni.getSystemInfo({
success: e => {
let info = {
screenHeight:e.screenHeight,
statusBarHeight:e.statusBarHeight,
windowWidth:e.windowWidth,
top:btn.top
}
uni.setStorageSync("telephoneInfo",info);
resolve(info);
},
fail: (err) => {
reject(err);
}
})
//#endif
}else{
resolve(data);
}
})
},
// 获取当前年月日
getNowDate(){
let date = new Date;
let now = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate();
return now;
},
// 获取上个月的年月日
getPreMonth(date) {
var arr = date.split('-');
var year = arr[0]; //获取当前日期的年份
var month = arr[1]; //获取当前日期的月份
var day = arr[2]; //获取当前日期的日
var days = new Date(year, month, 0);
days = days.getDate(); //获取当前日期中月的天数
var year2 = year;
var month2 = parseInt(month) - 1;
if (month2 == 0) {
year2 = parseInt(year2) - 1;
month2 = 12;
}
var day2 = day;
var days2 = new Date(year2, month2, 0);
days2 = days2.getDate();
if (day2 > days2) {
day2 = days2;
}
if (month2 < 10) {
month2 = '0' + month2;
}
var t2 = year2 + '-' + month2 + '-' + "01";
return t2;
},
//检测小程序更新
checkUpdateVersion(){
//新版本更新
if (uni.canIUse('getUpdateManager')) {
//判断当前微信版本是否支持版本更新
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate(function (res) {
if (res.hasUpdate) {
// 请求完新版本信息的回调
updateManager.onUpdateReady(function () {
uni.showModal({
title: '更新提示',
content: '已更新版本,是否重启小程序?',
showCancel:false,
cancelColor:'#eeeeee',
confirmColor:'#40A2ED',
success: function (res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
}
},
});
});
// 新的版本下载失败
updateManager.onUpdateFailed(function () {
uni.showModal({
title: '更新失败',
content: '请检查网络设置,若仍更新失败,重新搜索打开',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
}
}
});
});
}
});
} else {
uni.showModal({
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。',
});
}
},
/**
* @param {string} url 目标页面的路由
* @param {Object} param 传递给目标页面的参数
* @description 处理目标页面的参数转成json字符串传递给param字段在目标页面通过JSON.parse(options.param)接收
*/
navigateTo(url, param = {},flag) {
if(isReadyLogin<=0 && !flag){
this.loginTip();
}else{
let part = '';
for(var item in param){
part += '&' + item + '=' + param[item];
}
url = url + part.replace('&','?');
uni.navigateTo({
url: url,
fail:err=> {
this.tipMsg('页面正在火速开发中,敬请期待!');
},
})
}
},
navigateBack(url, param = {}) {
if (loginFlag <= 0) {
this.tipMsg("很抱歉,你没有权限!");
} else {
let part = '';
for (var item in param) {
part += '&' + item + '=' + param[item];
}
url = "/pages" + url + part.replace('&', '?');
uni.navigateBack({
url: url,
fail: err => {
this.tipMsg('暂未开放该功能!');
},
})
}
},
}

79
pages_qiun/static/js/config.js

@ -0,0 +1,79 @@
const COLOR = [
"#EE6A66", "#6BC588", "#FFC300", "#24ABFD"
];
var ISCANVAS2D = true;
switch (uni.getSystemInfoSync().platform) {
case 'android':
ISCANVAS2D = true
break;
case 'ios':
ISCANVAS2D = true
break;
default:
ISCANVAS2D = false
break;
}
const RESPOND = {
success: 0,
warn: 301,
error: 500,
};
const TIMEARRAY = [
{
text: '当天',
value: 'today'
},
{
text: '昨天',
value: 'yesterday'
},
{
text: '本周',
value: 'week'
},
{
text: '上周',
value: 'weeklast'
},
{
text: '本月',
value: 'month'
},
{
text: '上月',
value: 'monthlast'
},
{
text: '指定日期',
value: 'auto'
}
];
const TABLIST = [
{name:"企业微信",type:"WECHAT"},
{name:"会员运营",type:"OPERATE"},
{name:"会员健康",type:"GJJK"},
{name:"会员服务",type:"SERVICE"},
];
const CARD_MENU = [
{title:"会员报表中心",author:"howcode",img:"https://s1.ax1x.com/2023/03/31/ppRp4iV.jpg",url:"/myPackageA/pages/main/index"},
{title:"智慧教育报表中心",author:"howcode",img:"https://s1.ax1x.com/2023/03/31/ppRp5GT.jpg",url:"/myPackageA/pages/school/index"},
{title:"差旅报表中心",author:"秋云",img:"https://s1.ax1x.com/2023/03/31/ppRpfI0.jpg",url:""},
{title:"运动报表中心",author:"howcode",img:"https://s1.ax1x.com/2023/03/31/ppRpWaq.jpg",url:"/myPackageA/pages/sport/index"},
{title:"财务报表中心",author:"howcode",img:"https://s1.ax1x.com/2023/03/31/ppRpozF.jpg",url:"/myPackageA/pages/finance/index"},
]
export default {
COLOR,
TIMEARRAY,
TABLIST,
RESPOND,
ISCANVAS2D,
CARD_MENU
}

68
pages_qiun/static/json/finance/1.json

@ -0,0 +1,68 @@
{
"expend":{
"categories": [
"1月",
"2月",
"2月",
"4月",
"5月"
],
"series": [
{
"name": "支出情况",
"data": [1201,2501.5,985,1760,2013.85],
"type": "line",
"style": "curve",
"color": "#4ECDB6",
"unit":""
}
],
"yAxis":[
{"calibration":true,"position":"left","title":"单位/元","titleFontSize":12,"unit":"","tofix":0,"min":0,"disableGrid":true}
]
},
"income":{
"categories": [
"1月",
"2月",
"2月",
"4月",
"5月"
],
"series": [
{
"name": "收入情况",
"data": [1601,1840.5,1900,1760,1500.85],
"type": "line",
"style": "curve",
"color": "#4ECDB6",
"unit":""
}
],
"yAxis":[
{"calibration":true,"position":"left","title":"单位/元","titleFontSize":12,"unit":"","tofix":0,"min":0,"disableGrid":true}
]
},
"remaining":{
"categories": [
"1月",
"2月",
"2月",
"4月",
"5月"
],
"series": [
{
"name": "结余情况",
"data": [815,712.5,378,450,600.85],
"type": "line",
"style": "curve",
"color": "#4ECDB6",
"unit":""
}
],
"yAxis":[
{"calibration":true,"position":"left","title":"单位/元","titleFontSize":12,"unit":"","tofix":0,"min":0,"disableGrid":true}
]
}
}

33
pages_qiun/static/json/finance/2.json

@ -0,0 +1,33 @@
{
"series": [
{
"data":[
{
"name": "住房相关",
"value": 3200,
"color":"#4DCCB3"
},
{
"name": "食品酒水",
"value": 1020,
"color":"#5A77EC"
},
{
"name": "娱乐休闲",
"value": 500,
"color":"#4E94EC"
},
{
"name": "交流通讯",
"value": 214.5,
"color":"#4FD4EB"
},
{
"name": "其他",
"value": 320.13,
"color":"#B5ED21"
}
]
}
]
}

26
pages_qiun/static/json/school/1.json

@ -0,0 +1,26 @@
[
{
"name":"课题研究",
"num":500,
"width":"",
"background":"#FFBE68"
},
{
"name":"论文发布",
"num":300,
"width":"",
"background":"#0FEBE1"
},
{
"name":"实践研究",
"num":455,
"width":"",
"background":"#BF8DFC"
},
{
"name":"评教",
"num":601,
"width":"",
"background":"#FF859C"
}
]

28
pages_qiun/static/json/school/2.json

@ -0,0 +1,28 @@
{
"series": [
{
"data": [
{
"name": "本科",
"value": 168,
"color": "#FFBF31"
},
{
"name": "大专",
"value": 144,
"color": "#3CEFC4"
},
{
"name": "博士",
"value": 123,
"color": "#FFA9B3"
},
{
"name": "硕士",
"value": 96,
"color": "#3CBBFF"
}
]
}
]
}

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

Loading…
Cancel
Save