Browse Source

Merge branch 'master' of http://150.158.33.144:3000/lalalashen/MoeNovaClient

lalalashen 3 months ago
parent
commit
fb95c66aac
31 changed files with 4765 additions and 61 deletions
  1. 43 0
      common/baseUrl.js
  2. 152 0
      common/requestConfig.js
  3. 102 0
      common/socket.js
  4. 4 4
      components/card/card.vue
  5. 49 0
      components/lh-select-city/README.md
  6. 1062 0
      components/lh-select-city/cityData.js
  7. 296 0
      components/lh-select-city/index.vue
  8. 13 0
      components/lh-select-city/package.json
  9. 4 0
      main.js
  10. 10 0
      node_modules/zhouWei-request/changelog.md
  11. 132 0
      node_modules/zhouWei-request/js_sdk/request/core/request.js
  12. 101 0
      node_modules/zhouWei-request/js_sdk/request/core/utils.js
  13. 7 0
      node_modules/zhouWei-request/js_sdk/request/index.js
  14. 451 0
      node_modules/zhouWei-request/js_sdk/request/request.md
  15. 132 0
      node_modules/zhouWei-request/js_sdk/request/upload/Base64.js
  16. 40 0
      node_modules/zhouWei-request/js_sdk/request/upload/aliUploader.js
  17. 185 0
      node_modules/zhouWei-request/js_sdk/request/upload/crypto.js
  18. 41 0
      node_modules/zhouWei-request/js_sdk/request/upload/hmac.js
  19. 169 0
      node_modules/zhouWei-request/js_sdk/request/upload/qiniuUploader.js
  20. 86 0
      node_modules/zhouWei-request/js_sdk/request/upload/sha1.js
  21. 287 0
      node_modules/zhouWei-request/js_sdk/request/upload/upload.js
  22. 396 0
      node_modules/zhouWei-request/js_sdk/request/upload/utils.js
  23. 214 0
      node_modules/zhouWei-request/js_sdk/requestConfig.js
  24. 80 0
      node_modules/zhouWei-request/package.json
  25. 508 0
      node_modules/zhouWei-request/readme.md
  26. 30 11
      pages/index/index.scss
  27. 158 44
      pages/index/index.vue
  28. 2 2
      pages/login/login.vue
  29. BIN
      static/fonts/阿里妈妈数黑体.otf
  30. BIN
      static/home/release-btn.png
  31. 11 0
      style/FontStyle.css

+ 43 - 0
common/baseUrl.js

@@ -0,0 +1,43 @@
+let baseUrl = "";
+let socketUrl =""
+if (process.env.NODE_ENV === 'development') {
+	baseUrl = "https://e.zhichao.art/Gapi";
+} else if (process.env.NODE_ENV === 'production') {
+	// 生产环境
+	baseUrl = "https://e.zhichao.art/Gapi";
+}
+const courtConfig = {
+	//微信公众号APPID
+	publicAppId: "xxxxxxxxxxxxx",
+	//请求接口
+	baseUrl: baseUrl,
+	socketUrl:socketUrl,
+	//平台名称
+	platformName: "萌创星球",
+	//项目logo
+	logoUrl: "/static/logo.png",
+	//页面分享配置
+	share: {
+		title: '萌创星球',
+		// #ifdef MP-WEIXIN
+		path: '/pages/home/home', //小程序分享路径
+		// #endif
+		// #ifdef H5 || APP-PLUS
+		//公众号||APP分享
+		desc: "萌创星球", // 分享描述
+		link: "xxxxxxxxxxx", // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+		imgUrl: "xxxxxxxxxxxxxxxxx", // 分享图标
+		// #endif
+	}
+};
+//手机号验证正则表达式
+const phoneRegular = /^1\d{10}$/;
+//邮箱验证正则表达式
+const mailRegular = /^\w+@\w+(\.[a-zA-Z]{2,3}){1,2}$/;
+//密码验证正则表达式
+const passwordRegular = /^[a-zA-Z0-9]{4,10}$/;
+export default Object.assign({
+	phoneRegular,
+	mailRegular,
+	passwordRegular
+}, courtConfig);

+ 152 - 0
common/requestConfig.js

@@ -0,0 +1,152 @@
+import request from "@/node_modules/zhouWei-request/js_sdk/request"; 
+import base from '@/common/baseUrl';
+ 
+let version_code = '';
+// #ifdef APP-PLUS
+import {
+	getCurrentNo
+} from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';
+import {
+	isString
+} from "util";
+import { log } from "console";
+setTimeout(() => {
+	getCurrentNo(function(res) {
+		console.log("版本号", res);
+		version_code = res.versionCode;
+	});
+}, 200);
+// #endif
+
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//接口请求地址
+	baseUrl: base.baseUrl,
+	//服务器本地上传文件地址
+	fileUrl: base.baseUrl,
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+	// 服务器上传文件名称
+	defaultFileName: "file",
+	//设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致)
+	header: {
+		'content-type': 'application/json;',
+		// 'project_token': base.projectToken, //项目token(可删除)
+	}
+});
+ 
+//请求开始拦截器
+$http.requestStart = function(options) {
+	if (options.load) { 
+	}
+	// 图片、视频上传大小限制
+	if (options.method == "FILE") {
+		// 文件最大字节: options.maxSize 可以在调用方法的时候加入参数
+		let maxSize = options.maxSize || '';
+		for (let item of options.files) {
+			if (item.fileType == 'image') {
+				if (maxSize && item.size > maxSize) {
+					setTimeout(() => {
+						uni.showToast({
+							title: "图片过大,请重新上传",
+							icon: "none"
+						});
+					}, 500);
+					return false;
+				}
+			} else if (item.fileType == "video") {
+				if (item.duration < 3) {
+					setTimeout(() => {
+						uni.showToast({
+							title: "视频长度不足3秒,请重新上传",
+							icon: "none"
+						});
+					}, 500);
+					return false;
+				}
+			}
+		}
+	}
+	// #ifdef APP-PLUS
+	// 添加当前版本号
+	if (version_code) {
+		options.header['version_code'] = version_code;
+	}
+	// #endif
+	//请求前加入token 
+		options.header.sign = getApp().globalData.headerSign
+		// options.header["content-type"] = "application/json" 
+	return options;
+}
+//请求结束
+$http.requestEnd = function(options) {
+ 
+}
+let loginPopupNum = 0;
+let num = 0
+$http.dataFactory = function(res) {
+	console.log("接口请求数据", {
+		url: res.url,
+		resolve: res.response,
+		header: res.header,
+		data: res.data,
+		method: res.method,
+	});
+	if (res.response.statusCode && res.response.statusCode == 200) {
+		let httpData = res.response.data ;
+		if (typeof(httpData) == "string") {
+			httpData = JSON.parse(httpData);
+		}  
+	
+		//判断数据是否请求成功
+		if (httpData.success == "yes" || httpData.statusCode == "200") {
+			// 返回正确的结果(then接受数据)   
+			// 返回Promise对象,支持链式调用和await操作
+			return Promise.resolve( res.response);
+		} else if (isString(httpData.resultCode)) {
+		  
+		} else { //其他错误提示   
+			if (res.isPrompt) {
+				uni.showToast({
+					title: httpData.info || httpData.msg,
+					icon: "none",
+					duration: 3000
+				});
+			}
+			// 返回错误的结果(catch接受数据)
+			return Promise.reject({
+				statusCode: 0,
+				errMsg: "【request】" + (httpData.info || httpData.msg),
+				data: res.data
+			});
+		}
+
+		 
+
+	} else {
+		// 返回错误的结果(catch接受数据)
+		return Promise.reject({
+			statusCode: res.response.statusCode,
+			errMsg: "【request】数据工厂验证不通过",
+			data: res.data
+		});
+	}
+};
+var content = 0
+// 错误回调
+$http.requestError = function(e) {
+	// e.statusCode === 0 是参数效验错误抛出的
+	if (e.statusCode === 0) {
+		throw e;
+	} else {
+		if (content != 0) {
+			uni.showToast({
+				title: "网络错误,请检查一下网络",
+				icon: "none"
+			});
+		} else {
+			content = 1
+		}
+	}
+}
+export default $http;

+ 102 - 0
common/socket.js

@@ -0,0 +1,102 @@
+import base from '@/config/baseUrl'; 
+class socket {
+	constructor(options) {
+		//地址
+		this.socketUrl = base.socketUrl;
+		this.socketStart = false;
+		this.monitorSocketError();
+		this.monitorSocketClose();
+		this.socketReceive();
+	}
+	init(callback) {
+		const _this = this;
+		if (base.socketUrl) {
+			if(this.socketStart){
+				console.log('webSocket已经启动了');
+			}else{
+				uni.connectSocket({
+					url: this.socketUrl,
+					method: 'GET'
+				});
+				uni.onSocketOpen((res) => {
+					this.socketStart = true;
+					callback && callback();
+					console.log('WebSocket连接已打开!');
+				});
+				setTimeout(() => {
+					_this.getHeartbeat();
+				}, 5000);
+			}
+		}else{
+			console.log('config/baseUrl socketUrl为空');
+		}
+	}
+	//Socket给服务器发送消息
+	send(data, callback) {
+		const _this = this;
+		// if (store.state.userInfo.uid) {
+		// 	data.userUid = store.state.userInfo.uid;
+		// }
+		console.log(data);
+		uni.sendSocketMessage({
+			data: JSON.stringify(data),
+			success: () => {
+				callback && callback(true);
+			},
+			fail: () => {
+				callback && callback(false);
+			}
+		});
+	}
+	//Socket接收服务器发送过来的消息
+	socketReceive() {
+		const _this = this;
+		uni.onSocketMessage(function(res) {
+			let data = JSON.parse(res.data);
+			console.log('收到服务器内容:', data);
+			_this.acceptMessage && _this.acceptMessage(data);
+		});
+	}
+	//关闭Socket
+	closeSocket() {
+		uni.closeSocket();
+		_this.socketStart = false;
+	}
+	//监听Socket关闭
+	monitorSocketClose() {
+		const _this = this;
+		uni.onSocketClose(function(res) {
+			console.log('WebSocket 已关闭!');
+			_this.socketStart = false;
+			setTimeout(function() {
+				_this.init();
+			}, 3000);
+		});
+	}
+	//监听Socket错误
+	monitorSocketError() {
+		const _this = this;
+		uni.onSocketError(function(res) {
+			_this.socketStart = false;
+			console.log('WebSocket连接打开失败,请检查!');
+		});
+	}
+	//心跳
+	getHeartbeat() {
+		const _this = this;
+		this.send({
+			type: "心跳",
+			userUid: store.state.userInfo.userUid
+		}, (val) => {
+			setTimeout(() => {
+				if (val) {
+					_this.getHeartbeat();
+				} else {
+					_this.init();
+				}
+			}, 10000);
+		});
+	}
+};
+const mySocket = new socket();
+export default mySocket;

+ 4 - 4
components/card/card.vue

@@ -9,9 +9,9 @@
 			</view>
 			<view class="waterfall-item__ft__desc">
 				<view class="user">
-					<image src="@/static/icon/caidou.png" mode="aspectFill" class="avater">
+					<image :src="item.avator" mode="aspectFill" class="avater">
 					</image>
-					<text class="name" :style="{color:textColor}">{{item.author}}</text>
+					<text class="name" :style="{color:textColor}">{{item.nickname}}</text>
 				</view>
 				<view class="like" @click="changeLike">
 					<image class="like-icon" :src="isLike ?'/static/icon/icon-18.png':'/static/icon/icon-19.png'" mode="">
@@ -123,7 +123,7 @@
 
 				.look-icon {
 					width: 26rpx;
-					height: 18rpx;
+					height: 26rpx;
 					margin-right: 10rpx;
 				}
 
@@ -189,7 +189,7 @@
 
 					.like-icon {
 						width: 30rpx;
-						height: 25rpx;
+						height: 30rpx;
 						margin-right: 10rpx;
 					}
 

+ 49 - 0
components/lh-select-city/README.md

@@ -0,0 +1,49 @@
+## 参数说明
+# hotCitys  热门城市(array)
+# value 当前选中城市(string)
+# windowHeight  scroll的高 也是滑块的高 记得带单位!!! px rpx upx都支持(string)
+# @onSelect   点击切换城市事件 参数为城市名称
+# sliding 是否开始滑动选择 不传默认开启(Boolean)
+
+## 使用说明
+
+```javascript
+<lhSelectCity
+  :value="value"
+  :windowHeight="windowHeight"
+  :hotCitys="hotCitys"
+  @onSelect="onSelectCity"
+/>
+
+
+import lhSelectCity from '@/components/lh-select-city/index.nvue'
+	export default {
+		components:{lhSelectCity},
+		data() {
+			return {
+				hotCitys: [
+					'杭州',
+					'天津',
+					'北京',
+					'上海',
+					'深圳',
+					'广州',
+					'成都',
+					'重庆',
+					'厦门'
+				],
+				value: '杭州',
+				windowHeight:""
+			}
+		},
+		onLoad(){
+			// 计算出可用高度
+			 this.windowHeight = uni.getSystemInfoSync().windowHeight-100+"px";
+		},
+		methods: {
+			onSelectCity(city) {
+				console.log(city)
+			}
+		}
+	}
+```

+ 1062 - 0
components/lh-select-city/cityData.js

