Browse Source

善行少年微信小程序首次提交

htc 1 ngày trước cách đây
commit
69a2782d38

+ 16 - 0
.hbuilderx/launch.json

@@ -0,0 +1,16 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+  // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+    "version": "0.0",
+    "configurations": [{
+     	"default" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"mp-weixin" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"type" : "uniCloud"
+     }
+    ]
+}

+ 76 - 0
App.vue

@@ -0,0 +1,76 @@
+<!-- App.vue -->
+<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">
+	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
+	@import "uview-plus/index.scss";
+	
+	.tab_page{
+		background: #F7F7F7;
+		padding: 0 24rpx 184rpx;
+		box-sizing: border-box;
+	}
+	
+	.top_bg_img{
+		width: 100%;
+		position: fixed;
+		top: 0;
+		left: 0;
+	}
+	
+	.adf{
+	  display: flex;
+	}
+	.adffc{
+	  display: flex;
+	  flex-direction: column;
+	}
+	.adfac{
+	  display: flex;
+	  align-items: center;
+	}
+	.adfacjc{
+	  display: flex;
+	  align-items: center;
+	  justify-content: center;
+	}
+	.adfacjb{
+	  display: flex;
+	  align-items: center;
+	  justify-content: space-between;
+	}
+	.adffcjb{
+	  display: flex;
+	  flex-direction: column;
+	justify-content: space-between;
+	}
+	.adffcacjc{
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	  justify-content: center;
+	}
+	.adffcac{
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	}
+	.adffcacjb{
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	  justify-content: space-between;
+	}
+</style>

+ 7 - 0
common/api/baseApi.js

@@ -0,0 +1,7 @@
+// const BaseApi = 'https://transcend.ringzle.com/chuangheng-app/app' //线上
+const BaseApi = 'https://wxapp.transcend-intl.cn/chuangheng-app/app' //生产
+// const BaseApi = 'http://192.168.2.19:9023/chuangheng-app/app' //李勇
+
+export {
+	BaseApi
+}

+ 87 - 0
common/api/index.js

@@ -0,0 +1,87 @@
+import http from './interface'
+ 
+export const $http = (url, method, data, json, isloading=true) => {
+	//设置请求前拦截器
+	http.interceptor.request = (config) => {
+		if(isloading){
+			uni.showLoading({
+				title:'加载中...'
+			})
+		}
+		
+		config.header = {
+			'content-type': json ? 'application/json' : 'application/x-www-form-urlencoded',
+			"token": uni.getStorageSync('token'),
+			"userId": uni.getStorageSync('userInfo')?JSON.parse(uni.getStorageSync('userInfo')).id:'',
+		}
+	}
+	//设置请求结束后拦截器
+	http.interceptor.response = async (response) => {
+		//判断返回状态 执行相应操作
+		if(isloading){
+			uni.hideLoading()
+		}
+		
+		if (response?.data?.code === 401 || response?.data?.msg.indexOf('未授权') > -1 || response?.data?.msg.indexOf('重新登录') > -1) {
+			return uni.showModal({
+				title: '温馨提示',
+				content:'当前登录已失效,是否返回重新登录',
+				success: (res) => {
+					if (res.confirm) {
+						uni.clearStorageSync();
+					}
+				}
+			})
+		}
+		
+		// 请根据后端规定的状态码判定
+		if (response.data.code === 300) {//token失效
+		//	return response.data = await doRequest(response, url)//动态刷新token,并重新完成request请求
+		}else{
+			if(response.data.code==10021&&response.data.msg){
+				uni.showToast({
+					title:response.data.msg,
+					icon:'none',
+					duration:1500
+				})
+			}
+		}
+
+		return response;
+	}
+	return http.request({
+		method: method,
+		url: url,
+		dataType: 'json',
+		data,
+	})
+}
+
+function postJson(url, data, isloading=true) {
+	return $http(url, 'POST', data, isloading)
+}
+
+function get(url, data, isloading=true) {
+	
+	return $http(url, 'GET', data, true, isloading)
+}
+
+function post(url, data, isloading=true) {
+	return $http(url, 'POST', data, true, isloading)
+}
+
+function put(url, data, isloading=true) {
+	return $http(url, 'PUT', data, true, isloading)
+}
+
+function del(url, data, isloading=true) {
+	return $http(url, 'DELETE', data, true, isloading)
+}
+
+export default {
+	postJson,
+	get,
+	post,
+	put,
+	del
+}

+ 120 - 0
common/api/interface.js

