榆钱落尽槿花稀 448712ece5 feat: 添加积分申请系统基础功能与UI组件
本次提交主要包含以下内容:

1. 新增积分申请系统核心功能:
   - 添加登录页面及API接口
   - 实现积分申请记录查看功能
   - 集成微信小程序分享功能
   - 添加请求管理工具类

2. 引入Tuniao UI组件库:
   - 添加时间线、折叠面板、表格等UI组件
   - 集成头像组、单选框组等交互组件
   - 配置全局样式和主题颜色

3. 基础架构搭建:
   - 配置项目manifest和pages.json路由
   - 添加状态管理store
   - 实现自定义导航栏适配
   - 添加工具函数(加解密、数字处理等)

4. 静态资源:
   - 添加项目logo和背景图片
   - 配置uni.scss全局样式变量

本次提交为系统基础功能搭建,后续将进一步完善积分申请流程和审批功能。
2025-05-27 16:40:02 +08:00

232 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view
class="tn-count-num-class tn-count-num"
:class="[fontColorClass]"
:style="{
fontSize: fontSizeStyle || '50rpx',
fontWeight: bold ? 'bold' : 'normal',
color: fontColorStyle || '#080808'
}"
>
{{ displayValue }}
</view>
</template>
<script>
import componentsColorMixin from '../../libs/mixin/components_color.js'
export default {
name: 'tn-count-to',
mixins: [componentsColorMixin],
props: {
// 开始的数值默认为0
startVal: {
type: Number,
default: 0
},
// 结束目标数值
endVal: {
type: Number,
default: 0,
required: true
},
// 是否自动开始
autoplay: {
type: Boolean,
default: true
},
// 滚动到目标值的持续时间,单位为毫秒
duration: {
type: Number,
default: 2000
},
// 是否在即将结束的时候使用缓慢滚动的效果
useEasing: {
type: Boolean,
default: true
},
// 显示的小数位数
decimals: {
type: Number,
default: 0
},
// 十进制的分割符
decimalSeparator: {
type: String,
default: '.'
},
// 千分位的分隔符
// 类似金额的分割(¥23,321.05中的",")
thousandthsSeparator: {
type: String,
default: ''
},
// 是否显示加粗字体
bold: {
type: Boolean,
default: false
}
},
computed: {
countDown() {
return this.startVal > this.endVal
}
},
data() {
return {
localStartVal: this.startVal,
localDuration: this.duration,
// 显示的数值
displayValue: this.formatNumber(this.startVal),
// 打印的数值
printValue: null,
// 是否暂停
paused: false,
// 开始时间戳
startTime: null,
// 停留时间戳
remainingTime: null,
// 当前时间戳
timestamp: null,
// 上一次的时间戳
lastTime: 0,
rAF: null
}
},
watch: {
startVal() {
this.autoplay && this.start()
},
endVal() {
this.autoplay && this.start()
}
},
mounted() {
this.autoplay && this.start()
},
methods: {
// 开始滚动
start() {
this.localStartVal = this.startVal
this.startTime = null
this.localDuration = this.duration
this.paused = false
this.rAF = this.requestAnimationFrame(this.count)
},
// 重新开始
reStart() {
if (this.paused) {
this.resume()
this.paused = false
} else {
this.stop()
this.paused = true
}
},
// 停止
stop() {
this.cancelAnimationFrame(this.rAF)
},
// 恢复
resume() {
this.startTime = null
this.localDuration = this.remainingTime
this.localStartVal = this.printValue
this.requestAnimationFrame(this.count)
},
// 重置
reset() {
this.startTime = null
this.cnacelAnimationFrame(this.rAF)
this.displayValue = this.formatNumber(this.startVal)
},
// 销毁组件
destroyed() {
this.cancelAnimationFrame(this.rAF)
},
// 累加时间
count(timestamp) {
if (!this.startTime) this.startTime = timestamp
this.timestamp = timestamp
const progress = timestamp - this.startTime
this.remainingTime = this.localDuration - progress
if (this.useEasing) {
if (this.countDown) {
this.printValue = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
} {
this.printValue = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration)
}
} else {
if (this.countDown) {
this.printValue = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration)
} else {
this.printValue = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration)
}
}
if (this.countDown) {
this.printValue = this.printValue < this.endVal ? this.endVal : this.printValue
} else {
this.printValue = this.printValue > this.endVal ? this.endVal : this.printValue
}
this.displayValue = this.formatNumber(this.printValue)
if (progress < this.localDuration) {
this.rAF = this.requestAnimationFrame(this.count)
} else {
this.$emit('end')
}
},
// 缓动时间计算
easingFn(t, b, c, d) {
return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b
},
// 请求帧动画
requestAnimationFrame(cb) {
const currentTime = new Date().getTime()
// 为了使setTimteout的尽可能的接近每秒60帧的效果
const timeToCall = Math.max(0, 16 - (currentTime - this.lastTime))
const timerId = setTimeout(() => {
cb && cb(currentTime + timeToCall)
}, timeToCall)
this.lastTime = currentTime + timeToCall
return timerId
},
// 清除帧动画
clearAnimationFrame(timerId) {
clearTimeout(timerId)
},
// 格式化数值
formatNumber(number) {
const reg = /(\d+)(\d{3})/
number = Number(number)
number = number.toFixed(Number(this.decimals))
number += ''
const numberArray = number.split('.')
let num1 = numberArray[0]
const num2 = numberArray.length > 1 ? this.decimalSeparator + numberArray[1] : ''
if (this.thousandthsSeparator && !this.isNumber(this.thousandthsSeparator)) {
while(reg.test(num1)) {
num1 = num1.replace(reg, '$1' + this.thousandthsSeparator + '$2')
}
}
return num1 + num2
},
// 判断是否为数字
isNumber(val) {
return !isNaN(parseFloat(val))
}
}
}
</script>
<style lang="scss" scoped>
.tn-count-num {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
text-align: center;
line-height: 1;
}
</style>