@@ -0,0 +1,1062 @@
+const cityData = [
+  {
+    letter: 'A',
+    list: [
+      '安远',
+      '安义',
+      '安溪',
+      '安丘',
+      '安宁',
+      '安吉',
+      '安福',
+      '阿城',
+      '安阳',
+      '安顺',
+      '鞍山',
+      '安庆',
+      '安康',
+      '阿里',
+      '阿勒泰',
+      '阿拉善盟',
+      '阿克苏',
+      '阿坝'
+    ]
+  },
+  {
+    letter: 'B',
+    list: [
+      '北京',
+      '博兴',
+      '博罗',
+      '博爱',
+      '璧山',
+      '宾阳',
+      '宾县',
+      '滨海',
+      '巴彦',
+      '宝应',
+      '亳州',
+      '博尔塔拉',
+      '滨州',
+      '毕节',
+      '本溪',
+      '北海',
+      '巴中',
+      '巴音郭楞',
+      '巴彦淖尔',
+      '包头',
+      '保山',
+      '宝鸡',
+      '保定',
+      '蚌埠',
+      '白银',
+      '白山',
+      '百色',
+      '白城'
+    ]
+  },
+  {
+    letter: 'C',
+    list: [
+      '成都',
+      '常州',
+      '长沙',
+      '长春',
+      '重庆',
+      '朝阳',
+      '巢湖',
+      '长治',
+      '昌吉',
+      '昌都',
+      '常德',
+      '沧州',
+      '郴州',
+      '承德',
+      '潮州',
+      '滁州',
+      '楚雄',
+      '崇左',
+      '池州',
+      '赤峰',
+      '枞阳',
+      '从化',
+      '慈溪',
+      '淳安',
+      '崇州',
+      '崇义',
+      '崇仁',
+      '茌平',
+      '成武',
+      '城口',
+      '呈贡',
+      '潮安',
+      '昌邑',
+      '长兴',
+      '长汀',
+      '长泰',
+      '常熟',
+      '常山',
+      '昌乐',
+      '长乐',
+      '长海',
+      '长丰',
+      '长岛',
+      '曹县',
+      '苍山',
+      '苍南'
+    ]
+  },
+  {
+    letter: 'D',
+    list: [
+      '丹东',
+      '大理',
+      '东莞',
+      '大连',
+      '大兴安岭',
+      '大同',
+      '大庆',
+      '德州',
+      '德阳',
+      '德宏',
+      '达州',
+      '大丰',
+      '东营',
+      '迪庆',
+      '定西',
+      '单县',
+      '当涂',
+      '砀山',
+      '岱山',
+      '大邑',
+      '大田',
+      '大埔',
+      '丹阳',
+      '德化',
+      '德安',
+      '大足',
+      '大余',
+      '德庆',
+      '德清',
+      '登封',
+      '德惠',
+      '定南',
+      '垫江',
+      '电白',
+      '德兴',
+      '东海',
+      '东阿',
+      '定远',
+      '定陶',
+      '东台',
+      '东山',
+      '东平',
+      '东明',
+      '东源',
+      '东阳',
+      '东乡',
+      '洞头',
+      '都江堰',
+      '都昌',
+      '东至'
+    ]
+  },
+  {
+    letter: 'E',
+    list: ['鄂尔多斯', '恩施', '恩平', '鄂州']
+  },
+  {
+    letter: 'F',
+    list: [
+      '佛山',
+      '福州',
+      '防城港',
+      '抚顺',
+      '阜新',
+      '阜阳',
+      '抚州',
+      '法库',
+      '富阳',
+      '福清',
+      '阜宁',
+      '阜南',
+      '富民',
+      '浮梁',
+      '福鼎',
+      '福安',
+      '佛冈',
+      '分宜',
+      '凤阳',
+      '奉新',
+      '丰县',
+      '凤台',
+      '丰顺',
+      '封开',
+      '奉节',
+      '奉化',
+      '丰都',
+      '丰城',
+      '费县',
+      '肥西',
+      '肥东',
+      '肥城',
+      '方正',
+      '繁昌'
+    ]
+  },
+  {
+    letter: 'G',
+    list: [
+      '广州',
+      '贵阳',
+      '甘南',
+      '赣州',
+      '甘孜',
+      '广安',
+      '广元',
+      '贵港',
+      '桂林',
+      '果洛',
+      '固原',
+      '赣县',
+      '赣榆',
+      '高安',
+      '固镇',
+      '古田',
+      '贵溪',
+      '灌云',
+      '冠县',
+      '灌南',
+      '光泽',
+      '广饶',
+      '广宁',
+      '广丰',
+      '广德',
+      '广昌',
+      '巩义',
+      '高州',
+      '高邮',
+      '高邑',
+      '高要',
+      '高唐',
+      '高青',
+      '高密',
+      '高陵',
+      '皋兰',
+      '高淳',
+      '藁城'
+    ]
+  },
+  {
+    letter: 'H',
+    list: [
+      '杭州',
+      '哈尔滨',
+      '邯郸',
+      '海口',
+      '黑河',
+      '合肥',
+      '鹤岗',
+      '河池',
+      '鹤壁',
+      '汉中',
+      '哈密',
+      '海西',
+      '海南',
+      '海东',
+      '海北',
+      '惠州',
+      '呼伦贝尔',
+      '葫芦岛',
+      '呼和浩特',
+      '黄石',
+      '黄山',
+      '黄南',
+      '黄冈',
+      '淮南',
+      '怀化',
+      '淮北',
+      '淮安',
+      '红河',
+      '贺州',
+      '菏泽',
+      '河源',
+      '和田地',
+      '衡阳',
+      '衡水',
+      '怀远',
+      '怀宁',
+      '怀集',
+      '桦甸',
+      '华安',
+      '洪泽',
+      '和县',
+      '鹤山',
+      '和平',
+      '横县',
+      '横峰',
+      '合川',
+      '含山',
+      '海阳',
+      '海盐',
+      '海宁',
+      '海门',
+      '海丰',
+      '海安',
+      '湖州',
+      '户县',
+      '霍山',
+      '霍邱',
+      '呼兰',
+      '湖口',
+      '惠民',
+      '惠来',
+      '惠东',
+      '会昌',
+      '惠安',
+      '化州',
+      '桓台'
+    ]
+  },
+  {
+    letter: 'J',
+    list: [
+      '鸡西',
+      '酒泉',
+      '九江',
+      '锦州',
+      '晋中',
+      '济宁',
+      '金华',
+      '荆州',
+      '荆门',
+      '景德镇',
+      '晋城',
+      '金昌',
+      '揭阳',
+      '嘉峪关',
+      '吉安',
+      '江门',
+      '佳木斯',
+      '济南',
+      '吉林',
+      '嘉兴',
+      '焦作',
+      '井冈山',
+      '旌德',
+      '靖安',
+      '即墨',
+      '揭西',
+      '界首',
+      '揭东',
+      '嘉祥',
+      '嘉善',
+      '胶州',
+      '胶南',
+      '蕉岭',
+      '蛟河',
+      '吉安',
+      '建阳',
+      '建瓯',
+      '建宁',
+      '建湖',
+      '江阴',
+      '姜堰',
+      '江山',
+      '将乐',
+      '江津',
+      '江都',
+      '建德',
+      '九台',
+      '九江',
+      '吉水',
+      '晋州',
+      '金寨',
+      '缙云',
+      '金乡',
+      '金溪',
+      '进贤',
+      '金堂',
+      '金坛',
+      '晋宁',
+      '金门',
+      '晋江',
+      '金湖',
+      '井陉',
+      '泾县',
+      '景宁',
+      '靖江',
+      '巨野',
+      '莒县',
+      '句容',
+      '莒南',
+      '鄄城',
+      '济源',
+      '济阳',
+      '绩溪'
+    ]
+  },
+  {
+    letter: 'K',
+    list: [
+      '昆明',
+      '开封',
+      '喀什地',
+      '克拉玛依',
+      '克孜勒',
+      '开化',
+      '开平',
+      '开县',
+      '开阳',
+      '康平',
+      '垦利',
+      '昆山'
+    ]
+  },
+  {
+    letter: 'L',
+    list: [
+      '连云港',
+      '凉山',
+      '乐山',
+      '拉萨',
+      '廊坊',
+      '莱芜',
+      '来宾',
+      '洛阳',
+      '柳州',
+      '兰州',
+      '六盘水',
+      '六安',
+      '丽水',
+      '林芝',
+      '临沂',
+      '临夏',
+      '临汾',
+      '临沧',
+      '丽江',
+      '辽源',
+      '辽阳',
+      '聊城',
+      '乐亭',
+      '乐清',
+      '乐平',
+      '乐陵',
+      '雷州',
+      '乐昌',
+      '乐安',
+      '兰溪',
+      '蓝田',
+      '郎溪',
+      '莱州',
+      '莱阳',
+      '莱西',
+      '来安',
+      '吕梁',
+      '泸州',
+      '漯河',
+      '娄底',
+      '龙岩',
+      '陇南',
+      '临邑',
+      '临沭',
+      '临朐',
+      '临泉',
+      '临清',
+      '临海',
+      '陵县',
+      '灵寿',
+      '灵璧',
+      '临安',
+      '利津',
+      '黎川',
+      '辽中',
+      '连州',
+      '涟水',
+      '连山',
+      '连平',
+      '连南',
+      '廉江',
+      '连江',
+      '莲花',
+      '梁山',
+      '梁平',
+      '连城',
+      '鹿寨',
+      '芦溪',
+      '禄劝',
+      '鹿泉',
+      '罗源',
+      '洛宁',
+      '罗定',
+      '庐江',
+      '陆河',
+      '陆丰',
+      '滦县',
+      '滦南',
+      '栾川',
+      '栾城',
+      '龙游',
+      '龙泉',
+      '龙南',
+      '龙门',
+      '龙口',
+      '龙海',
+      '龙川',
+      '隆安',
+      '溧阳',
+      '利辛',
+      '浏阳',
+      '柳江',
+      '柳城',
+      '溧水'
+    ]
+  },
+  {
+    letter: 'M',
+    list: [
+      '马鞍山',
+      '茂名',
+      '眉山',
+      '梅州',
+      '绵阳',
+      '牡丹江',
+      '马山',
+      '梅县',
+      '蒙城',
+      '孟津',
+      '蒙阴',
+      '孟州',
+      '明光',
+      '明溪',
+      '闽侯',
+      '闽清',
+      '木兰'
+    ]
+  },
+  {
+    letter: 'N',
+    list: [
+      '南昌',
+      '南京',
+      '南宁',
+      '南通',
+      '宁波',
+      '南充',
+      '南平',
+      '南阳',
+      '那曲',
+      '内江',
+      '宁德',
+      '怒江',
+      '南安',
+      '南澳',
+      '南城',
+      '南川',
+      '南丰',
+      '南靖',
+      '南康',
+      '南陵',
+      '南雄',
+      '宁都',
+      '宁国',
+      '宁海',
+      '宁化',
+      '宁津',
+      '宁乡',
+      '宁阳',
+      '农安'
+    ]
+  },
+  {
+    letter: 'P',
+    list: [
+      '盘锦',
+      '攀枝花',
+      '平顶山',
+      '平凉',
+      '萍乡',
+      '普洱',
+      '莆田',
+      '濮阳',
+      '磐安',
+      '磐石',
+      '沛县',
+      '蓬莱',
+      '彭水',
+      '彭泽',
+      '彭州',
+      '平度',
+      '平和',
+      '平湖',
+      '屏南',
+      '平山',
+      '平潭',
+      '平阳',
+      '平阴',
+      '平邑',
+      '平原',
+      '平远',
+      '郫县',
+      '邳州',
+      '鄱阳',
+      '浦城',
+      '浦江',
+      '蒲江',
+      '普兰店',
+      '普宁'
+    ]
+  },
+  {
+    letter: 'Q',
+    list: [
+      '青岛',
+      '泉州',
+      '黔东',
+      '黔南',
+      '黔西南',
+      '庆阳',
+      '清远',
+      '秦皇岛',
+      '钦州',
+      '齐齐哈尔',
+      '七台河',
+      '曲靖',
+      '衢州',
+      '迁安',
+      '潜山',
+      '铅山',
+      '迁西',
+      '启东',
+      '齐河',
+      '綦江',
+      '祁门',
+      '清流',
+      '青田',
+      '清新',
+      '青阳',
+      '庆元',
+      '庆云',
+      '清镇',
+      '青州',
+      '沁阳',
+      '邛崃',
+      '栖霞',
+      '全椒',
+      '曲江',
+      '曲阜',
+      '全南'
+    ]
+  },
+  {
+    letter: 'R',
+    list: [
+      '日喀则',
+      '日照',
+      '饶平',
+      '仁化',
+      '融安',
+      '荣昌',
+      '荣成',
+      '融水',
+      '如东',
+      '如皋',
+      '瑞安',
+      '瑞昌',
+      '瑞金',
+      '乳山',
+      '汝阳',
+      '乳源'
+    ]
+  },
+  {
+    letter: 'S',
+    list: [
+      '上海',
+      '沈阳',
+      '深圳',
+      '石家庄',
+      '苏州',
+      '三门峡',
+      '三明',
+      '三亚',
+      '商丘',
+      '商洛',
+      '上饶',
+      '汕尾',
+      '汕头',
+      '绍兴',
+      '韶关',
+      '山南',
+      '邵阳',
+      '十堰',
+      '双鸭山',
+      '石嘴山',
+      '绥化',
+      '松原',
+      '四平',
+      '朔州',
+      '泗阳',
+      '泗县',
+      '泗水',
+      '四会',
+      '泗洪',
+      '沭阳',
+      '顺昌',
+      '舒兰',
+      '舒城',
+      '双流',
+      '双城',
+      '寿县',
+      '寿宁',
+      '寿光',
+      '石柱',
+      '始兴',
+      '石台',
+      '石狮',
+      '石林',
+      '石城',
+      '射阳',
+      '歙县',
+      '深泽',
+      '莘县',
+      '嵊州',
+      '嵊泗',
+      '沙县',
+      '绍兴',
+      '邵武',
+      '尚志',
+      '上虞',
+      '上犹',
+      '上饶',
+      '上林',
+      '上栗',
+      '商河',
+      '上杭',
+      '上高',
+      '诏安',
+      '三门',
+      '三江',
+      '松阳',
+      '嵩县',
+      '松溪',
+      '嵩明',
+      '宿州',
+      '宿迁',
+      '随州',
+      '遂宁',
+      '宿松',
+      '遂溪',
+      '濉溪',
+      '睢宁',
+      '遂川',
+      '遂昌',
+      '宿豫'
+    ]
+  },
+  {
+    letter: 'T',
+    list: [
+      '天津',
+      '台州',
+      '唐山',
+      '塔城地',
+      '泰安',
+      '太原',
+      '泰州',
+      '天水',
+      '铁岭',
+      '铜川',
+      '通化',
+      '通辽',
+      '铜陵',
+      '铜仁',
+      '通州',
+      '桐乡',
+      '铜山',
+      '潼南',
+      '桐庐',
+      '铜陵',
+      '铜梁',
+      '通河',
+      '铜鼓',
+      '桐城',
+      '天台',
+      '天长',
+      '滕州',
+      '唐海',
+      '郯城',
+      '泰兴',
+      '泰顺',
+      '台山',
+      '泰宁',
+      '太湖',
+      '泰和',
+      '太和',
+      '太仓',
+      '吐鲁番'
+    ]
+  },
+  {
+    letter: 'W',
+    list: [
+      '潍坊',
+      '威海',
+      '武汉',
+      '无锡',
+      '渭南',
+      '文山',
+      '温州',
+      '乌海',
+      '芜湖',
+      '乌兰察布',
+      '乌鲁木齐',
+      '武威',
+      '吴忠',
+      '武陟',
+      '婺源',
+      '武夷山',
+      '武义',
+      '巫溪',
+      '无为',
+      '巫山',
+      '武平',
+      '武宁',
+      '武鸣',
+      '武隆',
+      '五莲',
+      '吴江',
+      '无极',
+      '五华',
+      '芜湖',
+      '五河',
+      '无棣',
+      '吴川',
+      '武城',
+      '五常',
+      '涡阳',
+      '温县',
+      '汶上',
+      '温岭',
+      '翁源',
+      '文登',
+      '文成',
+      '微山',
+      '万载',
+      '万年',
+      '望江',
+      '望城',
+      '万安',
+      '瓦房店',
+      '梧州'
+    ]
+  },
+  {
+    letter: 'X',
+    list: [
+      '厦门',
+      '西安',
+      '许昌',
+      '徐州',
+      '襄樊',
+      '湘潭',
+      '湘西',
+      '咸宁',
+      '咸阳',
+      '孝感',
+      '锡林郭勒盟',
+      '兴安盟',
+      '邢台',
+      '西宁',
+      '新乡',
+      '信阳',
+      '新余',
+      '忻州',
+      '西双版纳',
+      '宣城',
+      '峡江',
+      '夏津',
+      '象山',
+      '响水',
+      '仙居',
+      '仙游',
+      '萧县',
+      '霞浦',
+      '息烽',
+      '新安',
+      '新昌',
+      '信丰',
+      '新丰',
+      '新干',
+      '兴国',
+      '兴化',
+      '兴宁',
+      '行唐',
+      '荥阳',
+      '星子',
+      '辛集',
+      '新建',
+      '新津',
+      '新乐',
+      '新民',
+      '新密',
+      '新泰',
+      '新兴',
+      '新沂',
+      '信宜',
+      '新郑',
+      '休宁',
+      '秀山',
+      '修水',
+      '修文',
+      '修武',
+      '寻甸',
+      '盱眙',
+      '徐闻',
+      '寻乌'
+    ]
+  },
+  {
+    letter: 'Y',
+    list: [
+      '扬州',
+      '烟台',
+      '雅安',
+      '延安',
+      '延边',
+      '盐城',
+      '阳江',
+      '阳泉',
+      '宜宾',
+      '宜昌',
+      '伊春',
+      '宜春',
+      '伊犁哈萨克',
+      '银川',
+      '营口',
+      '鹰潭',
+      '益阳',
+      '永州',
+      '岳阳',
+      '玉林',
+      '榆林',
+      '运城',
+      '云浮',
+      '玉树',
+      '玉溪',
+      '阳春',
+      '阳东',
+      '阳谷',
+      '阳山',
+      '阳信',
+      '阳西',
+      '扬中',
+      '偃师',
+      '延寿',
+      '兖州',
+      '伊川',
+      '宜丰',
+      '宜黄',
+      '依兰',
+      '宜良',
+      '沂南',
+      '英德',
+      '颍上',
+      '沂水',
+      '义乌',
+      '黟县',
+      '宜兴',
+      '弋阳',
+      '宜阳',
+      '沂源',
+      '仪征',
+      '永安',
+      '永川',
+      '永春',
+      '永登',
+      '永定',
+      '永丰',
+      '永吉',
+      '永嘉',
+      '永康',
+      '邕宁',
+      '永泰',
+      '永新',
+      '永修',
+      '尤溪',
+      '酉阳',
+      '元氏',
+      '禹城',
+      '于都',
+      '岳西',
+      '余干',
+      '玉环',
+      '余江',
+      '郁南',
+      '云安',
+      '郓城',
+      '云和',
+      '云霄',
+      '云阳',
+      '玉山',
+      '榆树',
+      '鱼台',
+      '玉田',
+      '余姚',
+      '榆中'
+    ]
+  },
+  {
+    letter: 'Z',
+    list: [
+      '漳州',
+      '遵化',
+      '郑州',
+      '中山',
+      '珠海',
+      '枣庄',
+      '张家界',
+      '张家口',
+      '张掖',
+      '湛江',
+      '肇庆',
+      '昭通',
+      '镇江',
+      '中卫',
+      '周口',
+      '舟山',
+      '驻马店',
+      '株洲',
+      '淄博',
+      '自贡',
+      '资阳',
+      '遵义',
+      '赞皇',
+      '增城',
+      '张家港',
+      '漳平',
+      '漳浦',
+      '章丘',
+      '樟树',
+      '沾化',
+      '赵县',
+      '招远',
+      '正定',
+      '政和',
+      '柘荣',
+      '中牟',
+      '忠县',
+      '周宁',
+      '周至',
+      '庄河',
+      '诸城',
+      '诸暨',
+      '紫金',
+      '资溪',
+      '邹城',
+      '邹平'
+    ]
+  }
+]
+
+export default cityData

+ 296 - 0
components/lh-select-city/index.vue