@@ -0,0 +1,120 @@
+import {
+	BaseApi
+} from './baseApi.js'
+export default {
+	config: {
+		baseUrl: BaseApi,
+		header: {
+			'Content-Type':'application/json;charset=UTF-8',
+			'Content-Type':'application/x-www-form-urlencoded'
+		},  
+		data: {},
+		method: "GET",
+		dataType: "json",  /* 如设为json,会对返回的数据做一次 JSON.parse */
+		responseType: "text",
+		success() {},
+		fail() {},
+		complete() {}
+	},
+	interceptor: {
+		request: null,
+		response: null
+	},
+	request(options) {
+		if (!options) {
+			options = {}
+		}
+		options.baseUrl = options.baseUrl || this.config.baseUrl
+		options.dataType = options.dataType || this.config.dataType
+		options.url = options.baseUrl + options.url
+		options.data = options.data || {}
+		options.method = options.method || this.config.method
+		
+		return new Promise((resolve, reject) => {
+			let _config = null
+			
+			options.complete = (response) => {
+				let statusCode = response.statusCode
+				response.config = _config
+				if (process.env.NODE_ENV === 'development') {
+					if (statusCode === 200) {
+						////console.log("【" + _config.requestId + "】 结果:" + JSON.stringify(response.data))
+					}
+				}
+				if (this.interceptor.response) {
+					
+					let newResponse = this.interceptor.response(response)
+					if (newResponse) {
+						response = newResponse
+					}
+				}
+				// 统一的响应日志记录
+				//_reslog(response)
+				if (statusCode === 200) { //成功
+					resolve(response);
+				} else {
+					reject(response)
+				}
+			}
+
+			_config = Object.assign({}, this.config, options)
+			_config.requestId = new Date().getTime()
+
+			if (this.interceptor.request) {
+				this.interceptor.request(_config)
+			}
+			
+			// 统一的请求日志记录
+			//_reqlog(_config)
+
+			if (process.env.NODE_ENV === 'development') {
+				//console.log("【" + _config.requestId + "】 地址:" + _config.url)
+				if (_config.data) {
+					//console.log("【" + _config.requestId + "】 参数:" + JSON.stringify(_config.data))
+				}
+			}
+
+			uni.request(_config);
+		});
+	}	
+}
+
+
+/**
+ * 请求接口日志记录
+ */
+function _reqlog(req) {
+	if (process.env.NODE_ENV === 'development') {
+		//console.log("【" + req.requestId + "】 地址:" + req.url)
+		if (req.data) {
+			//console.log("【" + req.requestId + "】 请求参数:" + JSON.stringify(req.data))
+		}
+	}
+	//TODO 调接口异步写入日志数据库
+}
+
+/**
+ * 响应接口日志记录
+ */
+function _reslog(res) {
+	let _statusCode = res.statusCode;
+	if (process.env.NODE_ENV === 'development') {
+		//console.log("【" + res.config.requestId + "】 地址:" + res.config.url)
+		if (res.config.data) {
+			//console.log("【" + res.config.requestId + "】 请求参数:" + JSON.stringify(res.config.data))
+		}
+		//console.log("【" + res.config.requestId + "】 响应结果:" + JSON.stringify(res))
+	}
+	//TODO 除了接口服务错误外,其他日志调接口异步写入日志数据库
+	switch(_statusCode){
+		case 200:
+			break;
+		case 401:
+			break;
+		case 404:
+			break;
+		default:
+			break;
+	}
+}
+

+ 19 - 0
common/mixins/system.js

@@ -0,0 +1,19 @@
+export default {
+	data() {
+		return {
+			h:uni.getSystemInfoSync().windowHeight,//屏幕高度
+			mt:uni.getSystemInfoSync().statusBarHeight + 44,//自定义头部组件高度(使用自定义头部组件的上边距)
+			th:50+uni.getSystemInfoSync().safeAreaInsets.bottom,//底部tabbar高度
+			imgBase:this.$imgBase
+		}
+	},
+	onShow(){
+		uni.getSystemInfo({
+			success:res=>{
+				if(res.platform === 'android'){
+					this.th = res.screenHeight - res.windowHeight - res.statusBarHeight - 48;
+				}
+			}
+		})
+	}
+}

+ 21 - 0
common/utils/dateFormat.js

@@ -0,0 +1,21 @@
+//  对Date的扩展,将 Date 转化为指定格式的String
+//  月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, 
+//  年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) 
+//  例子: 
+//  (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 
+//  (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18 
+Date.prototype.Format =  function (fmt) {
+     var o = {
+        "M+":  this.getMonth() + 1,  // 月份 
+        "d+":  this.getDate(),  // 日 
+        "h+":  this.getHours(),  // 小时 
+        "m+":  this.getMinutes(),  // 分 
+        "s+":  this.getSeconds(),  // 秒 
+        "q+": Math.floor(( this.getMonth() + 3) / 3),  // 季度 
+        "S":  this.getMilliseconds()  // 毫秒 
+    };
+     if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, ( this.getFullYear() + "").substr(4 - RegExp.$1.length));
+     for ( var k  in o)
+     if ( new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+     return fmt;
+}

+ 23 - 0
common/utils/global.js

@@ -0,0 +1,23 @@
+import regTest from '@/common/utils/reg.js'
+import api from '@/common/api/index.js'
+
+const showToast = (title, duration = 2000, icon = "none") => {
+	uni.showToast({ title, duration, icon })
+}
+
+const showModal = content => {
+	uni.showModal({
+	  title: '温馨提示',
+	  content,
+	  showCancel: false,
+	  confirmText: '确定',
+	  confirmColor: '#007A69'
+	})
+}
+
+export const globalProperties = {
+  $api: api,
+  $regTest: regTest,
+  $showToast: showToast,
+  $showModal: showModal
+};

+ 289 - 0
common/utils/reg.js

