榆钱落尽槿花稀 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

365 lines
9.6 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-swiper__wrap-class tn-swiper__wrap" :style="{borderRadius: `${radius}rpx`}">
<!-- 轮播图 -->
<swiper
class="tn-swiper"
:class="[backgroundColorClass]"
:style="[swiperStyle]"
:current="current"
:interval="interval"
:circular="circular"
:autoplay="autoplay"
:duration="duration"
:previous-margin="effect3d ? effect3dPreviousSpacing + 'rpx' : '0'"
:next-margin="effect3d ? effect3dPreviousSpacing + 'rpx' : '0'"
@change="change"
>
<swiper-item
v-for="(item, index) in list"
:key="index"
class="tn-swiper__item"
>
<view
class="tn-swiper__item__image__wrap"
:class="[swiperIndex !== index ? 'tn-swiper__item__image--scale' : '']"
:style="{
borderRadius: `${radius}rpx`,
transform: effect3d && swiperIndex !== index ? 'scaleY(0.9)' : 'scaleY(1)',
margin: effect3d && swiperIndex !== index ? '0 20rpx' : 0
}"
@click="click(index)"
>
<image class="tn-swiper__item__image" :src="item[name] || item" :mode="imageMode"></image>
<view
v-if="title && item[titleName]"
class="tn-swiper__item__title tn-text-ellipsis"
:style="[titleStyle]">
{{ item[titleName] }}
</view>
</view>
</swiper-item>
</swiper>
<!-- 指示点 -->
<view class="tn-swiper__indicator" :style="[indicatorStyle]">
<block v-if="mode === 'rect'">
<view
v-for="(item, index) in list"
:key="index"
class="tn-swiper__indicator__rect"
:class="{'tn-swiper__indicator__rect--active': swiperIndex === index}"
></view>
</block>
<block v-if="mode === 'dot'">
<view
v-for="(item, index) in list"
:key="index"
class="tn-swiper__indicator__dot"
:class="{'tn-swiper__indicator__dot--active': swiperIndex === index}"
></view>
</block>
<block v-if="mode === 'round'">
<view
v-for="(item, index) in list"
:key="index"
class="tn-swiper__indicator__round"
:class="{'tn-swiper__indicator__round--active': swiperIndex === index}"
></view>
</block>
<block v-if="mode === 'number'">
<view class="tn-swiper__indicator__number">{{ swiperIndex + 1 }}/{{ list.length }}</view>
</block>
</view>
</view>
</template>
<script>
export default {
name: 'tn-swiper',
props: {
// 轮播图列表数据
// [{image: xxx.jpg, title: 'xxxx'}]
list: {
type: Array,
default() {
return []
}
},
// 初始化时,默认显示第几项
current: {
type: Number,
default: 0
},
// 高度
height: {
type: Number,
default: 250
},
// 背景颜色
backgroundColor: {
type: String,
default: 'transparent'
},
// 图片的属性名
name: {
type: String,
default: 'image'
},
// 是否显示标题
title: {
type: Boolean,
default: false
},
// 标题的属性名
titleName: {
type: String,
default: 'title'
},
// 用户自定义标题样式
titleStyle: {
type: Object,
default() {
return {}
}
},
// 圆角的值
radius: {
type: Number,
default: 8
},
// 指示器模式
// rect -> 方形 round -> 圆角方形 dot -> 点 number -> 轮播图下标
mode: {
type: String,
default: 'round'
},
// 指示器位置
// topLeft \ topCenter \ topRight \ bottomLeft \ bottomCenter \ bottomRight
indicatorPosition: {
type: String,
default: 'bottomCenter'
},
// 开启3D缩放效果
effect3d: {
type: Boolean,
default: false
},
// 在3D缩放模式下item之间的间隔
effect3dPreviousSpacing: {
type: Number,
default: 50
},
// 自定播放
autoplay: {
type: Boolean,
default: true
},
// 图片之间播放间隔多久
interval: {
type: Number,
default: 3000
},
// 轮播间隔时间
duration: {
type: Number,
default: 500
},
// 是否衔接滑动
circular: {
type: Boolean,
default: true
},
// 图片裁剪模式
imageMode: {
type: String,
default: 'aspectFill'
}
},
computed: {
backgroundColorStyle() {
return this.$t.color.getBackgroundColorStyle(this.backgroundColor)
},
backgroundColorClass() {
return this.$t.color.getBackgroundColorInternalClass(this.backgroundColor)
},
swiperStyle() {
let style = {}
if (this.backgroundColorStyle) {
style.backgroundColor = this.backgroundColorStyle
}
if (this.height) {
style.height = this.height + 'rpx'
}
return style
},
indicatorStyle() {
let style = {}
if (this.indicatorPosition === 'topLeft' || this.indicatorPosition === 'bottomLeft') style.justifyContent = 'flex-start'
if (this.indicatorPosition === 'topCenter' || this.indicatorPosition === 'bottomCenter') style.justifyContent = 'center'
if (this.indicatorPosition === 'topRight' || this.indicatorPosition === 'bottomRight') style.justifyContent = 'flex-end'
if (['topLeft','topCenter','topRight'].indexOf(this.indicatorPosition) >= 0) {
style.top = '12rpx'
style.bottom = 'auto'
} else {
style.top = 'auto'
style.bottom = '12rpx'
}
style.padding = `0 ${this.effect3d ? '74rpx' : '24rpx'}`
return style
},
swiperTitleStyle() {
let style = {}
if (this.mode === 'none' || this.mode === '') style.paddingBottom = '12rpx'
if (['bottomLeft','bottomCenter','bottomRight'].indexOf(this.indicatorPosition) >= 0 && this.mode === 'number') {
style.paddingBottom = '60rpx'
} else if (['bottomLeft','bottomCenter','bottomRight'].indexOf(this.indicatorPosition) >= 0 && this.mode !== 'number') {
style.paddingBottom = '40rpx'
} else {
style.paddingBottom = '12rpx'
}
style = Object.assign(style, this.titleStyle)
return style
}
},
data() {
return {
// 当前显示的item的index
swiperIndex: this.current
}
},
watch: {
list(newVal, oldVal) {
// 如果修改了list的数据重置current的值
if (newVal.length !== oldVal.length) this.swiperIndex = 0
},
current(value) {
// 监听外部current的变化实时修改内部依赖于此测swiperIndex值如果更新了current而不是更新swiperIndex就会错乱因为指示器是依赖于swiperIndex的
this.swiperIndex = value
}
},
methods: {
click(index) {
this.$emit('click', index)
},
// 图片自动切换时触发
change(event) {
const current = event.detail.current
this.swiperIndex = current
this.$emit('change', current)
}
}
}
</script>
<style lang="scss" scoped>
.tn-swiper {
&__wrap {
position: relative;
overflow: hidden;
transform: translateY(0);
}
&__item {
display: flex;
flex-direction: row;
align-items: center;
overflow: hidden;
&__image {
width: 100%;
height: 100%;
will-change: transform;
display: block;
/* #ifdef H5 */
pointer-events: none;
/* #endif */
&__wrap {
width: 100%;
height: 100%;
flex: 1;
transition: all 0.5s;
overflow: hidden;
box-sizing: content-box;
position: relative;
}
&--scale {
transform-origin: center center;
}
}
&__title {
width: 100%;
position: absolute;
background-color: rgba(0, 0, 0, 0.3);
bottom: 0;
left: 0;
font-size: 28rpx;
padding: 12rpx 24rpx;
color: rgba(255, 255, 255, 0.8);
}
}
&__indicator {
padding: 0 24rpx;
position: absolute;
display: flex;
flex-direction: row;
width: 100%;
z-index: 1;
&__rect {
width: 26rpx;
height: 8rpx;
background-color: rgba(0, 0, 0, 0.3);
transition: all 0.5s;
&--active {
background-color: rgba(255, 255, 255, 0.8);
}
}
&__dot {
width: 14rpx;
height: 14rpx;
margin: 0 6rpx;
border-radius: 20rpx;
background-color: rgba(0, 0, 0, 0.3);
transition: all 0.5s;
&--active {
background-color: rgba(255, 255, 255, 0.8);
}
}
&__round {
width: 14rpx;
height: 14rpx;
margin: 0 6rpx;
border-radius: 20rpx;
background-color: rgba(0, 0, 0, 0.3);
transition: all 0.5s;
&--active {
width: 34rpx;
background-color: rgba(255, 255, 255, 0.8);
}
}
&__number {
padding: 6rpx 16rpx;
line-height: 1;
background-color: rgba(0, 0, 0, 0.3);
color: rgba(255, 255, 255, 0.8);
border-radius: 100rpx;
font-size: 26rpx;
}
}
}
</style>