@@ -0,0 +1,296 @@
+<template>
+	<view class="select-city-wrap" :style="'height:'+windowHeight">
+		<!-- 内容 -->
+		<scroll-view class="scroll" :scroll-into-view="scrollIntoId" :scroll-y="true" :scroll-with-animation="true"
+			:show-scrollbar="false" :style="'height:'+windowHeight">
+			<view class="action" @tap="BackPage">
+				<view class="action-box">
+					<text class="cuIcon-back"></text>
+					<slot name="backText">选择城市</slot>
+					<text style="width:72rpx"></text>
+				</view>
+			</view>
+			<!-- 当前城市 -->
+			<view style="height:200rpx">
+				<text class="name" id="current">当前城市</text>
+				<view class="city-item" v-if="city">
+					<view class="city-item-view">
+						<text class="city-item-text">{{ city }}</text>
+					</view>
+				</view>
+			</view>
+
+			<!-- 热门城市 -->
+			<text class="name">热门城市</text>
+			<view class="city-item">
+				<view :class=" city== cityname?'city-item-viewa':'city-item-view' " v-for="(cityname, i) in hotCitys"
+					:key="cityname + 4" @click="onSelect(cityname)">
+					<text :class=" city== cityname?'city-item-texta':'city-item-text' ">{{ cityname }}</text>
+				</view>
+			</view>
+			<view :id="item.letter" v-for="item in cityData" :key="item.letter+1">
+				<!-- ABCD -->
+				<text class="letter">{{ item.letter }}</text>
+				<!-- 城市 -->
+				<view class="city-item">
+					<view :class=" city== cityname?'city-item-viewa':'city-item-view' "
+						v-for="(cityname, i) in item.list" :key="cityname + 5 * i" @click="onSelect(cityname)">
+						<text :class=" city== cityname?'city-item-texta':'city-item-text' ">{{ cityname }}</text>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+
+		<!-- 右边锚点 -->
+		<view class="anchor" @touchstart="start" @touchmove="move" @touchend="end" v-if="sliding">
+
+			<view>
+				<view class="anchor-item" @click="scrollIntoId='current' "><text class="anchor-text">#</text></view>
+				<view class="anchor-item" v-for="(item,index) in anchorArr" :key="item + 2" @click="scrollIntoId=item">
+					<text class="anchor-text">{{item}}</text>
+				</view>
+			</view>
+		</view>
+		<view class="anchor" v-else>
+			<view>
+				<view class="anchor-item" @click="scrollIntoId='current' "><text class="anchor-text">#</text></view>
+				<view class="anchor-item" v-for="(item,index) in anchorArr" :key="item + 3" @click="scrollIntoId=item">
+					<text class="anchor-text">{{item}}</text>
+				</view>
+			</view>
+		</view>
+
+
+	</view>
+</template>
+<script>
+	// hotCitys  热门城市  
+	// value 当前选中城市
+	// windowHeight  scroll的高 也是滑块的高 记得带单位!!! px rpx upx都支持
+	// sliding 是否开始滑动选择 默认开启  false true
+	// @onSelect   点击切换城市事件 参数为城市名称
+	import cityData from './cityData.js'
+	let anchorArr = ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X",
+		"Y", "Z"
+	];
+	export default {
+		props: {
+			hotCitys: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			value: {
+				type: String
+			},
+			windowHeight: {
+				type: String
+			},
+			// 开启滑动选择
+			sliding: {
+				type: Boolean,
+				default: true
+			},
+		},
+		data() {
+			return {
+				cityData,
+				scrollIntoId: '',
+				city: this.value,
+				anchorArr,
+				// 滑动中选中的具体值
+				slidingChoice: "",
+				//开始滑动位置
+				startY: "",
+				// 滑动中当前选中下标
+				downIndex: -1,
+			}
+		},
+		computed: {},
+		methods: {
+			// 点击城市
+			onSelect(city) {
+				this.city = city;
+				this.$emit('onSelect', city)
+			},
+			// 开始滑动
+			start(e) {
+				// console.log("开始滑动",e);
+				// #ifdef MP
+				let eY = e.changedTouches[0].clientY
+				// #endif
+				// #ifdef APP-PLUS
+				let eY = e.changedTouches[0].screenY
+				// #endif
+				this.startY = eY;
+				// 计算点击时候下标
+				let index = eY / (uni.upx2px(eY) / eY);
+				index = parseInt((index - 200) / 40) - 1;
+				this.downIndex = index;
+			},
+			// 开始移动
+			move(e) {
+				// console.log("开始移动",e);
+				// #ifdef MP
+				let downY = e.changedTouches[0].clientY;
+				// #endif
+				// #ifdef APP-PLUS
+				let downY = e.changedTouches[0].screenY;
+				// #endif
+
+				let gap = this.startY - downY;
+				let index = parseInt(gap / (uni.upx2px(gap) / gap) / 40);
+				// 选中下标
+				let optforIndex = this.downIndex - index;
+				if (optforIndex < -1) {
+					optforIndex = -1;
+				} else if (optforIndex > 21) {
+					optforIndex = 21;
+				}
+				this.slidingChoice = this.anchorArr[optforIndex];
+				this.scrollIntoId = this.anchorArr[optforIndex];
+			},
+			// 滑动结束
+			end(e) {
+				// console.log("结束滑动",e)
+				this.slidingChoice = '';
+			},
+			BackPage() {
+			this.$emit("closeLhSelectCityFun")
+			}
+
+		}
+	}
+</script>
+
+<style scoped>
+	/deep/.select-city-wrap {
+		height: 100vh;
+		overflow: hidden;
+		z-index: 9999;
+	}
+
+	/* 滑块 */
+	.scroll {
+		/* background-color: yellow; */
+	}
+
+	.name {
+		color: #333;
+		font-size: 28rpx;
+		margin: 30rpx 30rpx;
+	}
+
+	/* 城市 */
+	.letter {
+		width: 44rpx;
+		height: 44rpx;
+		color: #fff;
+		border-radius: 22rpx;
+		background-color: #2f9bfe;
+		font-size: 28rpx;
+		line-height: 44rpx;
+		text-align: center;
+		margin-bottom: 30rpx;
+		margin-left: 30rpx;
+		display: inline-block;
+	}
+
+	.city-item {
+		display: flex;
+		flex-wrap: wrap;
+		flex-direction: row;
+		margin-left: 20rpx;
+	}
+
+	.city-item-view {
+		width: 180rpx;
+		height: 55rpx;
+		margin: 15rpx;
+		border: 1rpx solid #dcdcdc;
+		border-radius: 6rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #FFFFFF;
+		/* 	background-color: #d5ebff;
+	border-color: #2f9bfe; */
+	}
+
+	.city-item-viewa {
+		width: 180rpx;
+		height: 55rpx;
+		margin: 15rpx;
+		border: 1rpx solid #2f9bfe;
+		border-radius: 6rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #d5ebff;
+	}
+
+	.city-item-text {
+		color: #999;
+		font-size: 28rpx;
+	}
+
+	.city-item-texta {
+		font-size: 28rpx;
+		color: #2f9bfe;
+	}
+
+	/* 右锚点 */
+	.anchor {
+		/* background-color: pink; */
+		position: fixed;
+		right: 20rpx;
+		top: 200rpx;
+		z-index: 10;
+		flex-direction: row;
+	}
+
+	.anchor-item {
+		align-items: center;
+		flex-direction: row;
+		height: 40rpx;
+		text-align: center;
+	}
+
+	.anchor-text-position {
+		height: 40rpx;
+		width: 40rpx;
+		text-align: center;
+		line-height: 40rpx;
+		font-size: 32rpx;
+		color: #333;
+		background-color: #E5E5E5;
+		border-radius: 20rpx;
+	}
+
+	.anchor-text {
+		font-size: 32rpx;
+		line-height: 40rpx;
+		padding: 0 15rpx;
+		color: #2f9bfe;
+	}
+
+	.action {
+		height: 60rpx;
+	}
+
+	.action-box {
+		position: fixed;
+		left: 20rpx;
+		top: 0;
+		width: 100vw;
+		height: 60rpx;
+		box-sizing: border-box;
+		background-color: #fff;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.backText {}
+</style>

+ 13 - 0
components/lh-select-city/package.json

@@ -0,0 +1,13 @@
+{
+    "id": "lh-select-city",
+    "name": "城市选择 (支持nvue)",
+    "version": "1.1",
+    "description": "uni-app城市选择插件 支持nvue",
+    "keywords": [
+        "nvue",
+        "城市",
+        "城市选择",
+        "选择城市",
+        "选择市"
+    ]
+}

+ 4 - 0
main.js

@@ -25,6 +25,10 @@ Vue.prototype.isArray = Array.isArray || function(obj) {
 	return obj instanceof Array;
 };
 
+//挂载全局http请求
+import $http from '@/common/requestConfig'
+Vue.prototype.$http = $http;
+
 App.mpType = 'app'
 
 const app = new Vue({

+ 10 - 0
node_modules/zhouWei-request/changelog.md

@@ -0,0 +1,10 @@
+## 3.3.2(2021-07-29)
+修复app用阿里云上传文件报错
+## 3.3.1(2021-07-09)
+修改阿里云视频上传bug
+## 3.3.0(2021-07-09)
+新增阿里云文件上传、图片上传
+## 3.2.1(2021-05-18)
+新增文件类型
+## 3.2.0(2021-05-12)
+1. 支持uni_modules

+ 132 - 0
node_modules/zhouWei-request/js_sdk/request/core/request.js

@@ -0,0 +1,132 @@
+import { mergeConfig, dispatchRequest, jsonpRequest} from "./utils.js";
+export default class request {
+	constructor(options) {
+		//请求公共地址
+		this.baseUrl = options.baseUrl || "";
+		//公共文件上传请求地址
+		this.fileUrl = options.fileUrl || "";
+		// 超时时间
+		this.timeout = options.timeout || 6000;
+		// 服务器上传图片默认url
+		this.defaultUploadUrl = options.defaultUploadUrl || "";
+		// 服务器上传文件名称
+		this.defaultFileName = options.defaultFileName || "";
+		//默认请求头
+		this.header = options.header || {};
+		//默认配置
+		this.config = options.config || {
+			isPrompt: true,
+			load: true,
+			isFactory: true,
+            resend: 0
+		};
+	}
+	//post请求
+	post(url = '', data = {}, options = {}) {
+		return this.request({
+			method: "POST",
+			data: data,
+			url: url,
+			...options
+		});
+	}
+
+	//get请求
+	get(url = '', data = {}, options = {}) {
+		return this.request({
+			method: "GET",
+			data: data,
+			url: url,
+			...options
+		});
+	}
+
+	//put请求
+	put(url = '', data = {}, options = {}) {
+		return this.request({
+			method: "PUT",
+			data: data,
+			url: url,
+			...options
+		});
+	}
+
+	//delete请求
+	delete(url = '', data = {}, options = {}) {
+		return this.request({
+			method: "DELETE",
+			data: data,
+			url: url,
+			...options
+		});
+	}
+	//jsonp请求(只限于H5使用)
+	jsonp(url = '', data = {}, options = {}) {
+		return this.request({
+			method: "JSONP",
+			data: data,
+			url: url,
+			...options
+		});
+	}
+	//接口请求方法
+	async request(data) {
+		// 请求数据
+		let requestInfo,
+		// 是否运行过请求开始钩子
+		runRequestStart = false;
+		try {
+			if (!data.url) {
+				throw { errMsg: "【request】缺失数据url", statusCode: 0}
+			}
+			// 数据合并
+			requestInfo = mergeConfig(this, data);
+			// 代表之前运行到这里
+			runRequestStart = true;
+			//请求前回调
+			if (this.requestStart) {
+				let requestStart = this.requestStart(requestInfo);
+				if (typeof requestStart == "object") {
+					let changekeys = ["data", "header", "isPrompt", "load", "isFactory"];
+					changekeys.forEach(key => {
+						requestInfo[key] = requestStart[key];
+					});
+				} else {
+					throw {
+						errMsg: "【request】请求开始拦截器未通过",
+						statusCode: 0,
+						data: requestInfo.data,
+						method: requestInfo.method,
+						header: requestInfo.header,
+						url: requestInfo.url,
+					}
+				}
+			}
+			let requestResult = {};
+			if(requestInfo.method == "JSONP"){
+				requestResult = await jsonpRequest(requestInfo);
+			} else {
+				requestResult = await dispatchRequest(requestInfo);
+			}
+			//是否用外部的数据处理方法
+			if (requestInfo.isFactory && this.dataFactory) {
+				//数据处理
+				let result = await this.dataFactory({
+					...requestInfo,
+					response: requestResult
+				});
+				return Promise.resolve(result);
+			} else {
+				return Promise.resolve(requestResult);
+			}
+		} catch (err){
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		} finally {
+			// 如果请求开始未运行到,请求结束也不运行
+			if(runRequestStart){
+				this.requestEnd && this.requestEnd(requestInfo);
+			}
+		}
+	}
+}

+ 101 - 0
node_modules/zhouWei-request/js_sdk/request/core/utils.js

@@ -0,0 +1,101 @@
+// 获取合并的数据
+export const mergeConfig = function(_this, options) {
+	//判断url是不是链接
+	let urlType = /^(http|https):\/\//.test(options.url);
+	let config = Object.assign({
+		timeout: _this.timeout
+	}, _this.config, options);
+	if (options.method == "FILE") {
+		config.url = urlType ? options.url : _this.fileUrl + options.url;
+	} else {
+		config.url = urlType ? options.url : _this.baseUrl + options.url;
+	}
+	//请求头
+	if (options.header) {
+		config.header = Object.assign({}, _this.header, options.header);
+	} else {
+		config.header = Object.assign({}, _this.header);
+	}
+	return config;
+}
+// 请求
+export const dispatchRequest = function(requestInfo) {
+	return new Promise((resolve, reject) => {
+		let requestAbort = true;
+		let requestData = {
+			url: requestInfo.url,
+			header: requestInfo.header, //加入请求头
+			success: (res) => {
+				requestAbort = false;
+				resolve(res);
+			},
+			fail: (err) => {
+				requestAbort = false;
+				if(err.errMsg == "request:fail abort"){
+					reject({
+						errMsg: "请求超时,请重新尝试",
+						statusCode: 0,
+					});
+				} else {
+					reject(err);
+				}
+			}
+		};
+		//请求类型
+		if (requestInfo.method) {
+			requestData.method = requestInfo.method;
+		}
+		if (requestInfo.data) {
+			requestData.data = requestInfo.data;
+		}
+		// #ifdef MP-WEIXIN || MP-ALIPAY
+		if (requestInfo.timeout) {
+			requestData.timeout = requestInfo.timeout;
+		}
+		// #endif
+		if (requestInfo.dataType) {
+			requestData.dataType = requestInfo.dataType;
+		}
+		// #ifndef APP-PLUS || MP-ALIPAY
+		if (requestInfo.responseType) {
+			requestData.responseType = requestInfo.responseType;
+		}
+		// #endif
+		// #ifdef H5
+		if (requestInfo.withCredentials) {
+			requestData.withCredentials = requestInfo.withCredentials;
+		}
+		// #endif
+		let requestTask = uni.request(requestData);
+		setTimeout(() => {
+			if(requestAbort){
+				requestTask.abort();
+			}
+		}, requestInfo.timeout)
+	})
+}
+// jsonp请求
+export const jsonpRequest = function(requestInfo) {
+	return new Promise((resolve, reject) => {
+		let dataStr = '';
+		Object.keys(requestInfo.data).forEach(key => {
+			dataStr += key + '=' + requestInfo.data[key] + '&';
+		});
+		//匹配最后一个&并去除
+		if (dataStr !== '') {
+			dataStr = dataStr.substr(0, dataStr.lastIndexOf('&'));
+		}
+		requestInfo.url = requestInfo.url + '?' + dataStr;
+		let callbackName = "callback" + Math.ceil(Math.random() * 1000000);
+		// #ifdef H5
+		window[callbackName] = function(data) {
+			resolve(data);
+		}
+		let script = document.createElement("script");
+		script.src = requestInfo.url + "&callback=" + callbackName;
+		document.head.appendChild(script);
+		// 及时删除,防止加载过多的JS
+		document.head.removeChild(script);
+		// #endif
+	});
+}

+ 7 - 0
node_modules/zhouWei-request/js_sdk/request/index.js

@@ -0,0 +1,7 @@
+/***************纯粹的数据请求(如果使用这种可以删除掉fileUpload.js)******************/
+// import request from "./core/request.js";
+// export default request;
+
+/********数据请求同时继承了文件上传(包括七牛云上传)************/
+import upload from "./upload/upload.js";
+export default upload;

+ 451 - 0
node_modules/zhouWei-request/js_sdk/request/request.md

@@ -0,0 +1,451 @@
+# request请求、配置简单、批量上传图片、视频、超强适应性(支持多域名请求)
+1. 配置简单、源码清晰注释多、适用于一项目多域名请求、第三方请求、七牛云图片上传、本地服务器图片上传等等
+2. 支持请求`get`、`post`、`put`、`delete`
+3. 自动显示请求加载动画(可单个接口关闭)
+4. 全局`api`数据处理函数,只回调请求正确的数据(可单个接口关闭)
+5. 未登录或登录失效自动拦截并调用登录方法(可单个接口关闭)
+6. 全局自动提示接口抛出的错误信息(可单个接口关闭)
+7. 支持 Promise
+8. 支持拦截器
+9. 支持七牛云文件(图片、视频)批量上传
+10. 支持本地服务器文件(图片、视频)批量上传
+11. 支持上传文件拦截过滤
+12. 支持上传文件进度监听
+13. 支持上传文件单张成功回调
+
+| `QQ交流群(607391225)`         | `微信交流群(加我好友备注"进群")`                  |
+| ----------------------------|--------------------------- |
+|![QQ交流群](http://qn.kemean.cn//upload/202004/14/15868301778472k7oubi6.png)|![微信交流群](https://qn.kemean.cn/upload/202010/13/weiXin_group_code.jpg)|
+| QQ群号:607391225 |微信号:zhou0612wei|
+
+### [点击跳转-插件示例](https://ext.dcloud.net.cn/plugin?id=2009)
+### [点击跳转-5年的web前端开源的uni-app快速开发模板-下载看文档](https://ext.dcloud.net.cn/plugin?id=2009)
+
+### 常见问题
+1.接口请求成功了,没有返回数据或者数据是走的catch回调
+
+答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改`
+
+2.官方的方法有数据,本插件方法请求报错跨域问题
+
+答:`requestConfig.js` 请求配置文件里面,`header`请求头设置的`content-type`请求类型需求和后台保持一致
+
+3.登录后用户`token`怎么设置?
+
+答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置
+
+4.怎么判断上传的文件(图片)太大?怎么过滤掉太大的文件(图片)?
+
+答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置
+
+5.接口请求成功了,一直提示“网络错误,请检查一下网络”?
+
+答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改`
+
+### 本次更新注意事项
+1. 所有的headers都改成了header(和官方统一)
+2. 七牛云的获取token等信息提取到了`requestConfig.js`文件,参考如下
+
+### 文件说明
+1. `request => core` 请求方法的目录
+2. `request => core => request.js` 请求方法的class文件
+3. `request => core => utils.js` 请求方法的源码文件
+4. `request => upload` 上传方法的目录
+5. `request => upload => upload.js` 上传方法的class文件
+6. `request => upload => utils.js` 上传方法源码文件
+7. `request => upload => qiniuUploader.js` 七牛云官方上传文件
+8. `request => index.js` 输出方法的文件
+9. `requestConfig.js` 请求配置文件(具体看代码)
+
+### 在main.js引入并挂在Vue上
+```
+import $http from '@/zhouWei-request/requestConfig';
+Vue.prototype.$http = $http;
+```
+
+### `requestConfig.js`配置说明(requestConfig.js有配置示例)
+```
+import request from "@/plugins/request";
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//接口请求地址
+	baseUrl: "https://twin-ui.com/", //示例域名,请自行设计
+	//服务器本地上传文件地址
+	fileUrl: "https://twin-ui.com/", //示例域名,请自行设计
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+	//设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致)
+	header: {
+		'Content-Type': 'application/json;charset=UTF-8'
+	},
+    // 请求超时时间(默认6000)
+    timeout: 6000,
+    // 默认配置(可不写)
+    config: {
+        // 是否自动提示错误
+        isPrompt: true,
+        // 是否显示加载动画
+        load: true,
+        // 是否使用数据工厂
+        isFactory: true,
+       // ... 可写更多配置
+    }
+});
+
+// 添加获取七牛云token的方法
+$http.getQnToken = function(callback){
+	//该地址需要开发者自行配置(每个后台的接口风格都不一样)
+	$http.get("api/common/v1/qn_upload").then(data => {
+		/*
+		 *接口返回参数:
+		 *visitPrefix:访问文件的域名
+		 *token:七牛云上传token
+		 *folderPath:上传的文件夹
+		 *region: 地区 默认为:SCN
+		 */
+		callback({
+			visitPrefix: data.visitPrefix,
+			token: data.token,
+			folderPath: data.folderPath
+		});
+	});
+}
+//当前接口请求数
+let requestNum = 0;
+//请求开始拦截器
+$http.requestStart = function(options) {
+    if (options.load) {
+    	if (requestNum <= 0) {
+            //打开加载动画
+            uni.showLoading({
+                title: '加载中',
+                mask: true
+            });
+        }
+        requestNum += 1;
+    }
+    // 图片上传大小限制
+    if (options.method == "FILE" && options.maxSize) {
+    	// 文件最大字节: options.maxSize 可以在调用方法的时候加入参数
+    	let maxSize = options.maxSize;
+    	for (let item of options.files) {
+    		if (item.size > maxSize) {
+    			setTimeout(() => {
+    				uni.showToast({
+    					title: "图片过大,请重新上传",
+    					icon: "none"
+    				});
+    			}, 500);
+    			return false;
+    		}
+    	}
+    }
+    //请求前加入token
+    options.header['token'] = "你的项目token";
+    return options; // return false 表示请求拦截,不会继续请求
+}
+//请求结束
+$http.requestEnd = function(options) {
+	//判断当前接口是否需要加载动画
+	if (options.load) {
+		requestNum = requestNum - 1;
+		if (requestNum <= 0) {
+			uni.hideLoading();
+		}
+	}
+}
+//所有接口数据处理(可在接口里设置不调用此方法)
+//此方法需要开发者根据各自的接口返回类型修改,以下只是模板
+$http.dataFactory = async function(res) {
+    console.log("接口请求数据", {
+        url: res.url,
+        resolve: res.response,
+        header: res.header,
+        data: res.data,
+        method: res.method,
+    });
+    if (res.response.statusCode && res.response.statusCode == 200) {
+        let httpData = res.response.data;
+        if (typeof (httpData) == "string") {
+            httpData = JSON.parse(httpData);
+        }
+        // 开始----------------------以下是示例-请认真阅读代码-----------------------开始
+        //判断数据是否请求成功
+        if (httpData.success || httpData.code == 200) {  // 重点------判断接口请求是否成功,成功就返回成功的数据
+            // ---重点---返回正确的结果(then接受数据)---重点---
+            return Promise.resolve(httpData);
+        } else {
+            //其他错误提示
+            if (res.isPrompt) { // 是否提示
+                uni.showToast({
+                    title: httpData.info || httpData.msg, // 重点------把接口返回的错误抛出显示
+                    icon: "none",
+                    duration: 3000
+                });
+            }
+            // ---重点---返回错误的结果(catch接受数据)----重点---
+            return Promise.reject({
+                statusCode: 0,
+                errMsg: "【request】" + (httpData.info || httpData.msg)
+            });
+        }
+        // 结束----------------------以上是示例-请认真阅读代码-----------------------结束
+    } else {
+		// 返回错误的结果(catch接受数据)
+		return Promise.reject({
+			statusCode: res.response.statusCode,
+			errMsg: "【request】数据工厂验证不通过"
+		});
+	}
+};
+// 错误回调(所有错误都在这里)
+$http.requestError = function (e) {
+	if (e.statusCode === 0) {
+		throw e;
+	} else {
+		uni.showToast({
+			title: "网络错误,请检查一下网络",
+			icon: "none"
+		});
+	}
+}
+```
+
+### 通用请求方法
+```
+this.$http.request({
+	url: 'aid/region',
+	method: "GET", // POST、GET、PUT、DELETE、JSONP,具体说明查看官方文档
+	data: {pid:0},
+	timeout: 30000,  // 默认 30000 说明:超时时间,单位 ms,具体说明查看官方文档
+	dataType: "json",  // 默认 json 说明:如果设为 json,会尝试对返回的数据做一次 JSON.parse,具体说明查看官方文档
+	responseType: "text",  // 默认 text 说明:设置响应的数据类型。合法值:text、arraybuffer,具体说明查看官方文档
+	withCredentials: false,  // 默认 false 说明:跨域请求时是否携带凭证(cookies),具体说明查看官方文档
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用)
+}).then(function (response) {
+	//这里只会在接口是成功状态返回
+}).catch(function (error) {
+	//这里只会在接口是失败状态返回,不需要去处理错误提示
+	console.log(error);
+});
+```
+
+### get请求 正常写法 
+```
+this.$http.get('aid/region',{pid:0}).
+then(function (response) {
+	//这里只会在接口是成功状态返回
+}).catch(function (error) {
+	//这里只会在接口是失败状态返回,不需要去处理错误提示
+	console.log(error);
+});
+```
+
+### post请求 async写法 
+```
+async request(){
+	let data = await this.$http.post('aid/region',{pid:0});
+	console.log(data);
+}
+```
+
+### 其他功能配置项
+```
+let data = await this.$http.post(
+	'http://www.aaa.com/aid/region', //可以直接放链接(将不启用全局定义域名)
+	{
+		pid:0
+	}, 
+	{
+		isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+		load: true,//(默认 true 说明:本接口是否提示加载动画)
+		header: { //默认 无 说明:请求头
+			'Content-Type': 'application/json'
+		},
+		isFactory: true //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用)
+	}
+);
+```
+
+### `requestConfig.js`可以设置服务器上传图片默认url
+```
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//服务器本地上传文件地址
+	fileUrl: base.baseUrl,
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+});
+```
+```
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlImgUpload({
+	name:"后台接受文件key名称", //默认 file
+	count:"最大选择数",//默认 9
+	sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	data:"而外参数" //可不填,
+});
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlVideoUpload({
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	name:"后台接受文件key名称", //默认 file
+	data:"而外参数" //可不填,
+});
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlFileUpload({
+	files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	data:"向服务器传递的参数", //可不填
+	name:"后台接受文件key名称", //默认 file
+});
+```
+
+### 本地服务器图片上传(支持多张上传)
+```
+this.$http.urlImgUpload('flie/upload',{
+	name:"后台接受文件key名称", //默认 file
+	count:"最大选择数",//默认 9
+	sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	data:"而外参数" //可不填,
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 本地服务器视频上传
+```
+this.$http.urlVideoUpload('flie/upload',{
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	name:"后台接受文件key名称", //默认 file
+	data:"而外参数" //可不填,
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	},
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 本地服务器文件上传(支持多张上传)
+```
+this.$http.urlFileUpload("flie/upload",{
+	files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	data:"向服务器传递的参数", //可不填
+	name:"后台接受文件key名称", //默认 file
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+
+### 七牛云图片上传(支持多张上传)
+```
+this.$http.qnImgUpload({
+	count:"最大选择数", // 默认 9
+	sizeType:"选择压缩图原图,默认两个都选", // 默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选", // 默认 ['album','camera']
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 七牛云视频上传
+```
+this.$http.qnVideoUpload({
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 七牛云文件上传(支持多张上传)
+```
+this.$http.qnFileUpload(
+{
+	files:[], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### jsonp 跨域请求(只支持H5)
+```
+let data = await this.$http.jsonp('http://www.aaa.com/aid/region',{pid:0}, {
+    isFactory: false, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+});
+```

+ 132 - 0
node_modules/zhouWei-request/js_sdk/request/upload/Base64.js

@@ -0,0 +1,132 @@
+const Base64 = {
+
+    // private property
+    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+    // public method for encoding
+    encode: function (input) {
+        var output = "";
+        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+        var i = 0;
+
+        input = Base64._utf8_encode(input);
+
+        while (i < input.length) {
+
+            chr1 = input.charCodeAt(i++);
+            chr2 = input.charCodeAt(i++);
+            chr3 = input.charCodeAt(i++);
+
+            enc1 = chr1 >> 2;
+            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+            enc4 = chr3 & 63;
+
+            if (isNaN(chr2)) {
+                enc3 = enc4 = 64;
+            } else if (isNaN(chr3)) {
+                enc4 = 64;
+            }
+
+            output = output +
+                this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
+                this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
+
+        }
+
+        return output;
+    },
+
+    // public method for decoding
+    decode: function (input) {
+        var output = "";
+        var chr1, chr2, chr3;
+        var enc1, enc2, enc3, enc4;
+        var i = 0;
+
+        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+        while (i < input.length) {
+
+            enc1 = this._keyStr.indexOf(input.charAt(i++));
+            enc2 = this._keyStr.indexOf(input.charAt(i++));
+            enc3 = this._keyStr.indexOf(input.charAt(i++));
+            enc4 = this._keyStr.indexOf(input.charAt(i++));
+
+            chr1 = (enc1 << 2) | (enc2 >> 4);
+            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+            chr3 = ((enc3 & 3) << 6) | enc4;
+
+            output = output + String.fromCharCode(chr1);
+
+            if (enc3 != 64) {
+                output = output + String.fromCharCode(chr2);
+            }
+            if (enc4 != 64) {
+                output = output + String.fromCharCode(chr3);
+            }
+
+        }
+
+        output = Base64._utf8_decode(output);
+
+        return output;
+
+    },
+
+    // private method for UTF-8 encoding
+    _utf8_encode: function (string) {
+        string = string.replace(/\r\n/g, "\n");
+        var utftext = "";
+
+        for (var n = 0; n < string.length; n++) {
+
+            var c = string.charCodeAt(n);
+
+            if (c < 128) {
+                utftext += String.fromCharCode(c);
+            } else if ((c > 127) && (c < 2048)) {
+                utftext += String.fromCharCode((c >> 6) | 192);
+                utftext += String.fromCharCode((c & 63) | 128);
+            } else {
+                utftext += String.fromCharCode((c >> 12) | 224);
+                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+                utftext += String.fromCharCode((c & 63) | 128);
+            }
+
+        }
+
+        return utftext;
+    },
+
+    // private method for UTF-8 decoding
+    _utf8_decode: function (utftext) {
+        var string = "";
+        var i = 0;
+        var c = c1 = c2 = 0;
+
+        while (i < utftext.length) {
+
+            c = utftext.charCodeAt(i);
+
+            if (c < 128) {
+                string += String.fromCharCode(c);
+                i++;
+            } else if ((c > 191) && (c < 224)) {
+                c2 = utftext.charCodeAt(i + 1);
+                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+                i += 2;
+            } else {
+                c2 = utftext.charCodeAt(i + 1);
+                c3 = utftext.charCodeAt(i + 2);
+                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+                i += 3;
+            }
+
+        }
+
+        return string;
+    }
+}
+
+module.exports = Base64;

+ 40 - 0
node_modules/zhouWei-request/js_sdk/request/upload/aliUploader.js

@@ -0,0 +1,40 @@
+const Base64 = require('./Base64.js');
+require('./hmac.js');
+require('./sha1.js');
+const Crypto = require('./crypto.js');
+// 获取policy
+const getPolicyBase64 = function (timeout) {
+    let dateTime = new Date().getTime();
+	let date = new Date(dateTime + (timeout || 1800000));
+    let srcT = date.toISOString();
+    const policyText = {
+        "expiration": srcT, //设置该Policy的失效时间
+        "conditions": [
+            ["content-length-range", 0, 100 * 1024 * 1024] // 设置上传文件的大小限制,100mb
+        ]
+    };
+    const policyBase64 = Base64.encode(JSON.stringify(policyText));
+    return policyBase64;
+}
+// 获取签名
+const getSignature = function (policyBase64, AccessKeySecret) {
+    const bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, AccessKeySecret, {
+        asBytes: true
+    });
+    const signature = Crypto.util.bytesToBase64(bytes);
+    return signature;
+}
+// 获取阿里云token信息
+const getAliyunOssKey = function (options) {
+	const policyBase64 = getPolicyBase64(options.timeout);
+	const signature = getSignature(policyBase64, options.accessKeySecret);
+	return {
+		policy: policyBase64,
+		accessKeyId: options.accessKeyId,
+		accessKeySecret: options.accessKeySecret,
+		signature: signature,
+		success_action_status: '200'
+	}
+}
+
+module.exports = getAliyunOssKey;

+ 185 - 0
node_modules/zhouWei-request/js_sdk/request/upload/crypto.js

@@ -0,0 +1,185 @@
+/*!
+ * Crypto-JS v1.1.0
+ * http://code.google.com/p/crypto-js/
+ * Copyright (c) 2009, Jeff Mott. All rights reserved.
+ * http://code.google.com/p/crypto-js/wiki/License
+ */
+
+const Crypto = {};
+
+(function(){
+
+var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+// Crypto utilities
+var util = Crypto.util = {
+
+	// Bit-wise rotate left
+	rotl: function (n, b) {
+		return (n << b) | (n >>> (32 - b));
+	},
+
+	// Bit-wise rotate right
+	rotr: function (n, b) {
+		return (n << (32 - b)) | (n >>> b);
+	},
+
+	// Swap big-endian to little-endian and vice versa
+	endian: function (n) {
+
+		// If number given, swap endian
+		if (n.constructor == Number) {
+			return util.rotl(n,  8) & 0x00FF00FF |
+			       util.rotl(n, 24) & 0xFF00FF00;
+		}
+
+		// Else, assume array and swap all items
+		for (var i = 0; i < n.length; i++)
+			n[i] = util.endian(n[i]);
+		return n;
+
+	},
+
+	// Generate an array of any length of random bytes
+	randomBytes: function (n) {
+		for (var bytes = []; n > 0; n--)
+			bytes.push(Math.floor(Math.random() * 256));
+		return bytes;
+	},
+
+	// Convert a string to a byte array
+	stringToBytes: function (str) {
+		var bytes = [];
+		for (var i = 0; i < str.length; i++)
+			bytes.push(str.charCodeAt(i));
+		return bytes;
+	},
+
+	// Convert a byte array to a string
+	bytesToString: function (bytes) {
+		var str = [];
+		for (var i = 0; i < bytes.length; i++)
+			str.push(String.fromCharCode(bytes[i]));
+		return str.join("");
+	},
+
+	// Convert a string to big-endian 32-bit words
+	stringToWords: function (str) {
+		var words = [];
+		for (var c = 0, b = 0; c < str.length; c++, b += 8)
+			words[b >>> 5] |= str.charCodeAt(c) << (24 - b % 32);
+		return words;
+	},
+
+	// Convert a byte array to big-endian 32-bits words
+	bytesToWords: function (bytes) {
+		var words = [];
+		for (var i = 0, b = 0; i < bytes.length; i++, b += 8)
+			words[b >>> 5] |= bytes[i] << (24 - b % 32);
+		return words;
+	},
+
+	// Convert big-endian 32-bit words to a byte array
+	wordsToBytes: function (words) {
+		var bytes = [];
+		for (var b = 0; b < words.length * 32; b += 8)
+			bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
+		return bytes;
+	},
+
+	// Convert a byte array to a hex string
+	bytesToHex: function (bytes) {
+		var hex = [];
+		for (var i = 0; i < bytes.length; i++) {
+			hex.push((bytes[i] >>> 4).toString(16));
+			hex.push((bytes[i] & 0xF).toString(16));
+		}
+		return hex.join("");
+	},
+
+	// Convert a hex string to a byte array
+	hexToBytes: function (hex) {
+		var bytes = [];
+		for (var c = 0; c < hex.length; c += 2)
+			bytes.push(parseInt(hex.substr(c, 2), 16));
+		return bytes;
+	},
+
+	// Convert a byte array to a base-64 string
+	bytesToBase64: function (bytes) {
+
+		// Use browser-native function if it exists
+		// if (typeof btoa == "function") return btoa(util.bytesToString(bytes));
+
+		var base64 = [],
+		    overflow;
+
+		for (var i = 0; i < bytes.length; i++) {
+			switch (i % 3) {
+				case 0:
+					base64.push(base64map.charAt(bytes[i] >>> 2));
+					overflow = (bytes[i] & 0x3) << 4;
+					break;
+				case 1:
+					base64.push(base64map.charAt(overflow | (bytes[i] >>> 4)));
+					overflow = (bytes[i] & 0xF) << 2;
+					break;
+				case 2:
+					base64.push(base64map.charAt(overflow | (bytes[i] >>> 6)));
+					base64.push(base64map.charAt(bytes[i] & 0x3F));
+					overflow = -1;
+			}
+		}
+
+		// Encode overflow bits, if there are any
+		if (overflow != undefined && overflow != -1)
+			base64.push(base64map.charAt(overflow));
+
+		// Add padding
+		while (base64.length % 4 != 0) base64.push("=");
+
+		return base64.join("");
+
+	},
+
+	// Convert a base-64 string to a byte array
+	base64ToBytes: function (base64) {
+
+		// Use browser-native function if it exists
+		if (typeof atob == "function") return util.stringToBytes(atob(base64));
+
+		// Remove non-base-64 characters
+		base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
+
+		var bytes = [];
+
+		for (var i = 0; i < base64.length; i++) {
+			switch (i % 4) {
+				case 1:
+					bytes.push((base64map.indexOf(base64.charAt(i - 1)) << 2) |
+					           (base64map.indexOf(base64.charAt(i)) >>> 4));
+					break;
+				case 2:
+					bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & 0xF) << 4) |
+					           (base64map.indexOf(base64.charAt(i)) >>> 2));
+					break;
+				case 3:
+					bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & 0x3) << 6) |
+					           (base64map.indexOf(base64.charAt(i))));
+					break;
+			}
+		}
+
+		return bytes;
+
+	}
+
+};
+
+// Crypto mode namespace
+Crypto.mode = {};
+
+})();
+
+module.exports = Crypto;

+ 41 - 0
node_modules/zhouWei-request/js_sdk/request/upload/hmac.js

@@ -0,0 +1,41 @@
+/*!
+ * Crypto-JS v1.1.0
+ * http://code.google.com/p/crypto-js/
+ * Copyright (c) 2009, Jeff Mott. All rights reserved.
+ * http://code.google.com/p/crypto-js/wiki/License
+ */
+
+const Crypto = require('./crypto.js');
+
+(function(){
+
+// Shortcut
+var util = Crypto.util;
+
+Crypto.HMAC = function (hasher, message, key, options) {
+
+	// Allow arbitrary length keys
+	key = key.length > hasher._blocksize * 4 ?
+	      hasher(key, { asBytes: true }) :
+	      util.stringToBytes(key);
+
+	// XOR keys with pad constants
+	var okey = key,
+	    ikey = key.slice(0);
+	for (var i = 0; i < hasher._blocksize * 4; i++) {
+		okey[i] ^= 0x5C;
+		ikey[i] ^= 0x36;
+	}
+
+	var hmacbytes = hasher(util.bytesToString(okey) +
+	                       hasher(util.bytesToString(ikey) + message, { asString: true }),
+	                       { asBytes: true });
+	return options && options.asBytes ? hmacbytes :
+	       options && options.asString ? util.bytesToString(hmacbytes) :
+	       util.bytesToHex(hmacbytes);
+
+};
+
+})();
+
+module.exports = Crypto;

+ 169 - 0
node_modules/zhouWei-request/js_sdk/request/upload/qiniuUploader.js

@@ -0,0 +1,169 @@
+// created by gpake
+(function () {
+
+  var config = {
+    qiniuRegion: '',
+    qiniuImageURLPrefix: '',
+    qiniuUploadToken: '',
+    qiniuUploadTokenURL: '',
+    qiniuUploadTokenFunction: null,
+    qiniuShouldUseQiniuFileName: false
+  }
+
+  module.exports = {
+    init: init,
+    upload: upload,
+  }
+
+  // 在整个程序生命周期中,只需要 init 一次即可
+  // 如果需要变更参数,再调用 init 即可
+  function init(options) {
+    config = {
+      qiniuRegion: '',
+      qiniuImageURLPrefix: '',
+      qiniuUploadToken: '',
+      qiniuUploadTokenURL: '',
+      qiniuUploadTokenFunction: null,
+      qiniuShouldUseQiniuFileName: false
+    };
+    updateConfigWithOptions(options);
+  }
+
+  function updateConfigWithOptions(options) {
+    if (options.region) {
+      config.qiniuRegion = options.region;
+    } else {
+      console.error('qiniu uploader need your bucket region');
+    }
+    if (options.uptoken) {
+      config.qiniuUploadToken = options.uptoken;
+    } else if (options.uptokenURL) {
+      config.qiniuUploadTokenURL = options.uptokenURL;
+    } else if (options.uptokenFunc) {
+      config.qiniuUploadTokenFunction = options.uptokenFunc;
+    }
+    if (options.domain) {
+      config.qiniuImageURLPrefix = options.domain;
+    }
+    config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName
+  }
+
+  function upload(filePath, success, fail, options, progress, cancelTask) {
+    if (null == filePath) {
+      console.error('qiniu uploader need filePath to upload');
+      return;
+    }
+    if (options) {
+      updateConfigWithOptions(options);
+    }
+    if (config.qiniuUploadToken) {
+      doUpload(filePath, success, fail, options, progress, cancelTask);
+    } else if (config.qiniuUploadTokenURL) {
+      getQiniuToken(function () {
+        doUpload(filePath, success, fail, options, progress, cancelTask);
+      });
+    } else if (config.qiniuUploadTokenFunction) {
+      config.qiniuUploadToken = config.qiniuUploadTokenFunction();
+      if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
+        console.error('qiniu UploadTokenFunction result is null, please check the return value');
+        return
+      }
+      doUpload(filePath, success, fail, options, progress, cancelTask);
+    } else {
+      console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]');
+      return;
+    }
+  }
+
+  function doUpload(filePath, success, fail, options, progress, cancelTask) {
+    if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
+      console.error('qiniu UploadToken is null, please check the init config or networking');
+      return
+    }
+    var url = uploadURLFromRegionCode(config.qiniuRegion);
+    var fileName = filePath.split('//')[1];
+    if (options && options.key) {
+      fileName = options.key;
+    }
+    var formData = {
+      'token': config.qiniuUploadToken
+    };
+    if (!config.qiniuShouldUseQiniuFileName) {
+      formData['key'] = fileName
+    }
+    var uploadTask = wx.uploadFile({
+      url: url,
+      filePath: filePath,
+      name: 'file',
+      formData: formData,
+      success: function (res) {
+        var dataString = res.data
+        if (res.data.hasOwnProperty('type') && res.data.type === 'Buffer') {
+          dataString = String.fromCharCode.apply(null, res.data.data)
+        }
+        try {
+          var dataObject = JSON.parse(dataString);
+          //do something
+          var imageUrl = config.qiniuImageURLPrefix + '/' + dataObject.key;
+          dataObject.imageURL = imageUrl;
+          if (success) {
+            success(dataObject);
+          }
+        } catch (e) {
+          console.log('parse JSON failed, origin String is: ' + dataString)
+          if (fail) {
+            fail(e);
+          }
+        }
+      },
+      fail: function (error) {
+        console.error(error);
+        if (fail) {
+          fail(error);
+        }
+      }
+    })
+
+    uploadTask.onProgressUpdate((res) => {
+      progress && progress(res)
+    })
+
+    cancelTask && cancelTask(() => {
+      uploadTask.abort()
+    })
+  }
+
+  function getQiniuToken(callback) {
+    wx.request({
+      url: config.qiniuUploadTokenURL,
+      success: function (res) {
+        var token = res.data.uptoken;
+        if (token && token.length > 0) {
+          config.qiniuUploadToken = token;
+          if (callback) {
+            callback();
+          }
+        } else {
+          console.error('qiniuUploader cannot get your token, please check the uptokenURL or server')
+        }
+      },
+      fail: function (error) {
+        console.error('qiniu UploadToken is null, please check the init config or networking: ' + error);
+      }
+    })
+  }
+
+  function uploadURLFromRegionCode(code) {
+    var uploadURL = null;
+    switch (code) {
+      case 'ECN': uploadURL = 'https://up.qbox.me'; break;
+      case 'NCN': uploadURL = 'https://up-z1.qbox.me'; break;
+      case 'SCN': uploadURL = 'https://up-z2.qbox.me'; break;
+      case 'NA': uploadURL = 'https://up-na0.qbox.me'; break;
+      case 'ASG': uploadURL = 'https://up-as0.qbox.me'; break;
+      default: console.error('please make the region is with one of [ECN, SCN, NCN, NA, ASG]');
+    }
+    return uploadURL;
+  }
+
+})();