@@ -0,0 +1,289 @@
+/**
+ * 验证电子邮箱格式
+ */
+function email(value) {
+    return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
+}
+
+/**
+ * 验证手机格式
+ */
+function mobile(value) {
+    return /^1([3589]\d|4[5-9]|6[1-2,4-7]|7[0-8])\d{8}$/.test(value)
+}
+
+/**
+ * 验证URL格式
+ */
+function url(value) {
+    return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
+        .test(value)
+}
+
+/**
+ * 验证日期格式
+ */
+function date(value) {
+    if (!value) return false
+    // 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳
+    if (number(value)) value = +value
+    return !/Invalid|NaN/.test(new Date(value).toString())
+}
+
+/**
+ * 验证ISO类型的日期格式
+ */
+function dateISO(value) {
+    return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
+}
+
+/**
+ * 验证十进制数字
+ */
+function number(value) {
+    return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
+}
+
+/**
+ * 验证字符串
+ */
+function string(value) {
+    return typeof value === 'string'
+}
+
+/**
+ * 验证整数
+ */
+function digits(value) {
+    return /^\d+$/.test(value)
+}
+
+/**
+ * 验证身份证号码
+ */
+function idCard(value) {
+    return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
+        value
+    )
+}
+
+/**
+ * 是否车牌号
+ */
+function carNo(value) {
+	value = value.trim();
+    // 新能源车牌
+    const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([A-HJ-K][A-HJ-NP-Z0-9][0-9]{4}$))/;
+    // 旧车牌
+    const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
+    if (value.length === 7) {
+        return creg.test(value)
+    } if (value.length === 8) {
+        return xreg.test(value)
+    }
+    return false
+}
+
+/**
+ * 金额,只允许2位小数
+ */
+function amount(value) {
+    // 金额,只允许保留两位小数
+    return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
+}
+
+/**
+ * 中文
+ */
+function chinese(value) {
+    const reg = /^[\u4e00-\u9fa5]+$/gi
+    return reg.test(value)
+}
+
+/**
+ * 只能输入字母
+ */
+function letter(value) {
+    return /^[a-zA-Z]*$/.test(value)
+}
+
+/**
+ * 只能是字母或者数字
+ */
+function enOrNum(value) {
+    // 英文或者数字
+    const reg = /^[0-9a-zA-Z]*$/g
+    return reg.test(value)
+}
+
+/**
+ * 验证是否包含某个值
+ */
+function contains(value, param) {
+    return value.indexOf(param) >= 0
+}
+
+/**
+ * 验证一个值范围[min, max]
+ */
+function range(value, param) {
+    return value >= param[0] && value <= param[1]
+}
+
+/**
+ * 验证一个长度范围[min, max]
+ */
+function rangeLength(value, param) {
+    return value.length >= param[0] && value.length <= param[1]
+}
+
+/**
+ * 是否固定电话
+ */
+function landline(value) {
+    const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
+    return reg.test(value)
+}
+
+/**
+ * 判断是否为空
+ */
+function empty(value) {
+    switch (typeof value) {
+    case 'undefined':
+        return true
+    case 'string':
+        if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
+        break
+    case 'boolean':
+        if (!value) return true
+        break
+    case 'number':
+        if (value === 0 || isNaN(value)) return true
+        break
+    case 'object':
+        if (value === null || value.length === 0) return true
+        for (const i in value) {
+            return false
+        }
+        return true
+    }
+    return false
+}
+
+/**
+ * 是否json字符串
+ */
+function jsonString(value) {
+    if (typeof value === 'string') {
+        try {
+            const obj = JSON.parse(value)
+            if (typeof obj === 'object' && obj) {
+                return true
+            }
+            return false
+        } catch (e) {
+            return false
+        }
+    }
+    return false
+}
+
+/**
+ * 是否数组
+ */
+function array(value) {
+    if (typeof Array.isArray === 'function') {
+        return Array.isArray(value)
+    }
+    return Object.prototype.toString.call(value) === '[object Array]'
+}
+
+/**
+ * 是否对象
+ */
+function object(value) {
+    return Object.prototype.toString.call(value) === '[object Object]'
+}
+
+/**
+ * 是否短信验证码
+ */
+function code(value, len = 6) {
+    return new RegExp(`^\\d{${len}}$`).test(value)
+}
+
+/**
+ * 是否函数方法
+ * @param {Object} value
+ */
+function func(value) {
+    return typeof value === 'function'
+}
+
+/**
+ * 是否promise对象
+ * @param {Object} value
+ */
+function promise(value) {
+    return object(value) && func(value.then) && func(value.catch)
+}
+
+/** 是否图片格式
+ * @param {Object} value
+ */
+function image(value) {
+    const newValue = value.split('?')[0]
+    const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i
+    return IMAGE_REGEXP.test(newValue)
+}
+
+/**
+ * 是否视频格式
+ * @param {Object} value
+ */
+function video(value) {
+    const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
+    return VIDEO_REGEXP.test(value)
+}
+
+/**
+ * 是否为正则对象
+ * @param {Object}
+ * @return {Boolean}
+ */
+function regExp(o) {
+    return o && Object.prototype.toString.call(o) === '[object RegExp]'
+}
+
+export default {
+    email,
+    mobile,
+    url,
+    date,
+    dateISO,
+    number,
+    digits,
+    idCard,
+    carNo,
+    amount,
+    chinese,
+    letter,
+    enOrNum,
+    contains,
+    range,
+    rangeLength,
+    empty,
+    isEmpty: empty,
+    jsonString,
+    landline,
+    object,
+    array,
+    code,
+    func,
+    promise,
+    video,
+    image,
+    regExp,
+    string
+}

+ 92 - 0
components/CusHeader/index.vue