+ 86 - 0
node_modules/zhouWei-request/js_sdk/request/upload/sha1.js

@@ -0,0 +1,86 @@
+/*!
+ * Crypto-JS v1.1.0
+ * http://code.google.com/p/crypto-js/
+ * Copyright (c) 2009, Jeff Mott. All rights reserved.
+ * http://code.google.com/p/crypto-js/wiki/License
+ */
+
+const Crypto = require('./crypto.js');
+
+(function(){
+
+// Shortcut
+var util = Crypto.util;
+
+// Public API
+var SHA1 = Crypto.SHA1 = function (message, options) {
+	var digestbytes = util.wordsToBytes(SHA1._sha1(message));
+	return options && options.asBytes ? digestbytes :
+	       options && options.asString ? util.bytesToString(digestbytes) :
+	       util.bytesToHex(digestbytes);
+};
+
+// The core
+SHA1._sha1 = function (message) {
+
+	var m  = util.stringToWords(message),
+	    l  = message.length * 8,
+	    w  =  [],
+	    H0 =  1732584193,
+	    H1 = -271733879,
+	    H2 = -1732584194,
+	    H3 =  271733878,
+	    H4 = -1009589776;
+
+	// Padding
+	m[l >> 5] |= 0x80 << (24 - l % 32);
+	m[((l + 64 >>> 9) << 4) + 15] = l;
+
+	for (var i = 0; i < m.length; i += 16) {
+
+		var a = H0,
+		    b = H1,
+		    c = H2,
+		    d = H3,
+		    e = H4;
+
+		for (var j = 0; j < 80; j++) {
+
+			if (j < 16) w[j] = m[i + j];
+			else {
+				var n = w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16];
+				w[j] = (n << 1) | (n >>> 31);
+			}
+
+			var t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (
+			         j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :
+			         j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :
+			         j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :
+			                  (H1 ^ H2 ^ H3) - 899497514);
+
+			H4 =  H3;
+			H3 =  H2;
+			H2 = (H1 << 30) | (H1 >>> 2);
+			H1 =  H0;
+			H0 =  t;
+
+		}
+
+		H0 += a;
+		H1 += b;
+		H2 += c;
+		H3 += d;
+		H4 += e;
+
+	}
+
+	return [H0, H1, H2, H3, H4];
+
+};
+
+// Package private blocksize
+SHA1._blocksize = 16;
+
+})();
+
+module.exports = Crypto;

+ 287 - 0
node_modules/zhouWei-request/js_sdk/request/upload/upload.js

@@ -0,0 +1,287 @@
+import request from "./../core/request.js";
+const {
+	chooseImage,
+	chooseVideo,
+	qiniuUpload,
+	aliUpload,
+	urlUpload
+} = require("./utils");
+import {
+	mergeConfig
+} from "./../core/utils.js";
+export default class fileUpload extends request {
+	constructor(props) {
+		// 调用实现父类的构造函数
+		super(props);
+	}
+	//七牛云上传图片
+	async qnImgUpload(options = {}) {
+		let files;
+		try {
+			files = await chooseImage(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (files) {
+			return this.qnFileUpload({
+				...options,
+				files: files
+			});
+		}
+	}
+	//七牛云上传视频
+	async qnVideoUpload(options = {}) {
+		let files;
+		try {
+			files = await chooseVideo(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (files) {
+			return this.qnFileUpload({
+				...options,
+				files: files
+			});
+		}
+	}
+
+	//七牛云文件上传(支持多张上传)
+	async qnFileUpload(options = {}) {
+		let requestInfo;
+		try {
+			// 数据合并
+			requestInfo = {
+				...this.config,
+				...options,
+				header: {},
+				method: "FILE"
+			};
+			//请求前回调
+			if (this.requestStart) {
+				let requestStart = this.requestStart(requestInfo);
+				if (typeof requestStart == "object") {
+					let changekeys = ["load", "files"];
+					changekeys.forEach(key => {
+						requestInfo[key] = requestStart[key];
+					});
+				} else {
+					throw {
+						errMsg: "【request】请求开始拦截器未通过",
+						statusCode: 0,
+						data: requestInfo.data,
+						method: requestInfo.method,
+						header: requestInfo.header,
+						url: requestInfo.url,
+					}
+				}
+			}
+			let requestResult = await qiniuUpload(requestInfo, this.getQnToken);
+			return Promise.resolve(requestResult);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		} finally {
+			this.requestEnd && this.requestEnd(requestInfo);
+		}
+	}
+	//阿里云上传图片
+	async aliImgUpload(options = {}) {
+		let files;
+		try {
+			files = await chooseImage(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (files) {
+			return this.aliFileUpload({
+				...options,
+				files: files
+			});
+		}
+	}
+	//阿里云上传视频
+	async aliVideoUpload(options = {}) {
+		let files;
+		try {
+			files = await chooseVideo(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (files) {
+			return this.aliFileUpload({
+				...options,
+				files: files
+			});
+		}
+	}
+	//阿里云文件上传(支持多张上传)
+	async aliFileUpload(options = {}) {
+		let requestInfo;
+		try {
+			// 数据合并
+			requestInfo = {
+				...this.config,
+				...options,
+				header: {},
+				method: "FILE"
+			};
+			//请求前回调
+			if (this.requestStart) {
+				let requestStart = this.requestStart(requestInfo);
+				if (typeof requestStart == "object") {
+					let changekeys = ["load", "files"];
+					changekeys.forEach(key => {
+						requestInfo[key] = requestStart[key];
+					});
+				} else {
+					throw {
+						errMsg: "【request】请求开始拦截器未通过",
+						statusCode: 0,
+						data: requestInfo.data,
+						method: requestInfo.method,
+						header: requestInfo.header,
+						url: requestInfo.url,
+					}
+				}
+			}
+			let requestResult = await aliUpload(requestInfo, this.getAliToken);
+			return Promise.resolve(requestResult);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		} finally {
+			this.requestEnd && this.requestEnd(requestInfo);
+		}
+	}
+	//本地服务器图片上传
+	async urlImgUpload() {
+		let options = {};
+		if (arguments[0]) {
+			if (typeof(arguments[0]) == "string") {
+				options.url = arguments[0];
+			} else if (typeof(arguments[0]) == "object") {
+				options = Object.assign(options, arguments[0]);
+			}
+		}
+		if (arguments[1] && typeof(arguments[1]) == "object") {
+			options = Object.assign(options, arguments[1]);
+		}
+		try {
+			options.files = await chooseImage(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(options.files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (options.files) {
+			return this.urlFileUpload(options);
+		}
+	}
+	//本地服务器上传视频
+	async urlVideoUpload() {
+		let options = {};
+		if (arguments[0]) {
+			if (typeof(arguments[0]) == "string") {
+				options.url = arguments[0];
+			} else if (typeof(arguments[0]) == "object") {
+				options = Object.assign(options, arguments[0]);
+			}
+		}
+		if (arguments[1] && typeof(arguments[1]) == "object") {
+			options = Object.assign(options, arguments[1]);
+		}
+		try {
+			options.files = await chooseVideo(options);
+			// 选择完成回调
+			options.onSelectComplete && options.onSelectComplete(options.files);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		}
+		if (options.files) {
+			return this.urlFileUpload(options);
+		}
+	}
+	//本地服务器文件上传方法
+	async urlFileUpload() {
+		let requestInfo = {
+			method: "FILE"
+		};
+		if (arguments[0]) {
+			if (typeof(arguments[0]) == "string") {
+				requestInfo.url = arguments[0];
+			} else if (typeof(arguments[0]) == "object") {
+				requestInfo = Object.assign(requestInfo, arguments[0]);
+			}
+		}
+		if (arguments[1] && typeof(arguments[1]) == "object") {
+			requestInfo = Object.assign(requestInfo, arguments[1]);
+		}
+		if (!requestInfo.url && this.defaultUploadUrl) {
+			requestInfo.url = this.defaultUploadUrl;
+		}
+		if (!requestInfo.name && this.defaultFileName) {
+			requestInfo.name = this.defaultFileName;
+		}
+		// 请求数据
+		// 是否运行过请求开始钩子
+		let runRequestStart = false;
+		try {
+			if (!requestInfo.url) {
+				throw {
+					errMsg: "【request】文件上传缺失数据url",
+					statusCode: 0,
+					data: requestInfo.data,
+					method: requestInfo.method,
+					header: requestInfo.header,
+					url: requestInfo.url,
+				}
+			}
+			// 数据合并
+			requestInfo = mergeConfig(this, requestInfo);
+			// 代表之前运行到这里
+			runRequestStart = true;
+			//请求前回调
+			if (this.requestStart) {
+				let requestStart = this.requestStart(requestInfo);
+				if (typeof requestStart == "object") {
+					let changekeys = ["data", "header", "isPrompt", "load", "isFactory", "files"];
+					changekeys.forEach(key => {
+						requestInfo[key] = requestStart[key];
+					});
+				} else {
+					throw {
+						errMsg: "【request】请求开始拦截器未通过",
+						statusCode: 0,
+						data: requestInfo.data,
+						method: requestInfo.method,
+						header: requestInfo.header,
+						url: requestInfo.url,
+					}
+				}
+			}
+			let requestResult = await urlUpload(requestInfo, this.dataFactory);
+			return Promise.resolve(requestResult);
+		} catch (err) {
+			this.requestError && this.requestError(err);
+			return Promise.reject(err);
+		} finally {
+			if (runRequestStart) {
+				this.requestEnd && this.requestEnd(requestInfo);
+			}
+		}
+	}
+}

+ 396 - 0
node_modules/zhouWei-request/js_sdk/request/upload/utils.js

@@ -0,0 +1,396 @@
+const qiniuUploader = require("./qiniuUploader");
+const aliUploader =  require('./aliUploader');  
+//七牛云上传文件命名
+export const randomChar = function(l, url = "") {
+	const x = "0123456789qwertyuioplkjhgfdsazxcvbnm";
+	let tmp = "";
+	let time = new Date();
+	for (let i = 0; i < l; i++) {
+		tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length);
+	}
+	return (
+		"file/" +
+		url +
+		time.getTime() +
+		tmp
+	);
+}
+//图片选择
+export const chooseImage = function(data) {
+	return new Promise((resolve, reject) => {
+		uni.chooseImage({
+			count: data.count || 9, //默认9
+			sizeType: data.sizeType || ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+			sourceType: data.sourceType || ['album', 'camera'], //从相册选择
+			success: function(res) {
+				for (var i = 0; i < res.tempFiles.length; i++) {
+					res.tempFiles[i].fileType = "image"
+				}
+				resolve(res.tempFiles);
+			},
+			fail: err => {
+				reject({
+					errMsg: err.errMsg, 
+					errCode: err.errCode, 
+					statusCode: 0,
+				});
+			}
+		});
+	});
+}
+//视频选择
+export const chooseVideo = function(data) {
+	return new Promise((resolve, reject) => {
+		uni.chooseVideo({
+			sourceType: data.sourceType || ['album', 'camera'], //从相册选择
+			compressed: data.compressed || false, //是否压缩所选的视频源文件,默认值为 true,需要压缩。
+			maxDuration: data.maxDuration || 60, //拍摄视频最长拍摄时间,单位秒。最长支持 60 秒。
+			camera: data.camera || 'back', //'front'、'back',默认'back'
+			success: function(res) {
+				let files = [{
+					path: res.tempFilePath,
+					fileType: "video"
+				}];
+				// #ifdef APP-PLUS || H5 || MP-WEIXIN
+				files[0].duration = res.duration;
+				files[0].size = res.size;
+				files[0].height = res.height;
+				files[0].width = res.width;
+				// #endif
+				// #ifdef H5
+				files[0].name = res.name;
+				// #endif
+				resolve(files);
+			},
+			fail: err => {
+				reject({
+					errMsg: err.errMsg, 
+					errCode: err.errCode, 
+					statusCode: 0,
+				});
+			}
+		});
+	});
+}
+// 七牛云上传
+export const qiniuUpload = function(requestInfo, getQnToken) {
+	return new Promise((resolve, reject) => {
+		if (Array.isArray(requestInfo.files)) {
+			let len = requestInfo.files.length;
+			let fileList = new Array;
+			if (getQnToken) {
+				getQnToken(qnRes => {
+					/*
+					 *接口返回参数:
+					 *visitPrefix:访问文件的域名
+					 *token:七牛云上传token
+					 *folderPath:上传的文件夹
+					 *region: 地区 默认为:SCN
+					 */
+                    let prefixLen = qnRes.visitPrefix.length;
+                    if(qnRes.visitPrefix.charAt(prefixLen - 1) == '/'){
+                        qnRes.visitPrefix = qnRes.visitPrefix.substring(0, prefixLen - 1)
+                    }
+					uploadFile(0);
+
+					function uploadFile(i) {
+						let item = requestInfo.files[i];
+						let updateUrl = randomChar(10, qnRes.folderPath);
+						let fileData = {
+							fileIndex: i,
+							files: requestInfo.files,
+							...item
+						};
+						if (item.name) {
+							fileData.name = item.name;
+							let nameArr = item.name.split(".");
+							updateUrl += "." + nameArr[nameArr.length - 1];
+						}
+						// 交给七牛上传
+						qiniuUploader.upload(item.path || item, (res) => {
+							fileData.url = res.imageURL;
+							requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+								url: res.imageURL,
+								...fileData
+							});
+							fileList.push(res.imageURL);
+							if (len - 1 > i) {
+								uploadFile(i + 1);
+							} else {
+								resolve(fileList);
+							}
+						}, (error) => {
+							reject(error);
+						}, {
+							region: qnRes.region || 'SCN', //地区
+							domain: qnRes.visitPrefix, // bucket 域名,下载资源时用到。
+							key: updateUrl,
+							uptoken: qnRes.token, // 由其他程序生成七牛 uptoken
+							uptokenURL: 'UpTokenURL.com/uptoken' // 上传地址
+						}, (res) => {
+							console.log(requestInfo);
+							requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res));
+							// console.log('上传进度', res.progress)
+							// console.log('已经上传的数据长度', res.totalBytesSent)
+							// console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend)
+						});
+					}
+				});
+			} else {
+				reject({
+					errMsg: "请添加七牛云回调方法:getQnToken",
+					statusCode: 0
+				});
+			}
+		} else {
+			reject({
+				errMsg: "files 必须是数组类型",
+				statusCode: 0
+			});
+		};
+	});
+}
+// 阿里云oss上传
+export const aliUpload = function(requestInfo, getAliToken) {
+	return new Promise((resolve, reject) => {
+		if (Array.isArray(requestInfo.files)) {
+			let len = requestInfo.files.length;
+			let fileList = new Array;
+			if (getAliToken) {
+				getAliToken(aliRes => {
+					/*
+					 *接口返回参数:
+					 *visitPrefix:访问文件的域名
+					 *folderPath:上传的文件夹
+					 *accessKeyId: 您的oss的访问ID
+					 *accessKeySecret: 您的oss的访问密钥
+					 * timeout: 签名过期时间(毫秒)
+					 */
+					let aliyunOssKey = aliUploader({
+						accessKeyId: aliRes.accessKeyId,
+						accessKeySecret: aliRes.accessKeySecret,
+						timeout: aliRes.timeout
+					});
+                    let prefixLen = aliRes.visitPrefix.length;
+                    if(aliRes.visitPrefix.charAt(prefixLen - 1) == '/'){
+                        aliRes.visitPrefix = aliRes.visitPrefix.substring(0, prefixLen - 1)
+                    }
+					uploadFile(0);
+
+					function uploadFile(i) {
+						let item = requestInfo.files[i];
+						let updateUrl = randomChar(10, aliRes.folderPath);
+						let fileData = {
+							fileIndex: i,
+							files: requestInfo.files,
+							...item
+						};
+						if (item.name) {
+							fileData.name = item.name;
+							let nameArr = item.name.split(".");
+							updateUrl += "." + nameArr[nameArr.length - 1];
+						}
+						if (item.path) {
+							let nameArr = item.path.split(".");
+							updateUrl += "." + nameArr[nameArr.length - 1];
+						}
+						console.log("----------111", {
+						  url: aliRes.visitPrefix, // 开发者服务器的URL。
+						  filePath: item.path,
+						  name: 'file', // 必须填file。
+						  formData: {
+						    key: updateUrl,
+						    policy: aliyunOssKey.policy,
+						    OSSAccessKeyId: aliyunOssKey.accessKeyId,
+						    signature: aliyunOssKey.signature,
+						  }});
+						uni.uploadFile({
+						  url: aliRes.visitPrefix, // 开发者服务器的URL。
+						  filePath: item.path,
+						  name: 'file', // 必须填file。
+						  formData: {
+						    key: updateUrl,
+						    policy: aliyunOssKey.policy,
+						    OSSAccessKeyId: aliyunOssKey.accessKeyId,
+						    signature: aliyunOssKey.signature,
+						  },
+						  success: (res) => {
+						    if (res.statusCode === 204) {
+								fileData.url = aliRes.visitPrefix + "/" + updateUrl;
+								requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+									url: fileData.url,
+									...fileData
+								});
+								fileList.push(fileData.url);
+								if (len - 1 > i) {
+									uploadFile(i + 1);
+								} else {
+									resolve(fileList);
+								}
+						    } else {
+								console.log("----失败", res);
+								reject(res);
+							}
+						  },
+						  fail: err => {
+							  console.log("----失败", err);
+						    reject(err);
+						  }
+						});
+					}
+				});
+			} else {
+				reject({
+					errMsg: "请添加阿里云回调方法:getAliToken",
+					statusCode: 0
+				});
+			}
+		} else {
+			reject({
+				errMsg: "files 必须是数组类型",
+				statusCode: 0
+			});
+		};
+	});
+}
+// 服务器URL上传
+export const urlUpload = function(requestInfo, dataFactory) {
+	return new Promise((resolve, reject) => {
+		// 本地文件上传去掉默认Content-Type
+		if (requestInfo.header['Content-Type']) {
+			delete requestInfo.header['Content-Type'];
+		}
+		// 本地文件上传去掉默认Content-Type
+		if (requestInfo.header['content-type']) {
+			delete requestInfo.header['content-type'];
+		}
+		if (Array.isArray(requestInfo.files)) {
+			// #ifdef APP-PLUS || H5
+			let files = [];
+			let fileData = {
+				files: requestInfo.files,
+				name: requestInfo.name || "file"
+			};
+			requestInfo.files.forEach(item => {
+                let fileInfo = {
+                    name: requestInfo.name || "file",
+                };
+                if(item.path){
+                    fileInfo.uri = item.path;
+                } else {
+                    fileInfo.file = item;
+                }
+				files.push(fileInfo);
+			});
+			let config = {
+				url: requestInfo.url,
+				files: files,
+				header: requestInfo.header, //加入请求头
+				success: (response) => {
+					//是否用外部的数据处理方法
+					if (requestInfo.isFactory && dataFactory) {
+						//数据处理
+						dataFactory({
+							...requestInfo,
+							response: response,
+						}).then(data => {
+							requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+								data: data,
+								...fileData
+							});
+							resolve(data);
+						},err => {
+							reject(err);
+						});
+					} else {
+						requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+							data: response,
+							...fileData
+						});
+						resolve(response);
+					}
+				},
+				fail: (err) => {
+					reject(err);
+				}
+			};
+			if (requestInfo.data) {
+				config.formData = requestInfo.data;
+			}
+			const uploadTask = uni.uploadFile(config);
+			uploadTask.onProgressUpdate(res => {
+				requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res));
+			});
+			// #endif
+			// #ifdef MP
+			const len = requestInfo.files.length - 1;
+			let fileList = new Array;
+			fileUpload(0);
+
+			function fileUpload(i) {
+				let item = requestInfo.files[i];
+				let fileData = {
+					fileIndex: i,
+					files: requestInfo.files,
+					...item
+				};
+				let config = {
+					url: requestInfo.url,
+					filePath: item.path,
+					header: requestInfo.header, //加入请求头
+					name: requestInfo.name || "file",
+					success: (response) => {
+						//是否用外部的数据处理方法
+						if (requestInfo.isFactory && dataFactory) {
+							//数据处理
+							dataFactory({
+								...requestInfo,
+								response: response,
+							}).then(data => {
+								fileList.push(data);
+								requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+									data: data,
+									...fileData
+								});
+								if (len <= i) {
+									resolve(fileList);
+								} else {
+									fileUpload(i + 1);
+								}
+							},err => {
+								reject(err);
+							});
+						} else {
+							requestInfo.onEachUpdate && requestInfo.onEachUpdate({
+								data: response,
+								...fileData
+							});
+							fileList.push(response);
+							if (len <= i) {
+								resolve(fileList);
+							} else {
+								fileUpload(i + 1);
+							}
+						}
+					},
+					fail: (err) => {
+						reject(err);
+					}
+				};
+				if (requestInfo.data) {
+					config.formData = requestInfo.data;
+				}
+				const uploadTask = uni.uploadFile(config);
+				uploadTask.onProgressUpdate(res => {
+					requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res));
+				});
+			}
+			// #endif
+		} else {
+			reject({
+				errMsg: "files 必须是数组类型",
+				statusCode: 0
+			});
+		}
+	});
+}