@@ -0,0 +1,92 @@
+<template>
+	<u-navbar :title="title" :bgColor="bgColor" :titleStyle="titleStyle">
+		<view class="u-nav-slot" slot="left" style="display: flex;background-color: transparent;">
+			<u-icon v-if="showback" name="arrow-left" size="44" :color="leftIconColor" @tap="toBack(backUrl)"></u-icon>
+		</view>
+	</u-navbar>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+
+// 定义组件属性
+const props = defineProps({
+	title: {
+		type: String,
+		default: ''
+	},
+	showback: {
+		type: Boolean,
+		default: true
+	},
+	backUrl: {
+		type: String,
+		default: ''
+	},
+	bgColor: {
+		type: String,
+		default: '#ffffff'
+	},
+	leftIconColor: {
+		type: String,
+		default: '#111111'
+	},
+	titleStyle: {
+		type: Object,
+		default: () => ({
+			fontSize: '36rpx',
+			fontWeight: 'bold',
+			color: '#111111'
+		})
+	},
+	backAlert: {
+		type: Boolean,
+		default: false
+	}
+})
+
+// 定义组件状态
+const tabUrls = ref([
+	'/pages/home',
+	'/pages/nonprofit',
+	'/pages/my'
+])
+
+// 导出方法供模板使用
+const toBack = (url: string) => {
+	if (props.backAlert) {
+		
+	} else {
+		dealBack(url)
+	}
+}
+
+const dealBack = (url: string) => {
+	if (!url) {
+		if (uni.getStorageSync('options')) {
+			const options = JSON.parse(decodeURIComponent(uni.getStorageSync('options')))
+			uni.redirectTo(options)
+			uni.removeStorageSync('options')
+			return
+		}
+		const pages = getCurrentPages()
+		if (pages && pages.length > 1) {
+			uni.navigateBack()
+		} else {
+			uni.reLaunch({ url: '/pages/home' })
+		}
+	} else {
+		if (tabUrls.value.find(u => u === url)) {
+			uni.reLaunch({ url })
+		} else {
+			uni.redirectTo({ url })
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+	.u-navbar--fixed {
+		z-index: 99999 !important;
+	}
+</style>

+ 188 - 0
components/CusSkeleton/index.vue

@@ -0,0 +1,188 @@
+<template>
+	<view class="u-skeleton" :class="[`u-skeleton--${type}`, `u-skeleton--${theme}`]" v-if="loading">
+		<template v-if="type === 'paragraph'">
+			<view class="u-skeleton-paragraph">
+				<view 
+					class="u-skeleton-paragraph-line" 
+					v-for="(item, index) in paragraphRows" 
+					:key="index"
+					:style="{ width: `${lineWidth}%` }"
+				></view>
+			</view>
+		</template>
+		
+		<template v-else-if="type === 'card'">
+			<view class="u-skeleton-card">
+				<view class="u-skeleton-card-header"></view>
+				<view class="u-skeleton-card-content">
+					<view class="u-skeleton-card-row"></view>
+					<view class="u-skeleton-card-row" :style="{ width: '70%' }"></view>
+					<view class="u-skeleton-card-row" :style="{ width: '90%' }"></view>
+				</view>
+			</view>
+		</template>
+		
+		<template v-else-if="type === 'list'">
+			<view class="u-skeleton-list-item" v-for="i in 3" :key="i">
+				<view class="u-skeleton-list-avatar"></view>
+				<view class="u-skeleton-list-content">
+					<view class="u-skeleton-list-title"></view>
+					<view class="u-skeleton-list-desc"></view>
+				</view>
+			</view>
+		</template>
+		
+		<template v-else>
+			<slot></slot>
+		</template>
+	</view>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+
+const props = defineProps({
+	loading: {
+		type: Boolean,
+		default: true
+	},
+	type: {
+		type: String,
+		default: 'paragraph',
+		validator: value => ['paragraph', 'card', 'list', 'custom'].includes(value)
+	},
+	rows: {
+		type: Number,
+		default: 3
+	},
+	theme: {
+		type: String,
+		default: 'primary',
+		validator: value => ['primary', 'dark', 'light'].includes(value)
+	},
+	lineWidth: {
+		type: Number,
+		default: 100
+	}
+})
+
+const paragraphRows = computed(() => {
+	return Array.from({ length: props.rows })
+})
+</script>
+
+<style lang="less">
+@keyframes u-skeleton-blink {
+	0% { background-color: #f0f0f0; }
+	50% { background-color: #e0e0e0; }
+	100% { background-color: #f0f0f0; }
+}
+
+.u-skeleton {
+	padding: 16rpx;
+	border-radius: 8rpx;
+	overflow: hidden;
+	
+	&--primary {
+		background-color: #f7f7f7;
+	}
+	
+	&--dark {
+		background-color: #f0f0f0;
+	}
+	
+	&--light {
+		background-color: #ffffff;
+	}
+	
+	&::before {
+		content: "";
+		position: absolute;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		animation: u-skeleton-blink 1.5s infinite ease-in-out;
+		z-index: 1;
+	}
+}
+
+.u-skeleton-paragraph {
+	padding: 20rpx;
+	
+	&-line {
+		height: 24rpx;
+		background-color: #e9e9e9;
+		margin-bottom: 20rpx;
+		border-radius: 4rpx;
+	}
+}
+
+.u-skeleton-card {
+	padding: 24rpx;
+	background-color: #fff;
+	border-radius: 8rpx;
+	margin-bottom: 16rpx;
+	
+	&-header {
+		height: 120rpx;
+		background-color: #e9e9e9;
+		border-radius: 8rpx;
+		margin-bottom: 20rpx;
+	}
+	
+	&-content {
+		padding: 0 10rpx;
+		
+		&-row {
+			height: 24rpx;
+			background-color: #e9e9e9;
+			border-radius: 4rpx;
+			margin-bottom: 16rpx;
+		}
+	}
+}
+
+.u-skeleton-list {
+	background-color: #fff;
+	border-radius: 8rpx;
+	padding: 16rpx;
+	
+	&-item {
+		display: flex;
+		padding: 20rpx 0;
+		border-bottom: 1rpx solid #eee;
+		
+		&:last-child {
+			border-bottom: none;
+		}
+		
+		&-avatar {
+			width: 64rpx;
+			height: 64rpx;
+			background-color: #e9e9e9;
+			border-radius: 50%;
+			margin-right: 16rpx;
+		}
+		
+		&-content {
+			flex: 1;
+			
+			&-title {
+				width: 40%;
+				height: 20rpx;
+				background-color: #e9e9e9;
+				border-radius: 4rpx;
+				margin-bottom: 12rpx;
+			}
+			
+			&-desc {
+				width: 70%;
+				height: 16rpx;
+				background-color: #e9e9e9;
+				border-radius: 4rpx;
+			}
+		}
+	}
+}
+</style>

+ 117 - 0
components/CusSkeleton/readme.md

@@ -0,0 +1,117 @@
+示例1 - 基本段落骨架屏
+<template>
+	<view class="container">
+		<u-skeleton type="paragraph" :rows="3" loading></u-skeleton>
+	</view>
+</template>
+
+示例2 - 卡片式骨架屏
+<template>
+	<view class="container">
+		<u-skeleton type="card" loading></u-skeleton>
+	</view>
+</template>
+
+示例3 - 列表式骨架屏
+<template>
+	<view class="container">
+		<u-skeleton type="list" loading></u-skeleton>
+	</view>
+</template>
+
+示例4 - 自定义主题
+<template>
+	<view class="container">
+		<u-skeleton type="paragraph" :rows="3" theme="dark" loading></u-skeleton>
+	</view>
+</template>
+
+示例5 - 控制加载状态
+<template>
+	<view class="container">
+		<button @click="toggleLoading">切换加载状态</button>
+		<u-skeleton type="paragraph" :rows="3" :loading="isLoading"></u-skeleton>
+	</view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const isLoading = ref(true)
+
+const toggleLoading = () => {
+	isLoading.value = !isLoading.value
+}
+</script>
+
+示例6 - 自定义骨架屏
+<template>
+	<view class="container">
+		<u-skeleton :loading="isLoading" type="custom">
+			<view class="custom-skeleton">
+				<view class="avatar"></view>
+				<view class="content">
+					<view class="title"></view>
+					<view class="desc"></view>
+				</view>
+			</view>
+		</u-skeleton>
+	</view>
+</template>
+
+<style lang="less">
+.custom-skeleton {
+	display: flex;
+	align-items: center;
+	padding: 16rpx;
+	
+	.avatar {
+		width: 64rpx;
+		height: 64rpx;
+		background-color: #e9e9e9;
+		border-radius: 50%;
+		margin-right: 16rpx;
+	}
+	
+	.content {
+		flex: 1;
+		
+		.title {
+			width: 40%;
+			height: 24rpx;
+			background-color: #e9e9e9;
+			border-radius: 4rpx;
+			margin-bottom: 12rpx;
+		}
+		
+		.desc {
+			width: 70%;
+			height: 16rpx;
+			background-color: #e9e9e9;
+			border-radius: 4rpx;
+		}
+	}
+}
+</style>
+
+组件属性说明
+属性名	类型	默认值	说明
+loading	Boolean	true	是否显示骨架屏
+type	String	‘paragraph’	骨架屏类型:‘paragraph’, ‘card’, ‘list’, ‘custom’
+rows	Number	3	段落骨架屏的行数
+theme	String	‘primary’	主题:‘primary’, ‘dark’, ‘light’
+lineWidth	Number	100	段落线宽度百分比
+
+特点说明
+动画效果:内置平滑的闪烁动画,提升用户体验
+多种预设类型:支持段落卡片、列表等常见场景
+自定义主题:提供三种主题色适应不同场景
+插槽自定义:通过插槽实现完全自定义骨架屏
+响应式设计:自适应不同屏幕尺寸
+微信小程序优化:符合小程序规范,性能优异
+
+注意事项
+小程序中 <style> 标签内的 @keyframes 会被提取到全局,确保动画名称唯一
+自定义骨架屏时,建议添加与预设相似的动画样式
+复杂骨架屏性能可能受影响,建议控制骨架屏复杂度
+加载完成后记得将 loading 设为 false

+ 100 - 0
components/CusTabbar/index.vue

@@ -0,0 +1,100 @@
+<template>
+	<view class="bottom_tabbar">
+		<view v-for="(item, index) in list" :key="index" @click="changeTabbar(index)">
+			<image :src="tabbarValue === index ? item.activeImg : item.inactiveImg"></image>
+			<text :class="{ active: tabbarValue === index }">{{ item.text }}</text>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import { ref, onMounted, watch } from 'vue';
+
+	const props = defineProps({
+		tabbarIndex: {
+			type: Number,
+			default: 0
+		}
+	});
+
+	const tabbarValue = ref(0);
+	const list = ref([
+		{
+			inactiveImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/cecc3397-5844-4bce-8965-232ea046b67e.png',
+			activeImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/4e81c0b3-b6c4-4aa2-9ce5-ad6a2a256499.png',
+			text: '首页',
+			path: '/pages/home'
+		},
+		{
+			inactiveImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/57824411-6c16-4b39-a28f-0a640178416c.png',
+			activeImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/7d00fc58-b738-4ab5-bb4a-cd95a080ec2b.png',
+			text: '公益',
+			path: '/pages/nonprofit'
+		},
+		{
+			inactiveImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/44e4a6e4-1d85-4b32-bed8-db2129137dc5.png',
+			activeImg: 'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/56acd490-8ca6-4e30-8d1b-5ece55a3ad3c.png',
+			text: '我的',
+			path: '/pages/my'
+		}
+	]);
+
+	watch(() => props.tabbarIndex,(newVal) => {
+		tabbarValue.value = newVal;
+	});
+
+	onMounted(() => {
+		tabbarValue.value = props.tabbarIndex;
+	});
+
+	const changeTabbar = (e) => {
+		tabbarValue.value = e;
+		uni.reLaunch({
+			url: list.value[e].path
+		});
+	};
+</script>
+
+<style scoped lang="scss">
+	.bottom_tabbar {
+		width: 100%;
+		height: 164rpx;
+		background: #ffffff;
+		display: flex;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 999;
+		padding-top: 19rpx;
+		box-sizing: border-box;
+		box-shadow: 0rpx -2rpx 8rpx 0rpx rgba(0, 0, 0, 0.06);
+
+		& > view {
+			width: calc(100% / 2);
+			height: 100%;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+
+			image {
+				width: 48rpx;
+				height: 48rpx;
+				margin-bottom: 12rpx;
+			}
+
+			text {
+				font-family: PingFangSC, PingFang SC;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #B2B2B2;
+				line-height: 30rpx;
+				text-align: center;
+
+				&.active {
+					font-weight: bold;
+					color: #151B29;
+				}
+			}
+		}
+	}
+</style>

+ 39 - 0
components/pageEmpty/index.vue

@@ -0,0 +1,39 @@
+<template>
+	<view class="page-empty" :style="{ 'height': height, 'margin-top': marginTop }">
+		<u-empty 
+			text="暂无数据" 
+			textSize="26rpx" 
+			width="332rpx" 
+			height="332rpx" 
+			mode="order" 
+			:icon="''"
+		></u-empty>
+	</view>
+</template>
+
+<script setup>
+	// 定义组件属性
+	const props = defineProps({
+		height: {
+			type: String,
+			default: '100vh'
+		},
+		marginTop: {
+			type: String,
+			default: '0px'
+		},
+		imgBase: {
+			type: String,
+			default: ''
+		}
+	})
+</script>
+
+<style scoped lang="scss">
+	.page-empty {
+		width: 100%;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+</style>

+ 115 - 0
components/pages/nonprofitActivety/index.vue

@@ -0,0 +1,115 @@
+<template>
+	<view class="nonprofit-activety">
+		<div class="na-top adf">
+			<div class="na-top-left">
+				<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/d3c53597-a848-4a33-8deb-ab256f028baa.png"></image>
+			</div>
+			<div class="na-top-right">
+				<p>{{'《环保知识知多少》让孩子成为大自然的守护者!'}}</p>
+				<div class="tip adf">
+					<div class="tip-left adfac">
+						<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/201a4250-24a4-412d-9ec9-fc58071d10ea.png"></image>
+						<text>截止报名:</text>
+					</div>
+					<div class="tip-right">{{"还有5天12小时34分钟"}}</div>
+				</div>
+				<div class="tip adf">
+					<div class="tip-left adfac">
+						<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/e9025f86-a59e-4f82-92f0-9d22e846193c.png"></image>
+						<text>活动地点:</text>
+					</div>
+					<div class="tip-right">{{"广东省深圳市南山区"}}</div>
+				</div>
+			</div>
+		</div>
+		<div class="na-bottom adfacjb">
+			<div class="na-bottom-left adf">已报名&nbsp;&nbsp;<strong>{{234}}</strong>/{{300}}&nbsp;&nbsp;人</div>
+			<div class="na-bottom-right">立即报名</div>
+		</div>
+	</view>
+</template>
+
+<script setup name="nonprofitActivety">
+	import { ref } from 'vue'
+</script>
+
+<style scoped lang="scss">
+	.nonprofit-activety{
+		background: linear-gradient( 45deg, #FFFFFF 80%, #F2FFE8 100%);
+		border-radius: 24rpx;
+		padding: 36rpx 24rpx 32rpx;
+		margin-top: 20rpx;
+		
+		.na-top{
+			&-left{
+				width: 158rpx;
+				height: 214rpx;
+				image{
+					width: 100%;
+					height: 100%;
+				}
+			}
+			&-right{
+				width: calc(100% - 158rpx);
+				padding-left: 20rpx;
+				box-sizing: border-box;
+				&>p{
+					font-family: PingFang-SC, PingFang-SC;
+					font-weight: bold;
+					font-size: 32rpx;
+					color: #151B29;
+					line-height: 40rpx;
+					margin-bottom: 5rpx;
+				}
+				.tip{
+					margin-top: 25rpx;
+					&-left{
+						width: 160rpx;
+						image{
+							width: 24rpx;
+							height: 24rpx;
+						}
+						text{
+							font-family: PingFangSC, PingFang SC;
+							font-weight: 400;
+							font-size: 24rpx;
+							color: #676775;
+							line-height: 24rpx;
+							margin-left: 10rpx;
+						}
+					}
+					&-right{
+						width: calc(100% - 160rpx);
+						font-family: PingFangSC, PingFang SC;
+						font-weight: 400;
+						font-size: 24rpx;
+						color: #676775;
+						line-height: 24rpx;
+						margin-left: 10rpx;
+					}
+				}
+			}
+		}
+		
+		.na-bottom{
+			margin-top: 24rpx;
+			&-left{
+				font-family: PingFangSC, PingFang SC;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #676775;
+				line-height: 24rpx;
+			}
+			&-right{
+				background: #B7F358;
+				border-radius: 27rpx;
+				padding: 12rpx 30rpx;
+				font-family: PingFang-SC, PingFang-SC;
+				font-weight: bold;
+				font-size: 24rpx;
+				color: #151B29;
+				line-height: 30rpx;
+			}
+		}
+	}
+</style>

+ 20 - 0
index.html

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

+ 56 - 0
main.js

@@ -0,0 +1,56 @@
+import App from './App'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import './uni.promisify.adaptor'
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+	...App
+})
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import {
+	createSSRApp
+} from 'vue'
+
+import uviewPlus from 'uview-plus'
+import Skeleton from '@/components/CusSkeleton/index.vue'
+import system from '@/common/mixins/system.js'
+import { globalProperties } from '@/common/utils/global.js'
+
+
+export function createApp() {
+	const app = createSSRApp(App)
+
+	app.use(uviewPlus)
+	app.mixin(system)
+	app.component('u-skeleton', Skeleton)
+
+	for (const key in globalProperties) {
+		app.config.globalProperties[key] = globalProperties[key]
+	}
+	
+	Date.prototype.Format =  function (fmt) {
+	     var o = {
+	        "M+":  this.getMonth() + 1,  // 月份 
+	        "d+":  this.getDate(),  // 日 
+	        "h+":  this.getHours(),  // 小时 
+	        "m+":  this.getMinutes(),  // 分 
+	        "s+":  this.getSeconds(),  // 秒 
+	        "q+": Math.floor(( this.getMonth() + 3) / 3),  // 季度 
+	        "S":  this.getMilliseconds()  // 毫秒 
+	    };
+	     if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, ( this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	     for ( var k  in o)
+	     if ( new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+	     return fmt;
+	}
+
+	return {
+		app
+	}
+}
+// #endif

+ 73 - 0
manifest.json

@@ -0,0 +1,73 @@
+{
+    "name" : "SHSN_WX",
+    "appid" : "__UNI__B966EE4",
+    "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,
+		"mergeVirtualHostAttributes" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "3"
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2582 - 0
package-lock.json


+ 9 - 0
package.json

@@ -0,0 +1,9 @@
+{
+  "devDependencies": {
+    "sass": "^1.63.2",
+    "sass-loader": "^10.4.1"
+  },
+  "dependencies": {
+    "uview-plus": "^3.5.41"
+  }
+}

+ 35 - 0
pages.json

@@ -0,0 +1,35 @@
+{
+	"pages": [ 
+		{
+			"path": "pages/home",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/nonprofit",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/my",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}
+	],
+	"globalStyle": {
+		"navigationBarTitleText": "善行少年",
+		"navigationBarBackgroundColor": "#FFFFFF",
+		"navigationBarTextStyle": "black"
+	},
+	"easycom": {
+		"autoscan": true,
+		"custom": {
+			"^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"
+		}
+	}
+}

+ 180 - 0
pages/home.vue

@@ -0,0 +1,180 @@
+<template>
+	<view class="tab_page" :style="{'height':h+'px', 'padding-top':mt+'px'}">
+		<up-navbar title=" " bgColor="transparent">
+            <template #left>
+				<view class="u-nav-slot" slot="left" style="display: flex;background-color: transparent;">
+					<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/a5ad7f10-d625-4c9a-89f3-59f98c56dee8.png" style="width: 370rpx;height: 40rpx;"></image>
+				</view>
+			</template>
+		</up-navbar>
+		<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/a7f990ec-1bff-4bd6-8b7f-fa61c0170d3b.png" class="top_bg_img" mode="widthFix"></image>
+		<div class="c-box adffc">
+			<div class="c-box-lunbo">
+				<up-swiper
+					:list="bannarList"
+					@change="e => current = e.current"
+					:autoplay="false"
+					height="326rpx"
+				>
+					<template #indicator>
+						<view class="indicator adf">
+							<view class="indicator__dot" v-for="(item, index) in bannarList" :key="index"
+								:class="[index === current && 'indicator__dot--active']">
+							</view>
+						</view>
+					</template>
+				</up-swiper>
+			</div>
+			<div class="c-box-title adfacjb">
+				<div class="c-box-title-left">公益活动</div>
+				<div class="c-box-title-right adfac">更多 <up-icon name="arrow-right" size="30rpx" style="margin-left: 10rpx;"></up-icon></div>
+			</div>
+			<div class="c-box-type">
+				<scroll-view class="scroll-view_H" scroll-x="true" scroll-with-animation="true" :scroll-left="scrollLeft">
+					<view class="scroll-view-item_H" :id="'svih_'+index" v-for="(item,index) in typeList" :key="index" @tap="changeType(item,index)">
+						<view class="cl_item" :class="{'active':tlIndex===index}">
+							<text>{{item.name}}</text>
+						</view>
+					</view>
+				</scroll-view>
+			</div>
+			<div class="c-box-list">
+				<NonprofitActivety></NonprofitActivety>
+				<NonprofitActivety></NonprofitActivety>
+			</div>
+		</div>
+		<CusTabbar :tabbarIndex="0"></CusTabbar>
+	</view>
+</template>
+
+<script setup name="">
+	import CusTabbar from '@/components/CusTabbar/index.vue'
+	import NonprofitActivety from '@/components/pages/nonprofitActivety/index.vue'
+	import { ref, getCurrentInstance, onMounted } from 'vue'
+	const { proxy } = getCurrentInstance()
+	
+	const bannarList = ref([
+		'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/337c22f0-2583-4556-84b6-eb21fdde6e82.png',
+		'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/337c22f0-2583-4556-84b6-eb21fdde6e82.png',
+		'https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/337c22f0-2583-4556-84b6-eb21fdde6e82.png'
+	])
+	const current = ref(0)
+	const typeList = ref([
+		{id:'',name:'全部'},
+		{id:1,name:'儿童关爱'},
+		{id:2,name:'老人关爱'},
+		{id:3,name:'社区发展'},
+		{id:4,name:'社会服务'},
+		{id:5,name:'健康行动'},
+		{id:6,name:'减肥运动'}
+	])
+	const tlIndex = ref(0)
+	const scrollLeft = ref(0)
+	
+	const changeType = (item,index) => {
+		tlIndex.value = index;
+		if(typeList.value.length>4){
+			if(index<3) scrollLeft.value = 0
+			else{
+				scrollLeft.value = (index-2)*172/2;
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	::v-deep .indicator__dot{
+		width: 48rpx;
+		height: 4rpx;
+		background: #E2E5E9;
+		border-radius: 2rpx;
+		margin: 0 8rpx;
+	}
+	::v-deep .indicator__dot--active{
+		width: 48rpx;
+		height: 4rpx;
+		background: #00AE57;
+		border-radius: 2rpx;
+	}
+	
+	.scroll-view_H {
+		white-space: nowrap;
+		width: 100%;
+	}
+	
+	.scroll-view-item_H {
+		display: inline-block;
+		width: 152rpx;
+		height: 100%;
+		margin-left: 20rpx;
+		&:first-child{
+			margin-left: 0;
+		}
+	}
+	
+	.tab_page{
+		.c-box{
+			width: 100%;
+			height: 100%;
+			overflow-y: auto;
+			position: relative;
+			&-lunbo{
+				width: 100%;
+				height: 326rpx;
+				margin-top: 20rpx;
+			}
+			&-title{
+				margin-top: 58rpx;
+				&-left{
+					width: 170rpx;
+					height: 44rpx;
+					padding-left: 2rpx;
+					font-family: PingFang-SC, PingFang-SC;
+					font-weight: 800;
+					font-size: 36rpx;
+					color: #151B29;
+					line-height: 36rpx;
+					background-image: url('https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/6ec1f999-fcbb-4a0b-a1a5-d0b5e1374bb1.png');
+					background-size: 170rpx 31rpx;
+					background-position: 0 20rpx;
+					background-repeat: no-repeat;
+				}
+				&-right{
+					font-family: PingFangSC, PingFang SC;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #676775;
+					line-height: 33rpx;
+				}
+			}
+			&-type{
+				width: 100%;
+				height: 68rpx;
+				margin-top: 31rpx;
+				.cl_item{
+					width: 152rpx;
+					height: 68rpx;
+					background: #FFFFFF;
+					border-radius: 34rpx;
+					font-family: PingFangSC, PingFang SC;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #676775;
+					line-height: 68rpx;
+					text-align: center;
+					&.active{
+						background: #B7F358;
+						font-weight: bold;
+						font-size: 30rpx;
+						color: #151B29;
+					}
+				}
+			}
+			&-list{
+				width: 100%;
+				flex: 1;
+				overflow-y: auto;
+			}
+		}
+	}
+</style>

+ 151 - 0
pages/my.vue

@@ -0,0 +1,151 @@
+<template>
+	<view class="tabPage" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
+		<cus-header title='我的' bgColor="transparent" :showback="false"></cus-header>
+		<div class="info">
+			<div class="i_top adfac">
+				<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/06/16/0bdaa978-db1a-4edb-8a41-fc45b096380f.png"></image>
+				<div class="it_texts">
+					<p>{{userName||''}}</p>
+					<p>{{mobile||''}}</p>
+				</div>
+			</div>
+			<div class="i_tips">
+				<p>所属公司:{{enterpriseName||''}}</p>
+				<p>所属团队:{{teamName||''}}</p>
+			</div>
+		</div>
+		<div class="box">
+			<div class="b_pre adfacjb">
+				<div class="bp_l adfac">
+					<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/06/16/ecb80887-6d86-420c-b797-7f12c5916871.png"></image>
+					<text>版本</text>
+				</div>
+				<div class="bp_r">1.0.0</div>
+			</div>
+			<div class="b_pre adfacjb" @tap="exitLogin">
+				<div class="bp_l adfac">
+					<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/06/16/4d10c9ef-8a13-4502-adfd-d388628446ab.png"></image>
+					<text>退出登录</text>
+				</div>
+				<div class="bp_r">
+					<u-icon name="arrow-right" color="#D3D2D2" size="32"></u-icon>
+				</div>
+			</div>
+		</div>
+		<Tabbar :tabbarIndex="1"></Tabbar>
+	</view>
+</template>
+
+<script>
+	import Tabbar from '@/components/CusTabbar/index.vue'
+	export default {
+		components:{ Tabbar },
+		data(){
+			return {
+				userName:'',
+				mobile:'',
+				enterpriseName:'',
+				teamName:''
+			}
+		},
+		onLoad() {
+			if(uni.getStorageSync('userInfo')){
+				this.userName = JSON.parse(uni.getStorageSync('userInfo')).realName||'';
+				this.mobile = JSON.parse(uni.getStorageSync('userInfo')).mobile||'';
+				this.enterpriseName = JSON.parse(uni.getStorageSync('userInfo')).enterpriseName||'';
+				this.teamName = JSON.parse(uni.getStorageSync('userInfo')).teamName||'';
+				if(this.mobile) this.mobile = this.mobile.replace(this.mobile.substr(3,4),' **** ')
+			}
+		},
+		methods:{
+			exitLogin(){
+				uni.clearStorageSync();
+				uni.reLaunch({
+					url:'/pages/login'
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="less">
+	.tabPage{
+		background: linear-gradient( 270deg, #EEEFF8 0%, #F6ECF4 100%, #F6ECF4 100%);
+		padding: 0 0 172rpx;
+		box-sizing: border-box;
+		display: flex;
+		flex-direction: column;
+		.info{
+			padding: 54rpx 40rpx;
+			.i_top{
+				image{
+					width: 188rpx;
+					height: 188rpx;
+				}
+				.it_texts{
+					padding-left: 30rpx;
+					p{
+						font-family: PingFang-SC, PingFang-SC;
+						font-weight: bold;
+						font-size: 40rpx;
+						color: #252525;
+						line-height: 40rpx;
+						&:last-child{
+							font-family: PingFang-SC, PingFang-SC;
+							font-weight: bold;
+							font-size: 32rpx;
+							color: #646464;
+							line-height: 32rpx;
+							margin-top: 36rpx;
+						}
+					}
+				}
+			}
+			.i_tips{
+				margin-top: 48rpx;
+				overflow: hidden;
+				p{
+					margin-top: 40rpx;
+					font-family: PingFangSC, PingFang SC;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #6B7280;
+					line-height: 28rpx;
+				}
+			}
+		}
+		.box{
+			padding: 30rpx;
+			background: #FFFFFF;
+			flex: 1;
+			.b_pre{
+				background: #FFFFFF;
+				box-shadow: inset 0rpx -1rpx 0rpx 0rpx #ECECEC;
+				border-radius: 16rpx 16rpx 0rpx 0rpx;
+				padding: 39rpx 0;
+				.bp_l{
+					image{
+						width: 36rpx;
+						height: 36rpx;
+					}
+					text{
+						font-family: PingFangSC, PingFang SC;
+						font-weight: 400;
+						font-size: 30rpx;
+						color: #111111;
+						line-height: 32rpx;
+						margin-left: 30rpx;
+					}
+				}
+				.bp_r{
+					font-family: PingFang-SC, PingFang-SC;
+					font-weight: bold;
+					font-size: 30rpx;
+					color: #111111;
+					line-height: 32rpx;
+					text-align: right;
+				}
+			}
+		}
+	}
+</style>

+ 22 - 0
pages/nonprofit.vue

@@ -0,0 +1,22 @@
+<template>
+	<view class="tabPage" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data(){
+			return {
+				
+			}
+		},
+		methods:{
+			
+		}
+	}
+</script>
+
+<style scoped lang="less">
+	
+</style>

+ 10 - 0
uni.promisify.adaptor.js

@@ -0,0 +1,10 @@
+uni.addInterceptor({
+  returnValue (res) {
+    if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
+      return res;
+    }
+    return new Promise((resolve, reject) => {
+      res.then((res) => res[0] ? reject(res[0]) : resolve(res[1]));
+    });
+  },
+});

+ 77 - 0
uni.scss

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