+ 214 - 0
node_modules/zhouWei-request/js_sdk/requestConfig.js

@@ -0,0 +1,214 @@
+import request from "./request";
+// 全局配置的请求域名
+let baseUrl = "http://www.xxx.com/api/";
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//接口请求地址
+	baseUrl: baseUrl,
+	//服务器本地上传文件地址
+	fileUrl: baseUrl,
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+	//设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致)
+	header: {
+		'content-type': 'application/json;charset=UTF-8'
+	},
+	// 请求超时时间(默认6000)
+	timeout: 6000,
+	// 默认配置(可不写)
+	config: {
+		// 是否自动提示错误
+		isPrompt: true,
+		// 是否显示加载动画
+		load: true,
+		// 是否使用数据工厂
+		isFactory: true
+	}
+});
+
+// 添加获取七牛云token的方法
+$http.getQnToken = function(callback){
+	//该地址需要开发者自行配置(每个后台的接口风格都不一样)
+	$http.get("api/kemean/aid/qn_upload").then(data => {
+		/*
+		 *接口返回参数:
+		 *visitPrefix:访问文件的域名
+		 *token:七牛云上传token
+		 *folderPath:上传的文件夹
+		 *region: 地区 默认为:SCN
+		 */
+		callback({
+			visitPrefix: data.visitPrefix,
+			token: data.token,
+			folderPath: data.folderPath,
+			region: "SCN"
+		});
+	});
+}
+// 添加获取阿里云token的方法
+$http.getAliToken = function(callback){
+	//该地址需要开发者自行配置(每个后台的接口风格都不一样)
+	$http.get("api/open/v1/ali_oss_upload").then(data => {
+		/*
+		 *接口返回参数:
+		 *visitPrefix: 访问文件的域名
+		 *folderPath: 上传的文件夹
+		 *region: 地区 
+		 *bucket: 阿里云的 bucket
+		 *accessKeyId: 阿里云的访问ID
+		 *accessKeySecret: 阿里云的访问密钥
+		 *stsToken: 阿里云的访问token
+		 */
+		callback({
+			accessKeyId: data.accessKeyId,
+			accessKeySecret: data.accessKeySecret,
+			bucket: data.bucket,
+			region: data.region,
+			visitPrefix: data.visitPrefix,
+			token: data.token,
+			folderPath: data.folderPath,
+			stsToken: data.securityToken,
+		});
+	});
+}
+//当前接口请求数
+let requestNum = 0;
+//请求开始拦截器
+$http.requestStart = function(options) {
+	if (options.load) {
+		if (requestNum <= 0) {
+			//打开加载动画
+			uni.showLoading({
+				title: '加载中',
+				mask: true
+			});
+		}
+		requestNum += 1;
+	}
+	// 图片、视频上传大小限制
+	if (options.method == "FILE") {
+		// 文件最大字节: options.maxSize 可以在调用方法的时候加入参数
+		let maxSize = options.maxSize || '';
+		for (let item of options.files) {
+			if(item.fileType == 'image'){
+				if (maxSize && item.size > maxSize) {
+					setTimeout(() => {
+						uni.showToast({
+							title: "图片过大,请重新上传",
+							icon: "none"
+						});
+					}, 500);
+					return false;
+				}
+			} else if(item.fileType == "video"){
+				if (item.duration < 3) {
+					setTimeout(() => {
+						uni.showToast({
+							title: "视频长度不足3秒,请重新上传",
+							icon: "none"
+						});
+					}, 500);
+					return false;
+				}
+			}
+		}
+	}
+	//请求前加入token
+	options.header['token'] = "你的项目登录token";
+	return options; // return false 表示请求拦截,不会继续请求
+}
+//请求结束
+$http.requestEnd = function(options) {
+	//判断当前接口是否需要加载动画
+	if (options.load) {
+		requestNum = requestNum - 1;
+		if (requestNum <= 0) {
+			uni.hideLoading();
+		}
+	}
+}
+//登录弹窗次数
+let loginPopupNum = 0;
+//所有接口数据处理(可在接口里设置不调用此方法)
+//此方法需要开发者根据各自的接口返回类型修改,以下只是模板
+$http.dataFactory = async function(res) {
+	console.log("接口请求数据", {
+		url: res.url,
+		resolve: res.response,
+		header: res.header,
+		data: res.data,
+		method: res.method,
+	});
+	if (res.response.statusCode && res.response.statusCode == 200) {
+		let httpData = res.response.data;
+		if (typeof (httpData) == "string") {
+			httpData = JSON.parse(httpData);
+		}
+		/*********以下只是模板(及共参考),需要开发者根据各自的接口返回类型修改*********/
+
+		//判断数据是否请求成功
+		if (httpData.success || httpData.code == 200) {
+			// 返回正确的结果(then接受数据)
+			return Promise.resolve(httpData.data);
+		} else if (httpData.code == "1000" || httpData.code == "1001" || httpData.code == 1100) {
+			let content = '此时此刻需要您登录喔~';
+			if (loginPopupNum <= 0) {
+				loginPopupNum++;
+				uni.showModal({
+					title: '温馨提示',
+					content: content,
+					confirmText: "去登录",
+					cancelText: "再逛会",
+					success: function (res) {
+						loginPopupNum--;
+						if (res.confirm) {
+							uni.navigateTo({
+								url: "/pages/user/login"
+							});
+						}
+					}
+				});
+			}
+			// 返回错误的结果(catch接受数据)
+			return Promise.reject({
+				statusCode: 0,
+				errMsg: "【request】" + (httpData.info || httpData.msg)
+			});
+		} else { //其他错误提示
+			if (res.isPrompt) {
+				uni.showToast({
+					title: httpData.info || httpData.msg,
+					icon: "none",
+					duration: 3000
+				});
+			}
+			// 返回错误的结果(catch接受数据)
+			return Promise.reject({
+				statusCode: 0,
+				errMsg: "【request】" + (httpData.info || httpData.msg)
+			});
+		}
+
+		/*********以上只是模板(及共参考),需要开发者根据各自的接口返回类型修改*********/
+
+	} else {
+		// 返回错误的结果(catch接受数据)
+		return Promise.reject({
+			statusCode: res.response.statusCode,
+			errMsg: "【request】数据工厂验证不通过"
+		});
+	}
+};
+// 错误回调
+$http.requestError = function (e) {
+	// e.statusCode === 0 是参数效验错误抛出的
+	if (e.statusCode === 0) {
+		throw e;
+	} else {
+		uni.showToast({
+			title: "网络错误,请检查一下网络",
+			icon: "none"
+		});
+	}
+}
+export default $http;

+ 80 - 0
node_modules/zhouWei-request/package.json

@@ -0,0 +1,80 @@
+{
+  "id": "zhouWei-request",
+  "displayName": "request请求、配置简单、批量上传图片、视频、超强适应性(支持多域名请求)",
+  "version": "3.3.2",
+  "description": "适用于一项目多域名请求、七牛云图片上传、阿里云图片上传、本地服务器图片上传、支持 Promise",
+  "keywords": [
+    "request",
+    "请求",
+    "http",
+    "ajax",
+    "上传"
+],
+  "repository": "https://github.com/zhouwei1994/uni-app-demo",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+  "dcloudext": {
+    "category": [
+        "JS SDK",
+        "通用 SDK"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": "465081029"
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": ""
+  },
+  "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"
+        }
+      }
+    }
+  }
+}

+ 508 - 0
node_modules/zhouWei-request/readme.md

@@ -0,0 +1,508 @@
+# request请求、配置简单、批量上传图片、视频、超强适应性(支持多域名请求)
+1. 配置简单、源码清晰注释多、适用于一项目多域名请求、第三方请求、七牛云图片上传、本地服务器图片上传等等
+2. 支持请求`get`、`post`、`put`、`delete`
+3. 自动显示请求加载动画(可单个接口关闭)
+4. 全局`api`数据处理函数,只回调请求正确的数据(可单个接口关闭)
+5. 未登录或登录失效自动拦截并调用登录方法(可单个接口关闭)
+6. 全局自动提示接口抛出的错误信息(可单个接口关闭)
+7. 支持 Promise
+8. 支持拦截器
+9. 支持七牛云文件(图片、视频)批量上传
+10. 支持本地服务器文件(图片、视频)批量上传
+11. 支持上传文件拦截过滤
+12. 支持上传文件进度监听
+13. 支持上传文件单张成功回调
+
+| `QQ交流群(607391225)`         | `微信交流群(加我好友备注"进群")`                  |
+| ----------------------------|--------------------------- |
+|![QQ交流群](http://qn.kemean.cn//upload/202004/14/15868301778472k7oubi6.png)|![微信交流群](https://qn.kemean.cn/upload/202010/13/weiXin_group_code.jpg)|
+| QQ群号:607391225 |微信号:zhou0612wei|
+
+### [点击跳转-插件示例](https://ext.dcloud.net.cn/plugin?id=2009)
+### [点击跳转-5年的web前端开源的uni-app快速开发模板-下载看文档](https://ext.dcloud.net.cn/plugin?id=2009)
+
+### 常见问题
+1.接口请求成功了,没有返回数据或者数据是走的catch回调
+
+答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改`
+
+2.官方的方法有数据,本插件方法请求报错跨域问题
+
+答:`requestConfig.js` 请求配置文件里面,`header`请求头设置的`content-type`请求类型需求和后台保持一致
+
+3.登录后用户`token`怎么设置?
+
+答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置
+
+4.怎么判断上传的文件(图片)太大?怎么过滤掉太大的文件(图片)?
+
+答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置
+
+5.接口请求成功了,一直提示“网络错误,请检查一下网络”?
+
+答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改`
+
+### 本次更新注意事项
+1. 所有的headers都改成了header(和官方统一)
+2. 七牛云的获取token等信息提取到了`requestConfig.js`文件,参考如下
+
+### 文件说明
+1. `request => core` 请求方法的目录
+2. `request => core => request.js` 请求方法的class文件
+3. `request => core => utils.js` 请求方法的源码文件
+4. `request => upload` 上传方法的目录
+5. `request => upload => upload.js` 上传方法的class文件
+6. `request => upload => utils.js` 上传方法源码文件
+7. `request => upload => qiniuUploader.js` 七牛云官方上传文件
+8. `request => index.js` 输出方法的文件
+9. `requestConfig.js` 请求配置文件(具体看代码)
+
+### 在main.js引入并挂在Vue上
+```
+import $http from '@/uni_modules/zhouWei-request/js_sdk/requestConfig';
+Vue.prototype.$http = $http;
+```
+
+### `requestConfig.js`配置说明(requestConfig.js有配置示例)
+```
+import request from "@/uni_modules/zhouWei-request/js_sdk/request";
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//接口请求地址
+	baseUrl: "https://twin-ui.com/", //示例域名,请自行设计
+	//服务器本地上传文件地址
+	fileUrl: "https://twin-ui.com/", //示例域名,请自行设计
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+	//设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致)
+	header: {
+		'Content-Type': 'application/json;charset=UTF-8'
+	},
+    // 请求超时时间(默认6000)
+    timeout: 6000,
+    // 默认配置(可不写)
+    config: {
+        // 是否自动提示错误
+        isPrompt: true,
+        // 是否显示加载动画
+        load: true,
+        // 是否使用数据工厂
+        isFactory: true,
+       // ... 可写更多配置
+    }
+});
+
+// 添加获取七牛云token的方法
+$http.getQnToken = function(callback){
+	//该地址需要开发者自行配置(每个后台的接口风格都不一样)
+	$http.get("api/common/v1/qn_upload").then(data => {
+		/*
+		 *接口返回参数:
+		 *visitPrefix:访问文件的域名
+		 *token:七牛云上传token
+		 *folderPath:上传的文件夹
+		 *region: 地区 默认为:SCN
+		 */
+		callback({
+			visitPrefix: data.visitPrefix,
+			token: data.token,
+			folderPath: data.folderPath
+		});
+	});
+}
+//当前接口请求数
+let requestNum = 0;
+//请求开始拦截器
+$http.requestStart = function(options) {
+    if (options.load) {
+    	if (requestNum <= 0) {
+            //打开加载动画
+            uni.showLoading({
+                title: '加载中',
+                mask: true
+            });
+        }
+        requestNum += 1;
+    }
+    // 图片上传大小限制
+    if (options.method == "FILE" && options.maxSize) {
+    	// 文件最大字节: options.maxSize 可以在调用方法的时候加入参数
+    	let maxSize = options.maxSize;
+    	for (let item of options.files) {
+    		if (item.size > maxSize) {
+    			setTimeout(() => {
+    				uni.showToast({
+    					title: "图片过大,请重新上传",
+    					icon: "none"
+    				});
+    			}, 500);
+    			return false;
+    		}
+    	}
+    }
+    //请求前加入token
+    options.header['token'] = "你的项目token";
+    return options; // return false 表示请求拦截,不会继续请求
+}
+//请求结束
+$http.requestEnd = function(options) {
+	//判断当前接口是否需要加载动画
+	if (options.load) {
+		requestNum = requestNum - 1;
+		if (requestNum <= 0) {
+			uni.hideLoading();
+		}
+	}
+}
+//所有接口数据处理(可在接口里设置不调用此方法)
+//此方法需要开发者根据各自的接口返回类型修改,以下只是模板
+$http.dataFactory = async function(res) {
+    console.log("接口请求数据", {
+        url: res.url,
+        resolve: res.response,
+        header: res.header,
+        data: res.data,
+        method: res.method,
+    });
+    if (res.response.statusCode && res.response.statusCode == 200) {
+        let httpData = res.response.data;
+        if (typeof (httpData) == "string") {
+            httpData = JSON.parse(httpData);
+        }
+        // 开始----------------------以下是示例-请认真阅读代码-----------------------开始
+        //判断数据是否请求成功
+        if (httpData.success || httpData.code == 200) {  // 重点------判断接口请求是否成功,成功就返回成功的数据
+            // ---重点---返回正确的结果(then接受数据)---重点---
+            return Promise.resolve(httpData);
+        } else {
+            //其他错误提示
+            if (res.isPrompt) { // 是否提示
+                uni.showToast({
+                    title: httpData.info || httpData.msg, // 重点------把接口返回的错误抛出显示
+                    icon: "none",
+                    duration: 3000
+                });
+            }
+            // ---重点---返回错误的结果(catch接受数据)----重点---
+            return Promise.reject({
+                statusCode: 0,
+                errMsg: "【request】" + (httpData.info || httpData.msg)
+            });
+        }
+        // 结束----------------------以上是示例-请认真阅读代码-----------------------结束
+    } else {
+		// 返回错误的结果(catch接受数据)
+		return Promise.reject({
+			statusCode: res.response.statusCode,
+			errMsg: "【request】数据工厂验证不通过"
+		});
+	}
+};
+// 错误回调(所有错误都在这里)
+$http.requestError = function (e) {
+	if (e.statusCode === 0) {
+		throw e;
+	} else {
+		uni.showToast({
+			title: "网络错误,请检查一下网络",
+			icon: "none"
+		});
+	}
+}
+```
+
+### 通用请求方法
+```
+this.$http.request({
+	url: 'aid/region',
+	method: "GET", // POST、GET、PUT、DELETE、JSONP,具体说明查看官方文档
+	data: {pid:0},
+	timeout: 30000,  // 默认 30000 说明:超时时间,单位 ms,具体说明查看官方文档
+	dataType: "json",  // 默认 json 说明:如果设为 json,会尝试对返回的数据做一次 JSON.parse,具体说明查看官方文档
+	responseType: "text",  // 默认 text 说明:设置响应的数据类型。合法值:text、arraybuffer,具体说明查看官方文档
+	withCredentials: false,  // 默认 false 说明:跨域请求时是否携带凭证(cookies),具体说明查看官方文档
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用)
+}).then(function (response) {
+	//这里只会在接口是成功状态返回
+}).catch(function (error) {
+	//这里只会在接口是失败状态返回,不需要去处理错误提示
+	console.log(error);
+});
+```
+
+### get请求 正常写法 
+```
+this.$http.get('aid/region',{pid:0}).
+then(function (response) {
+	//这里只会在接口是成功状态返回
+}).catch(function (error) {
+	//这里只会在接口是失败状态返回,不需要去处理错误提示
+	console.log(error);
+});
+```
+
+### post请求 async写法 
+```
+async request(){
+	let data = await this.$http.post('aid/region',{pid:0});
+	console.log(data);
+}
+```
+
+### 其他功能配置项
+```
+let data = await this.$http.post(
+	'http://www.aaa.com/aid/region', //可以直接放链接(将不启用全局定义域名)
+	{
+		pid:0
+	}, 
+	{
+		isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+		load: true,//(默认 true 说明:本接口是否提示加载动画)
+		header: { //默认 无 说明:请求头
+			'Content-Type': 'application/json'
+		},
+		isFactory: true //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用)
+	}
+);
+```
+
+### `requestConfig.js`可以设置服务器上传图片默认url
+```
+//可以new多个request来支持多个域名请求
+let $http = new request({
+	//服务器本地上传文件地址
+	fileUrl: base.baseUrl,
+	// 服务器上传图片默认url
+	defaultUploadUrl: "api/common/v1/upload_image",
+});
+```
+```
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlImgUpload({
+	name:"后台接受文件key名称", //默认 file
+	count:"最大选择数",//默认 9
+	sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	data:"而外参数" //可不填,
+});
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlVideoUpload({
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	name:"后台接受文件key名称", //默认 file
+	data:"而外参数" //可不填,
+});
+// 上传可以不用传递url(使用全局的上传图片url)
+this.$http.urlFileUpload({
+	files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	data:"向服务器传递的参数", //可不填
+	name:"后台接受文件key名称", //默认 file
+});
+```
+
+### 本地服务器图片上传(支持多张上传)
+```
+this.$http.urlImgUpload('flie/upload',{
+	name:"后台接受文件key名称", //默认 file
+	count:"最大选择数",//默认 9
+	sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	data:"而外参数" //可不填,
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 本地服务器视频上传
+```
+this.$http.urlVideoUpload('flie/upload',{
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	name:"后台接受文件key名称", //默认 file
+	data:"而外参数" //可不填,
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	},
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 本地服务器文件上传(支持多张上传)
+```
+this.$http.urlFileUpload("flie/upload",{
+	files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	data:"向服务器传递的参数", //可不填
+	name:"后台接受文件key名称", //默认 file
+	isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示)
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	header: { //默认 无 说明:请求头
+		'Content-Type': 'application/json'
+	},
+	isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+
+### 七牛云图片上传(支持多张上传)
+```
+this.$http.qnImgUpload({
+	count:"最大选择数", // 默认 9
+	sizeType:"选择压缩图原图,默认两个都选", // 默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选", // 默认 ['album','camera']
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 七牛云视频上传
+```
+this.$http.qnVideoUpload({
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 七牛云文件上传(支持多张上传)
+```
+this.$http.qnFileUpload(
+{
+	files:[], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 阿里云图片上传(支持多张上传)
+```
+this.$http.aliImgUpload({
+	count:"最大选择数", // 默认 9
+	sizeType:"选择压缩图原图,默认两个都选", // 默认 ['original', 'compressed']
+	sourceType:"选择相机拍照或相册上传 默认两个都选", // 默认 ['album','camera']
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 阿里云视频上传
+```
+this.$http.aliVideoUpload({
+	sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera']
+	compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false
+	maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60
+	camera: '前置还是后置摄像头', //'front'、'back',默认'back'
+	load: true,//(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onSelectComplete: res => {
+		console.log("选择完成返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### 阿里云文件上传(支持多张上传)
+```
+this.$http.aliFileUpload(
+{
+	files:[], // 必填 临时文件路径 格式: [{path: "图片地址"}]
+	load: true, //(默认 true 说明:本接口是否提示加载动画)
+	maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制)
+	onEachUpdate: res => {
+		console.log("单张上传成功返回:",res);
+	},
+	onProgressUpdate: res => {
+		console.log("上传进度返回:",res);
+	}
+}).then(res => {
+	console.log("全部上传完返回结果:",res);
+});
+```
+### jsonp 跨域请求(只支持H5)
+```
+let data = await this.$http.jsonp('http://www.aaa.com/aid/region',{pid:0}, {
+    isFactory: false, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用)
+});
+```

+ 30 - 11
pages/index/index.scss

@@ -1,5 +1,11 @@
  
 
+	@font-face {
+	    font-family: 'CustomFont';
+	    src: url('@/static/fonts/阿里妈妈数黑体.otf') format('opentype');
+	    font-weight: normal;
+	    font-style: normal;
+	}
 	.tab-nav {
 		display: flex;
 		justify-content: flex-start;
@@ -30,11 +36,11 @@
 			    border-top: 10rpx solid #ACF934;
 				display: none;
 			}
-			&.active { 
-				font-weight: bold;
+			&.active {  
 				background: #ACF934;
+				font-family: "CustomFont" !important;
 				.indicator-triangle {
-					display: block;
+					display: block; 
 				}
 			}
 		}
@@ -93,6 +99,9 @@
 						color: transparent;
 						width: 36rpx;
 						height: 36rpx;
+						position: relative;
+						left: -2rpx;
+						top: 0;
 					}
 				} 
 				.topic-content{
@@ -258,20 +267,18 @@
 	.float-btn {
 		position: fixed;
 		right: 30rpx;
-		bottom: 120rpx;
-		width: 100rpx;
-		height: 100rpx;
-		background-color: #FFFFFF;
+		bottom: 145rpx;
+		width: 120rpx;
+		height: 120rpx; 
 		border-radius: 50%;
 		display: flex;
 		justify-content: center;
-		align-items: center;
-		box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
+		align-items: center; 
 		z-index: 999;
 
 		.float-btn-icon {
-			width: 40rpx;
-			height: 40rpx;
+			width: 100%;
+			height: 100%;
 		}
 	}
 
@@ -387,4 +394,16 @@
 				justify-content: center;
 				align-items: center;
 			}
+		}
+		.lhSelectCity{
+			background-color: #fff; 
+			position: fixed;
+			left: 0;
+			right: 0;
+			width: 100%;
+			height: 100vh;
+			padding: 0 25rpx;
+			padding-top:  var(--status-bar-height);
+				
+;
 		}

+ 158 - 44
pages/index/index.vue

@@ -13,18 +13,18 @@
 		</view>
 		<z-paging ref="paging" v-model="dataList" @query="queryList" :style="{ height: windowHeight - 80 + 'px' }"
 			:show-scrollbar="false">
-			<template #top >
+			<template #top>
 				<page-navbar>
 					<template #navCenter>
 						<view class="top" style="  display: flex;">
-							<view  class="topBox">
-
-								<text style="margin-left: 10rpx; font-size: 44rpx;font-weight: 600;"> 杭州 </text>
+							<view class="topBox" @click="lhSelectCityFun">
+								<text style="margin-left: 10rpx; font-size: 44rpx;font-weight: 600;"> {{currentCity}}
+								</text>
 								<image src="@/static/home/home-bom.png"
 									style="width: 36rpx; height: 36rpx;margin-left: 15rpx;margin-right: 30rpx;"></image>
 							</view>
 							<view class="weather">
-								<p>多云🌤️20℃</p>
+								<p>{{weather.weather}}🌤️{{weather.temp}}</p>
 								<p>星期五</p>
 							</view>
 						</view>
@@ -95,7 +95,7 @@
 
 				</sortble>
 			</z-paging-cell>
-			<z-paging-cell>
+			<z-paging-cell style="background: #fff;">
 				<view class="tab-nav">
 					<view v-for="(tab, index) in tabs" :key="index"
 						:class="['tab-item', currentTab === index ? 'active' : '']" @click="switchTab(index)">
@@ -117,15 +117,21 @@
 								<view v-for="(topic, index) in page" :key="index" class="topic-item"
 									@click="goToArticleDetail(topic.id)">
 									<view class="hot-topics-left">
-										<image v-if="(pageIndex * 4 + index) ==0" src="@/static/icon/icon-first.png" class="topic-index topic-index-img" mode=""></image>
-										<image v-else-if="(pageIndex * 4 + index) ==1" src="@/static/icon/icon-second.png" class="topic-index topic-index-img" mode=""></image>
-										<image v-else-if="(pageIndex * 4 + index) ==2" src="@/static/icon/icon-third.png" class="topic-index topic-index-img" mode=""></image>
+										<image v-if="(pageIndex * 4 + index) ==0" src="@/static/icon/icon-first.png"
+											class="topic-index topic-index-img" mode=""></image>
+										<image v-else-if="(pageIndex * 4 + index) ==1"
+											src="@/static/icon/icon-second.png" class="topic-index topic-index-img"
+											mode=""></image>
+										<image v-else-if="(pageIndex * 4 + index) ==2"
+											src="@/static/icon/icon-third.png" class="topic-index topic-index-img"
+											mode=""></image>
 										<text v-else class="topic-index">{{ pageIndex * 4 + index + 1 }}</text>
-										
+
 										<view class="topic-content toe">
 											{{ topic.title }}
-										</view> 
-										<image v-if="topic.isHot" src="@/static/icon/icon-hot.png" class="hot-tag" mode=""></image>
+										</view>
+										<image v-if="topic.isHot" src="@/static/icon/icon-hot.png" class="hot-tag"
+											mode=""></image>
 									</view>
 									<text class="topic-participants">{{ topic.num_like }}人正在热议</text>
 									<!-- <text class="topic-index">{{ pageIndex * 5 + index + 1 }}</text>
@@ -216,11 +222,14 @@
 		<tabbar-vue :tabbars="tabbars" :currentIndex="0" ref="tabbar"></tabbar-vue>
 
 		<!-- 添加浮动按钮 -->
-		<view v-if="currentTab === 2" class="float-btn" @click="goToMake">
-			<image src="/static/icon/icon_add_black.png" class="float-btn-icon"></image>
+		<view v-if="currentTab === 2 " class="float-btn" @click="goToMake">
+			<image src="/static/home/release-btn.png" class="float-btn-icon"></image>
 		</view>
 
 		<novice-guidance :step="step"></novice-guidance>
+		<lhSelectCity style="height: 100vh;" class="lhSelectCity" :currentCity="currentCity"
+			:windowHeight="windowHeight" :hotCitys="hotCitys" @onSelect="City" v-if="lhSelectCityFalg"
+			@closeLhSelectCityFun="closeLhSelectCityFun()" />
 	</view>
 </template>
 
@@ -231,6 +240,7 @@
 	import wWaterfall from "@/components/w-waterfall/w-waterfall.vue";
 	import tabbar from "@/mixins/tabbar";
 	import card from "@/components/card/card.vue";
+	import lhSelectCity from "@/components/lh-select-city/index.vue"
 	// import noviceGuidance from "@/components/novice-guidance/index.vue";
 	export default {
 		components: {
@@ -238,6 +248,7 @@
 			tabbarVue,
 			pageNavbar,
 			wWaterfall,
+			lhSelectCity,
 			// noviceGuidance
 		},
 		mixins: [tabbar],
@@ -324,6 +335,26 @@
 				isLoadingExplore: false, // 是否正在加载探索列表
 				isLoadingNews: false, // 是否正在加载新闻列表
 				hotTopics: [],
+				lhSelectCityFalg: false,
+				hotCitys: [
+					'杭州',
+					'天津',
+					'北京',
+					'上海',
+					'深圳',
+					'广州',
+					'成都',
+					'重庆',
+					'厦门'
+				],
+				currentCity: '北京',
+				windowHeight: "",
+				weather:{
+					city: "",
+					weather: "",
+					temp: '0℃',
+					icon: 101
+				}
 			};
 		},
 		computed: {
@@ -347,10 +378,14 @@
 				return pages;
 			},
 		},
-		onLoad() {
+	 	onLoad() {
 			let that = this;
+			// 计算出可用高度
+			this.windowHeight = uni.getSystemInfoSync().windowHeight + "px";
 			// 不在onLoad中直接加载数据,避免与z-paging组件重复请求
-			// 让z-paging组件通过queryList方法控制数据加载
+			// 让z-paging组件通过queryList方法控制数据加载 
+			this.getWeather()
+		 
 		},
 		// 上拉加载更多
 		onReachBottom() {
@@ -358,6 +393,42 @@
 		},
 		// 下拉刷新数据
 		methods: {
+			getWeather(){
+				uni.request({
+					url: this.$apiHost + '/Index/getAreaInfo',
+					data: {
+						uuid: getApp().globalData.uuid,
+						skey: getApp().globalData.skey,
+					},
+					header: {
+						"content-type": "application/json",
+						'sign': getApp().globalData.headerSign
+					},
+					success: (res) => {
+						console.log(res);
+					 this.currentCity = res.data.city 
+						this.weather = res.data	
+							console.log(this.weather ,999,res.data	);
+					},
+					complete: () => {},
+					fail: (e) => {
+					}
+				});
+			},
+			lhSelectCityFun() {
+				this.lhSelectCityFalg = true
+			},
+			// 选中事件
+			City(city) {
+				this.currentCity = city
+				setTimeout(() => {
+					this.lhSelectCityFalg = false
+				}, 300)
+
+			},
+			closeLhSelectCityFun() {
+				this.lhSelectCityFalg = false
+			},
 			queryList() {
 				// 根据当前标签刷新数据
 				switch (this.currentTab) {
@@ -619,7 +690,7 @@
 							res.data.list.length > 0
 						) {
 							this.hotNewsList = res.data.list;
-							
+
 							// 如果有热点新闻数据,更新热搜资讯
 							if (this.hotNewsList.length > 0) {
 								// 将API返回的热点新闻转换为热搜资讯格式
@@ -637,30 +708,70 @@
 					complete: () => {
 						this.isLoadingExplore = false;
 					},
-					fail: (e) => { 
+					fail: (e) => {
 						console.log("请求热点新闻失败:", e);
 						this.isLoadingExplore = false;
 					},
 				});
 			},
-			loadNewsList() {
+		 	loadNewsList() {
 				if (this.isLoadingNews) return;
 				this.isLoadingNews = true;
+				// uni.request({
+				// 	url: this.$apiHost + "/Article/getlist",
+				// 	data: {
+				// 		uuid: getApp().globalData.uuid,
+				// 		skey: getApp().globalData.skey,
+				// 		type: "list", // 新闻列表
+				// 		offset: this.newsOffset,
+				// 	},
+				// 	header: {
+				// 		"content-type": "application/json",
+				// 		sign: getApp().globalData.headerSign,
+				// 	},
+				// 	success: (res) => {
+				// 		console.log("新闻列表数据:", res.data);
+				// 		if (
+				// 			res.data.success == "yes" &&
+				// 			res.data.list &&
+				// 			res.data.list.length > 0
+				// 		) {
+				// 			this.newsList = [...this.newsList, ...res.data.list];
+				// 			this.newsOffset += res.data.list.length;
 
-				uni.request({
-					url: this.$apiHost + "/Article/getlist",
-					data: {
-						uuid: getApp().globalData.uuid,
-						skey: getApp().globalData.skey,
-						type: "list", // 新闻列表
-						offset: this.newsOffset,
-					},
-					header: {
-						"content-type": "application/json",
-						sign: getApp().globalData.headerSign,
-					},
-					success: (res) => {
-						console.log("新闻列表数据:", res.data);
+				// 			if (res.data.list.length < 20) {
+				// 				this.hasMoreNews = false;
+				// 			}
+				// 		} else {
+				// 			this.hasMoreNews = false;
+				// 		}
+
+				// 		// 无论是否有数据,都需要通知z-paging组件完成刷新
+				// 		if (this.$refs.paging) {
+				// 			this.$refs.paging.complete(this.newsList);
+				// 		}
+				// 	},
+				// 	complete: () => {
+				// 		this.isLoadingNews = false;
+				// 	},
+				// 	fail: (e) => {
+				// 		console.log("请求新闻列表失败:", e);
+				// 		this.isLoadingNews = false;
+				// 		// 加载失败时也要通知组件完成
+				// 		if (this.$refs.paging) {
+				// 			this.$refs.paging.complete(false);
+				// 		}
+				// 	},
+				// });
+				this.$http.get('/Article/getlist', {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					type: "list", // 新闻列表
+					offset: this.newsOffset,
+				}).then(
+					async res => {
+						await res 
+						console.log("新闻列表数据:", res);
 						if (
 							res.data.success == "yes" &&
 							res.data.list &&
@@ -668,31 +779,33 @@
 						) {
 							this.newsList = [...this.newsList, ...res.data.list];
 							this.newsOffset += res.data.list.length;
-
+						
 							if (res.data.list.length < 20) {
 								this.hasMoreNews = false;
 							}
 						} else {
 							this.hasMoreNews = false;
 						}
-
+						
 						// 无论是否有数据,都需要通知z-paging组件完成刷新
 						if (this.$refs.paging) {
 							this.$refs.paging.complete(this.newsList);
 						}
-					},
-					complete: () => {
-						this.isLoadingNews = false;
-					},
-					fail: (e) => {
+					}).catch(
+					async e => {
+						await e
 						console.log("请求新闻列表失败:", e);
 						this.isLoadingNews = false;
 						// 加载失败时也要通知组件完成
 						if (this.$refs.paging) {
 							this.$refs.paging.complete(false);
 						}
-					},
-				});
+					}).finally(
+					() => {
+						 this.isLoadingNews = false;
+					})
+				 
+
 			},
 			loadMoreData() {
 				// 根据当前标签加载更多数据
@@ -717,7 +830,7 @@
 			handleTopicPageChange(e) {
 				this.currentTopicPage = e.detail.current;
 			},
- 
+
 			formatItem(item) {
 
 				this.downloadAndProcessImage(item.images)
@@ -731,7 +844,8 @@
 				return {
 					id: item.id,
 					allowEdit: false,
-					author: item.author,
+					nickname: item.nickname,
+					avator: item.avator,
 					num_like: item.num_like,
 					num_view: item.num_view,
 					image: item.images || item.img_url || item.image, // 优先使用images字段

+ 2 - 2
pages/login/login.vue

@@ -98,8 +98,8 @@
 					num_history: 0,
 					num_collection: 0
 				},
-				mobile: '',
-				password: '',
+				mobile: '18899990000',
+				password: '111111',
 				code: '',
 				captchaTime: 0,
 				push_token: '',

BIN
static/fonts/阿里妈妈数黑体.otf


BIN
static/home/release-btn.png


+ 11 - 0
style/FontStyle.css

@@ -1,3 +1,14 @@
+@font-face {
+    font-family: 'CustomFont';
+    src: url('@/static/fonts/阿里妈妈数黑体.otf') format('opentype');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.CustomFont {
+    font-family: 'CustomFont', sans-serif !important;
+}
+
 @font-face {
   font-family: 'iconfont';  /* project id 1639347 */
   src: url('https://at.alicdn.com/t/font_1639347_9tnhp28j8vi.eot');