ncs_23818 2 rokov pred
commit
4ef3300b68
100 zmenil súbory, kde vykonal 13280 pridanie a 0 odobranie
  1. 36 0
      README.en.md
  2. 39 0
      README.md
  3. 16 0
      ctxx_xcx/.hbuilderx/launch.json
  4. 33 0
      ctxx_xcx/App.vue
  5. 28 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseAudio.vue
  6. 94 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseImg.vue
  7. 55 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTable.vue
  8. 98 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate0.vue
  9. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate1.vue
  10. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate10.vue
  11. 86 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate11.vue
  12. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate2.vue
  13. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate3.vue
  14. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate4.vue
  15. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate5.vue
  16. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate6.vue
  17. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate7.vue
  18. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate8.vue
  19. 88 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate9.vue
  20. 15 0
      ctxx_xcx/components/gaoyia-parse/components/wxParseVideo.vue
  21. 261 0
      ctxx_xcx/components/gaoyia-parse/libs/html2json.js
  22. 156 0
      ctxx_xcx/components/gaoyia-parse/libs/htmlparser.js
  23. 209 0
      ctxx_xcx/components/gaoyia-parse/libs/wxDiscode.js
  24. 258 0
      ctxx_xcx/components/gaoyia-parse/parse.css
  25. 228 0
      ctxx_xcx/components/gaoyia-parse/parse.vue
  26. 79 0
      ctxx_xcx/components/nav-bar/nav-bar.vue
  27. 137 0
      ctxx_xcx/components/pick-regions/pick-regions.vue
  28. 0 0
      ctxx_xcx/components/pick-regions/regions.json
  29. 1247 0
      ctxx_xcx/components/three-level-linkage/data-info/level-data.js
  30. 443 0
      ctxx_xcx/components/three-level-linkage/linkage.nvue
  31. 24 0
      ctxx_xcx/components/wyb-noticeBar/iconfont.css
  32. 466 0
      ctxx_xcx/components/wyb-noticeBar/wyb-noticeBar.vue
  33. 4 0
      ctxx_xcx/config/env.js
  34. 20 0
      ctxx_xcx/index.html
  35. 29 0
      ctxx_xcx/main.js
  36. 72 0
      ctxx_xcx/manifest.json
  37. 16 0
      ctxx_xcx/package-lock.json
  38. 142 0
      ctxx_xcx/pages.json
  39. 410 0
      ctxx_xcx/pages/goodsDetail/index.vue
  40. 437 0
      ctxx_xcx/pages/goodsOrderDetail/index.vue
  41. 665 0
      ctxx_xcx/pages/index/index.vue
  42. 55 0
      ctxx_xcx/pages/indexNotice/index.vue
  43. 52 0
      ctxx_xcx/pages/loading/index.vue
  44. 178 0
      ctxx_xcx/pages/mandate/index.vue
  45. 284 0
      ctxx_xcx/pages/mine/index.vue
  46. 488 0
      ctxx_xcx/pages/orderPay/index.vue
  47. 58 0
      ctxx_xcx/pages/orderSuccess/index.vue
  48. 64 0
      ctxx_xcx/pages/order_s/index.vue
  49. 210 0
      ctxx_xcx/pages/shoeList/index.vue
  50. 472 0
      ctxx_xcx/pages/shoeOrderDetails/index.vue
  51. 270 0
      ctxx_xcx/pages/shop/index.vue
  52. 206 0
      ctxx_xcx/pages/shopList/index.vue
  53. 54 0
      ctxx_xcx/pages/shopNotice/index.vue
  54. 638 0
      ctxx_xcx/pages/shopesOrder/index.vue
  55. 64 0
      ctxx_xcx/pages/subscribe/index.vue
  56. 208 0
      ctxx_xcx/pages/subscribeDetails/index.vue
  57. 122 0
      ctxx_xcx/pages/subscribeList/index.vue
  58. 50 0
      ctxx_xcx/pages/userDeal/index.vue
  59. 266 0
      ctxx_xcx/pages/userInfoUpdate/index.vue
  60. BIN
      ctxx_xcx/static/index/add-icon.png
  61. BIN
      ctxx_xcx/static/index/add-icons.png
  62. BIN
      ctxx_xcx/static/index/address-icon.png
  63. BIN
      ctxx_xcx/static/index/check-icon-sel.png
  64. BIN
      ctxx_xcx/static/index/check-icon.png
  65. BIN
      ctxx_xcx/static/index/check-icons.png
  66. BIN
      ctxx_xcx/static/index/close.png
  67. BIN
      ctxx_xcx/static/index/eimail-icon.png
  68. BIN
      ctxx_xcx/static/index/index-icons.png
  69. BIN
      ctxx_xcx/static/index/index_bg.png
  70. BIN
      ctxx_xcx/static/index/index_icons.png
  71. BIN
      ctxx_xcx/static/index/index_nav_icon.png
  72. BIN
      ctxx_xcx/static/index/index_nav_icon_sel.png
  73. BIN
      ctxx_xcx/static/index/mine-icon1.png
  74. BIN
      ctxx_xcx/static/index/mine-icon2.png
  75. BIN
      ctxx_xcx/static/index/mine-icon3.png
  76. BIN
      ctxx_xcx/static/index/mine-icon4.png
  77. BIN
      ctxx_xcx/static/index/mine_icon.png
  78. BIN
      ctxx_xcx/static/index/mine_icon_sel.png
  79. BIN
      ctxx_xcx/static/index/notice-icon.png
  80. BIN
      ctxx_xcx/static/index/oder-ok.png
  81. BIN
      ctxx_xcx/static/index/phone-icon.png
  82. BIN
      ctxx_xcx/static/index/photo-icon.png
  83. BIN
      ctxx_xcx/static/index/shoes-icon.png
  84. BIN
      ctxx_xcx/static/index/shop-icons.png
  85. BIN
      ctxx_xcx/static/index/shopIcons.png
  86. BIN
      ctxx_xcx/static/index/shop_icon.png
  87. BIN
      ctxx_xcx/static/index/shop_icon_sel.png
  88. BIN
      ctxx_xcx/static/index/shopping-icon.png
  89. BIN
      ctxx_xcx/static/index/subscribe.png
  90. BIN
      ctxx_xcx/static/index/trumpet-icon.png
  91. BIN
      ctxx_xcx/static/index/wx-icon.png
  92. BIN
      ctxx_xcx/static/index/wxIcon.png
  93. 77 0
      ctxx_xcx/uni.scss
  94. 191 0
      ctxx_xcx/uni_modules/mp-html/README.md
  95. 114 0
      ctxx_xcx/uni_modules/mp-html/changelog.md
  96. 493 0
      ctxx_xcx/uni_modules/mp-html/components/mp-html/mp-html.vue
  97. 574 0
      ctxx_xcx/uni_modules/mp-html/components/mp-html/node/node.vue
  98. 1333 0
      ctxx_xcx/uni_modules/mp-html/components/mp-html/parser.js
  99. 76 0
      ctxx_xcx/uni_modules/mp-html/package.json
  100. 0 0
      ctxx_xcx/uni_modules/mp-html/static/app-plus/mp-html/js/handler.js

+ 36 - 0
README.en.md

@@ -0,0 +1,36 @@
+# ctxx-xcx
+
+#### Description
+{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 39 - 0
README.md

@@ -0,0 +1,39 @@
+# ctxx-xcx
+
+#### 介绍
+{**以下是 Gitee 平台说明,您可以替换此简介**
+Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
+无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 使用说明
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 参与贡献
+
+1.  Fork 本仓库
+2.  新建 Feat_xxx 分支
+3.  提交代码
+4.  新建 Pull Request
+
+
+#### 特技
+
+1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
+2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
+3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
+4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
+5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
+6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 16 - 0
ctxx_xcx/.hbuilderx/launch.json

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

+ 33 - 0
ctxx_xcx/App.vue

@@ -0,0 +1,33 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+	}
+</script>
+
+<style lang="scss">
+	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
+	@import "uview-ui/index.scss";
+	page{
+		background-color: #f7f7f7;
+	}
+	.overflow1{
+	  white-space: nowrap;
+	  overflow: hidden;
+	  text-overflow: ellipsis;
+	}
+	.overflow2{
+	  overflow : hidden;
+	  text-overflow: ellipsis;
+	  display: -webkit-box;
+	  -webkit-box-orient: vertical;
+	  -webkit-line-clamp: 2;
+	}
+</style>

+ 28 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseAudio.vue

@@ -0,0 +1,28 @@
+<template>
+	<!-- '<audio/>' 组件不再维护,建议使用能力更强的 'uni.createInnerAudioContext' 接口 有时间再改-->
+  <!--增加audio标签支持-->
+  <audio
+    :id="node.attr.id"
+    :class="node.classStr"
+    :style="node.styleStr"
+    :src="node.attr.src"
+    :loop="node.attr.loop"
+    :poster="node.attr.poster"
+    :name="node.attr.name"
+    :author="node.attr.author"
+    controls></audio>
+</template>
+
+<script>
+export default {
+  name: 'wxParseAudio',
+  props: {
+    node: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+};
+</script>

+ 94 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseImg.vue

@@ -0,0 +1,94 @@
+<template>
+	<image
+		:mode="node.attr.mode"
+		:lazy-load="node.attr.lazyLoad"
+		:class="node.classStr"
+		:style="newStyleStr || node.styleStr"
+		:data-src="node.attr.src"
+		:src="node.attr.src"
+		@tap="wxParseImgTap"
+		@load="wxParseImgLoad"
+	/>
+</template>
+
+<script>
+export default {
+	name: 'wxParseImg',
+	data() {
+		return {
+			newStyleStr: '',
+			preview: true
+		};
+	},
+	inject: ['parseWidth'],
+	mounted() {},
+	props: {
+		node: {
+			type: Object,
+			default() {
+				return {};
+			}
+		}
+	},
+	
+	methods: {
+		wxParseImgTap(e) {
+			if (!this.preview) return;
+			const { src } = e.currentTarget.dataset;
+			if (!src) return;
+			let parent = this.$parent;
+			while (!parent.preview || typeof parent.preview !== 'function') {
+				// TODO 遍历获取父节点执行方法
+				parent = parent.$parent;
+			}
+			parent.preview(src, e);
+		},
+		// 图片视觉宽高计算函数区
+		wxParseImgLoad(e) {
+			const { src } = e.currentTarget.dataset;
+			if (!src) return;
+			let { width, height } = e.mp.detail;
+
+			const recal = this.wxAutoImageCal(width, height);
+
+			const { imageheight, imageWidth } = recal;
+			const { padding, mode } = this.node.attr;//删除padding
+			// const { mode } = this.node.attr;
+
+			const { styleStr } = this.node;
+			const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
+
+			this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;//删除padding
+			// this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px;`;
+		},
+		// 计算视觉优先的图片宽高
+		wxAutoImageCal(originalWidth, originalHeight) {
+			// 获取图片的原始长宽
+			const windowWidth = this.parseWidth.value;
+			const results = {};
+
+			if (originalWidth < 60 || originalHeight < 60) {
+				const { src } = this.node.attr;
+				let parent = this.$parent;
+				while (!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.removeImageUrl(src);
+				this.preview = false;
+			}
+
+			// 判断按照那种方式进行缩放
+			if (originalWidth > windowWidth) {
+				// 在图片width大于手机屏幕width时候
+				results.imageWidth = windowWidth;
+				results.imageheight = windowWidth * (originalHeight / originalWidth);
+			} else {
+				// 否则展示原来的数据
+				results.imageWidth = originalWidth;
+				results.imageheight = originalHeight;
+			}
+			return results;
+		}
+	}
+};
+</script>

+ 55 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTable.vue

@@ -0,0 +1,55 @@
+<template>
+	<div class='tablebox'>
+		<rich-text :nodes="nodes" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
+	</div>
+</template>
+<script>
+export default {
+	name: 'wxParseTable',
+	props: {
+		node: {
+			type: Object,
+			default() {
+				return {};
+			},
+		},
+	},
+	inject: ['parseSelect'],
+	data() {
+		return {
+			nodes:[]
+		};
+	},
+	mounted() {
+		this.nodes=this.loadNode([this.node]);
+	},
+	methods: {
+		loadNode(node) {
+			let obj = [];
+			for (let children of node) {
+				if (children.node=='element') {
+					let t = {
+						name:children.tag,
+						attrs: {
+							class: children.classStr,
+							// style: children.styleStr,
+						},
+						children: children.nodes?this.loadNode(children.nodes):[]
+					}
+					
+					obj.push(t)
+				} else if(children.node=='text'){
+					obj.push({
+						type: 'text',
+						text: children.text
+					})
+				}
+			}
+			return obj
+		}
+	}
+};
+</script>
+<style>
+	@import url("../parse.css");
+</style>

+ 98 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate0.vue

@@ -0,0 +1,98 @@
+<template>
+	<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node"/>
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text'">{{node.text}}</block>
+</template>
+
+<script>
+	// #ifdef APP-PLUS | H5
+	import wxParseTemplate from './wxParseTemplate0';
+	// #endif
+	// #ifdef MP
+	import wxParseTemplate from './wxParseTemplate1';
+	// #endif
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+
+	export default {
+		// #ifdef APP-PLUS | H5
+		name: 'wxParseTemplate',
+		// #endif
+		// #ifdef MP
+		name: 'wxParseTemplate0',
+		// #endif
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;// TODO currentTarget才有dataset
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate1.vue

@@ -0,0 +1,88 @@
+<template>
+	<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text'">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate2';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate1',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate10.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate11';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate10',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 86 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate11.vue

@@ -0,0 +1,86 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate11',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate2.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text'">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate3';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate2',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate3.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate4';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate3',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate4.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate5';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate4',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate5.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate6';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate5',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate6.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate7';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate6',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate7.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate8';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate7',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate8.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate9';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate8',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 88 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseTemplate9.vue

@@ -0,0 +1,88 @@
+<template>
+		<!--判断是否是标签节点-->
+	<block v-if="node.node == 'element'">
+		<!--button类型-->
+		<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
+			<wx-parse-template :node="node" />
+		</button>
+		
+		<!--a类型-->
+		<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--li类型-->
+		<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+		
+		<!--table类型-->
+		<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
+		
+		<!--br类型-->
+		<!-- #ifndef H5 -->
+			<text v-else-if="node.tag == 'br'">\n</text>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+			<br v-else-if="node.tag == 'br'">
+		<!-- #endif -->
+		
+		<!--video类型-->
+		<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
+	
+		<!--audio类型-->
+		<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
+	
+		<!--img类型-->
+		<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
+	
+		<!--其他标签-->
+		<view v-else :class="node.classStr" :style="node.styleStr">
+			<block v-for="(node, index) of node.nodes" :key="index">
+				<wx-parse-template :node="node" />
+			</block>
+		</view>
+	</block>
+	
+	<!--判断是否是文本节点-->
+	<block v-else-if="node.node == 'text' ">{{node.text}}</block>
+</template>
+
+<script>
+	import wxParseTemplate from './wxParseTemplate10';
+	import wxParseImg from './wxParseImg';
+	import wxParseVideo from './wxParseVideo';
+	import wxParseAudio from './wxParseAudio';
+	import wxParseTable from './wxParseTable';
+	
+	export default {
+		name: 'wxParseTemplate9',
+		props: {
+			node: {},
+		},
+		components: {
+			wxParseTemplate,
+			wxParseImg,
+			wxParseVideo,
+			wxParseAudio,
+			wxParseTable
+		},
+		methods: {
+			wxParseATap(attr,e) {
+				const {
+					href
+				} = e.currentTarget.dataset;
+				if (!href) return;
+				let parent = this.$parent;
+				while(!parent.preview || typeof parent.preview !== 'function') {
+					parent = parent.$parent;
+				}
+				parent.navigate(href, e, attr);
+			}
+		}
+	};
+</script>

+ 15 - 0
ctxx_xcx/components/gaoyia-parse/components/wxParseVideo.vue

@@ -0,0 +1,15 @@
+<template>
+  <!--增加video标签支持,并循环添加-->
+  <view :class="node.classStr" :style="node.styleStr">
+    <video :class="node.classStr" :style="node.styleStr" class="video-video" :src="node.attr.src"></video>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'wxParseVideo',
+  props: {
+    node: {},
+  },
+};
+</script>

+ 261 - 0
ctxx_xcx/components/gaoyia-parse/libs/html2json.js

@@ -0,0 +1,261 @@
+/**
+ * html2Json 改造来自: https://github.com/Jxck/html2json
+ *
+ *
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+import wxDiscode from './wxDiscode';
+import HTMLParser from './htmlparser';
+
+function makeMap(str) {
+  const obj = {};
+  const items = str.split(',');
+  for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
+  return obj;
+}
+
+// Block Elements - HTML 5
+const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
+
+// Inline Elements - HTML 5
+const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
+
+function removeDOCTYPE(html) {
+  const isDocument = /<body.*>([^]*)<\/body>/.test(html);
+  return isDocument ? RegExp.$1 : html;
+}
+
+function trimHtml(html) {
+  return html
+    .replace(/<!--.*?-->/gi, '')
+    .replace(/\/\*.*?\*\//gi, '')
+    .replace(/[ ]+</gi, '<')
+    .replace(/<script[^]*<\/script>/gi, '')
+    .replace(/<style[^]*<\/style>/gi, '');
+}
+
+function getScreenInfo() {
+  const screen = {};
+  wx.getSystemInfo({
+    success: (res) => {
+      screen.width = res.windowWidth;
+      screen.height = res.windowHeight;
+    },
+  });
+  return screen;
+}
+
+function html2json(html, customHandler, imageProp, host) {
+  // 处理字符串
+  html = removeDOCTYPE(html);
+  html = trimHtml(html);
+  html = wxDiscode.strDiscode(html);
+  // 生成node节点
+  const bufArray = [];
+  const results = {
+    nodes: [],
+    imageUrls: [],
+  };
+
+	const screen = getScreenInfo();
+  function Node(tag) {
+    this.node = 'element';
+    this.tag = tag;
+		
+		this.$screen = screen;
+  }
+
+  HTMLParser(html, {
+    start(tag, attrs, unary) {
+      // node for this element
+      const node = new Node(tag);
+
+      if (bufArray.length !== 0) {
+        const parent = bufArray[0];
+        if (parent.nodes === undefined) {
+          parent.nodes = [];
+        }
+      }
+
+      if (block[tag]) {
+        node.tagType = 'block';
+      } else if (inline[tag]) {
+        node.tagType = 'inline';
+      } else if (closeSelf[tag]) {
+        node.tagType = 'closeSelf';
+      }
+
+      node.attr = attrs.reduce((pre, attr) => {
+        const { name } = attr;
+        let { value } = attr;
+        if (name === 'class') {
+          node.classStr = value;
+        }
+        // has multi attibutes
+        // make it array of attribute
+        if (name === 'style') {
+          node.styleStr = value;
+        }
+        if (value.match(/ /)) {
+          value = value.split(' ');
+        }
+
+        // if attr already exists
+        // merge it
+        if (pre[name]) {
+          if (Array.isArray(pre[name])) {
+            // already array, push to last
+            pre[name].push(value);
+          } else {
+            // single value, make it array
+            pre[name] = [pre[name], value];
+          }
+        } else {
+          // not exist, put it
+          pre[name] = value;
+        }
+
+        return pre;
+      }, {});
+
+      // 优化样式相关属性
+      if (node.classStr) {
+        node.classStr += ` ${node.tag}`;
+      } else {
+        node.classStr = node.tag;
+      }
+      if (node.tagType === 'inline') {
+        node.classStr += ' inline';
+      }
+
+      // 对img添加额外数据
+      if (node.tag === 'img') {
+        let imgUrl = node.attr.src;
+        imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
+        Object.assign(node.attr, imageProp, {
+          src: imgUrl || '',
+        });
+        if (imgUrl) {
+          results.imageUrls.push(imgUrl);
+        }
+      }
+
+      // 处理a标签属性
+      if (node.tag === 'a') {
+        node.attr.href = node.attr.href || '';
+      }
+
+      // 处理font标签样式属性
+      if (node.tag === 'font') {
+        const fontSize = [
+          'x-small',
+          'small',
+          'medium',
+          'large',
+          'x-large',
+          'xx-large',
+          '-webkit-xxx-large',
+        ];
+        const styleAttrs = {
+          color: 'color',
+          face: 'font-family',
+          size: 'font-size',
+        };
+        if (!node.styleStr) node.styleStr = '';
+        Object.keys(styleAttrs).forEach((key) => {
+          if (node.attr[key]) {
+            const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
+            node.styleStr += `${styleAttrs[key]}: ${value};`;
+          }
+        });
+      }
+
+      // 临时记录source资源
+      if (node.tag === 'source') {
+        results.source = node.attr.src;
+      }
+
+      if (customHandler.start) {
+        customHandler.start(node, results);
+      }
+
+      if (unary) {
+        // if this tag doesn't have end tag
+        // like <img src="hoge.png"/>
+        // add to parents
+        const parent = bufArray[0] || results;
+        if (parent.nodes === undefined) {
+          parent.nodes = [];
+        }
+        parent.nodes.push(node);
+      } else {
+        bufArray.unshift(node);
+      }
+    },
+    end(tag) {
+      // merge into parent tag
+      const node = bufArray.shift();
+      if (node.tag !== tag) {
+        console.error('invalid state: mismatch end tag');
+      }
+
+      // 当有缓存source资源时于于video补上src资源
+      if (node.tag === 'video' && results.source) {
+        node.attr.src = results.source;
+        delete results.source;
+      }
+
+      if (customHandler.end) {
+        customHandler.end(node, results);
+      }
+
+      if (bufArray.length === 0) {
+        results.nodes.push(node);
+      } else {
+        const parent = bufArray[0];
+        if (!parent.nodes) {
+          parent.nodes = [];
+        }
+        parent.nodes.push(node);
+      }
+    },
+    chars(text) {
+      if (!text.trim()) return;
+
+      const node = {
+        node: 'text',
+        text,
+      };
+
+      if (customHandler.chars) {
+        customHandler.chars(node, results);
+      }
+
+      if (bufArray.length === 0) {
+        results.nodes.push(node);
+      } else {
+        const parent = bufArray[0];
+        if (parent.nodes === undefined) {
+          parent.nodes = [];
+        }
+        parent.nodes.push(node);
+      }
+    },
+  });
+
+  return results;
+}
+
+export default html2json;

+ 156 - 0
ctxx_xcx/components/gaoyia-parse/libs/htmlparser.js

@@ -0,0 +1,156 @@
+/**
+ *
+ * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
+ *
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+// Regular Expressions for parsing tags and attributes
+
+const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
+const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
+const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
+
+function makeMap(str) {
+  const obj = {};
+  const items = str.split(',');
+  for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
+  return obj;
+}
+
+// Empty Elements - HTML 5
+const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
+
+// Block Elements - HTML 5
+const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
+
+// Inline Elements - HTML 5
+const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
+
+// Attributes that have their values filled in disabled="disabled"
+const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
+
+function HTMLParser(html, handler) {
+  let index;
+  let chars;
+  let match;
+  let last = html;
+  const stack = [];
+
+  stack.last = () => stack[stack.length - 1];
+
+  function parseEndTag(tag, tagName) {
+    // If no tag name is provided, clean shop
+    let pos;
+    if (!tagName) {
+      pos = 0;
+    } else {
+      // Find the closest opened tag of the same type
+      tagName = tagName.toLowerCase();
+      for (pos = stack.length - 1; pos >= 0; pos -= 1) {
+        if (stack[pos] === tagName) break;
+      }
+    }
+    if (pos >= 0) {
+      // Close all the open elements, up the stack
+      for (let i = stack.length - 1; i >= pos; i -= 1) {
+        if (handler.end) handler.end(stack[i]);
+      }
+
+      // Remove the open elements from the stack
+      stack.length = pos;
+    }
+  }
+
+  function parseStartTag(tag, tagName, rest, unary) {
+    tagName = tagName.toLowerCase();
+
+    if (block[tagName]) {
+      while (stack.last() && inline[stack.last()]) {
+        parseEndTag('', stack.last());
+      }
+    }
+
+    if (closeSelf[tagName] && stack.last() === tagName) {
+      parseEndTag('', tagName);
+    }
+
+    unary = empty[tagName] || !!unary;
+
+    if (!unary) stack.push(tagName);
+
+    if (handler.start) {
+      const attrs = [];
+
+      rest.replace(attr, function genAttr(matches, name) {
+        const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
+
+        attrs.push({
+          name,
+          value,
+          escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
+        });
+      });
+
+      if (handler.start) {
+        handler.start(tagName, attrs, unary);
+      }
+    }
+  }
+
+  while (html) {
+    chars = true;
+
+    if (html.indexOf('</') === 0) {
+      match = html.match(endTag);
+
+      if (match) {
+        html = html.substring(match[0].length);
+        match[0].replace(endTag, parseEndTag);
+        chars = false;
+      }
+
+      // start tag
+    } else if (html.indexOf('<') === 0) {
+      match = html.match(startTag);
+
+      if (match) {
+        html = html.substring(match[0].length);
+        match[0].replace(startTag, parseStartTag);
+        chars = false;
+      }
+    }
+
+    if (chars) {
+      index = html.indexOf('<');
+      let text = '';
+      while (index === 0) {
+        text += '<';
+        html = html.substring(1);
+        index = html.indexOf('<');
+      }
+      text += index < 0 ? html : html.substring(0, index);
+      html = index < 0 ? '' : html.substring(index);
+
+      if (handler.chars) handler.chars(text);
+    }
+
+    if (html === last) throw new Error(`Parse Error: ${html}`);
+    last = html;
+  }
+
+  // Clean up any remaining tags
+  parseEndTag();
+}
+
+export default HTMLParser;

+ 209 - 0
ctxx_xcx/components/gaoyia-parse/libs/wxDiscode.js

@@ -0,0 +1,209 @@
+// HTML 支持的数学符号
+function strNumDiscode(str) {
+str = str.replace(/&forall;|&#8704;|&#x2200;/g, '∀');
+str = str.replace(/&part;|&#8706;|&#x2202;/g, '∂');
+str = str.replace(/&exist;|&#8707;|&#x2203;/g, '∃');
+str = str.replace(/&empty;|&#8709;|&#x2205;/g, '∅');
+str = str.replace(/&nabla;|&#8711;|&#x2207;/g, '∇');
+str = str.replace(/&isin;|&#8712;|&#x2208;/g, '∈');
+str = str.replace(/&notin;|&#8713;|&#x2209;/g, '∉');
+str = str.replace(/&ni;|&#8715;|&#x220b;/g, '∋');
+str = str.replace(/&prod;|&#8719;|&#x220f;/g, '∏');
+str = str.replace(/&sum;|&#8721;|&#x2211;/g, '∑');
+str = str.replace(/&minus;|&#8722;|&#x2212;/g, '−');
+str = str.replace(/&lowast;|&#8727;|&#x2217;/g, '∗');
+str = str.replace(/&radic;|&#8730;|&#x221a;/g, '√');
+str = str.replace(/&prop;|&#8733;|&#x221d;/g, '∝');
+str = str.replace(/&infin;|&#8734;|&#x221e;/g, '∞');
+str = str.replace(/&ang;|&#8736;|&#x2220;/g, '∠');
+str = str.replace(/&and;|&#8743;|&#x2227;/g, '∧');
+str = str.replace(/&or;|&#8744;|&#x2228;/g, '∨');
+str = str.replace(/&cap;|&#8745;|&#x2229;/g, '∩');
+str = str.replace(/&cup;|&#8746;|&#x222a;/g, '∪');
+str = str.replace(/&int;|&#8747;|&#x222b;/g, '∫');
+str = str.replace(/&there4;|&#8756;|&#x2234;/g, '∴');
+str = str.replace(/&sim;|&#8764;|&#x223c;/g, '∼');
+str = str.replace(/&cong;|&#8773;|&#x2245;/g, '≅');
+str = str.replace(/&asymp;|&#8776;|&#x2248;/g, '≈');
+str = str.replace(/&ne;|&#8800;|&#x2260;/g, '≠');
+str = str.replace(/&le;|&#8804;|&#x2264;/g, '≤');
+str = str.replace(/&ge;|&#8805;|&#x2265;/g, '≥');
+str = str.replace(/&sub;|&#8834;|&#x2282;/g, '⊂');
+str = str.replace(/&sup;|&#8835;|&#x2283;/g, '⊃');
+str = str.replace(/&nsub;|&#8836;|&#x2284;/g, '⊄');
+str = str.replace(/&sube;|&#8838;|&#x2286;/g, '⊆');
+str = str.replace(/&supe;|&#8839;|&#x2287;/g, '⊇');
+str = str.replace(/&oplus;|&#8853;|&#x2295;/g, '⊕');
+str = str.replace(/&otimes;|&#8855;|&#x2297;/g, '⊗');
+str = str.replace(/&perp;|&#8869;|&#x22a5;/g, '⊥');
+str = str.replace(/&sdot;|&#8901;|&#x22c5;/g, '⋅');
+return str;
+}
+
+// HTML 支持的希腊字母
+function strGreeceDiscode(str) {
+str = str.replace(/&Alpha;|&#913;|&#x391;/g, 'Α');
+str = str.replace(/&Beta;|&#914;|&#x392;/g, 'Β');
+str = str.replace(/&Gamma;|&#915;|&#x393;/g, 'Γ');
+str = str.replace(/&Delta;|&#916;|&#x394;/g, 'Δ');
+str = str.replace(/&Epsilon;|&#917;|&#x395;/g, 'Ε');
+str = str.replace(/&Zeta;|&#918;|&#x396;/g, 'Ζ');
+str = str.replace(/&Eta;|&#919;|&#x397;/g, 'Η');
+str = str.replace(/&Theta;|&#920;|&#x398;/g, 'Θ');
+str = str.replace(/&Iota;|&#921;|&#x399;/g, 'Ι');
+str = str.replace(/&Kappa;|&#922;|&#x39a;/g, 'Κ');
+str = str.replace(/&Lambda;|&#923;|&#x39b;/g, 'Λ');
+str = str.replace(/&Mu;|&#924;|&#x39c;/g, 'Μ');
+str = str.replace(/&Nu;|&#925;|&#x39d;/g, 'Ν');
+str = str.replace(/&Xi;|&#925;|&#x39d;/g, 'Ν');
+str = str.replace(/&Omicron;|&#927;|&#x39f;/g, 'Ο');
+str = str.replace(/&Pi;|&#928;|&#x3a0;/g, 'Π');
+str = str.replace(/&Rho;|&#929;|&#x3a1;/g, 'Ρ');
+str = str.replace(/&Sigma;|&#931;|&#x3a3;/g, 'Σ');
+str = str.replace(/&Tau;|&#932;|&#x3a4;/g, 'Τ');
+str = str.replace(/&Upsilon;|&#933;|&#x3a5;/g, 'Υ');
+str = str.replace(/&Phi;|&#934;|&#x3a6;/g, 'Φ');
+str = str.replace(/&Chi;|&#935;|&#x3a7;/g, 'Χ');
+str = str.replace(/&Psi;|&#936;|&#x3a8;/g, 'Ψ');
+str = str.replace(/&Omega;|&#937;|&#x3a9;/g, 'Ω');
+
+str = str.replace(/&alpha;|&#945;|&#x3b1;/g, 'α');
+str = str.replace(/&beta;|&#946;|&#x3b2;/g, 'β');
+str = str.replace(/&gamma;|&#947;|&#x3b3;/g, 'γ');
+str = str.replace(/&delta;|&#948;|&#x3b4;/g, 'δ');
+str = str.replace(/&epsilon;|&#949;|&#x3b5;/g, 'ε');
+str = str.replace(/&zeta;|&#950;|&#x3b6;/g, 'ζ');
+str = str.replace(/&eta;|&#951;|&#x3b7;/g, 'η');
+str = str.replace(/&theta;|&#952;|&#x3b8;/g, 'θ');
+str = str.replace(/&iota;|&#953;|&#x3b9;/g, 'ι');
+str = str.replace(/&kappa;|&#954;|&#x3ba;/g, 'κ');
+str = str.replace(/&lambda;|&#955;|&#x3bb;/g, 'λ');
+str = str.replace(/&mu;|&#956;|&#x3bc;/g, 'μ');
+str = str.replace(/&nu;|&#957;|&#x3bd;/g, 'ν');
+str = str.replace(/&xi;|&#958;|&#x3be;/g, 'ξ');
+str = str.replace(/&omicron;|&#959;|&#x3bf;/g, 'ο');
+str = str.replace(/&pi;|&#960;|&#x3c0;/g, 'π');
+str = str.replace(/&rho;|&#961;|&#x3c1;/g, 'ρ');
+str = str.replace(/&sigmaf;|&#962;|&#x3c2;/g, 'ς');
+str = str.replace(/&sigma;|&#963;|&#x3c3;/g, 'σ');
+str = str.replace(/&tau;|&#964;|&#x3c4;/g, 'τ');
+str = str.replace(/&upsilon;|&#965;|&#x3c5;/g, 'υ');
+str = str.replace(/&phi;|&#966;|&#x3c6;/g, 'φ');
+str = str.replace(/&chi;|&#967;|&#x3c7;/g, 'χ');
+str = str.replace(/&psi;|&#968;|&#x3c8;/g, 'ψ');
+str = str.replace(/&omega;|&#969;|&#x3c9;/g, 'ω');
+str = str.replace(/&thetasym;|&#977;|&#x3d1;/g, 'ϑ');
+str = str.replace(/&upsih;|&#978;|&#x3d2;/g, 'ϒ');
+str = str.replace(/&piv;|&#982;|&#x3d6;/g, 'ϖ');
+str = str.replace(/&middot;|&#183;|&#xb7;/g, '·');
+return str;
+}
+
+function strcharacterDiscode(str) {
+// 加入常用解析
+
+// str = str.replace(/&nbsp;|&#32;|&#x20;/g, "&nbsp;");
+// str = str.replace(/&ensp;|&#8194;|&#x2002;/g, '&ensp;');
+// str = str.replace(/&#12288;|&#x3000;/g, '<span class=\'spaceshow\'> </span>');
+// str = str.replace(/&emsp;|&#8195;|&#x2003;/g, '&emsp;');
+// str = str.replace(/&quot;|&#34;|&#x22;/g, "\"");
+// str = str.replace(/&apos;|&#39;|&#x27;/g, "&apos;");
+// str = str.replace(/&acute;|&#180;|&#xB4;/g, "´");
+// str = str.replace(/&times;|&#215;|&#xD7;/g, "×");
+// str = str.replace(/&divide;|&#247;|&#xF7;/g, "÷");
+// str = str.replace(/&amp;|&#38;|&#x26;/g, '&amp;');
+// str = str.replace(/&lt;|&#60;|&#x3c;/g, '&lt;');
+// str = str.replace(/&gt;|&#62;|&#x3e;/g, '&gt;');
+
+
+
+
+str = str.replace(/&nbsp;|&#32;|&#x20;/g, "<span class='spaceshow'> </span>");
+str = str.replace(/&ensp;|&#8194;|&#x2002;/g, '<span class=\'spaceshow\'> </span>');
+str = str.replace(/&#12288;|&#x3000;/g, '<span class=\'spaceshow\'> </span>');
+str = str.replace(/&emsp;|&#8195;|&#x2003;/g, '<span class=\'spaceshow\'> </span>');
+str = str.replace(/&quot;|&#34;|&#x22;/g, "\"");
+str = str.replace(/&quot;|&#39;|&#x27;/g, "'");
+str = str.replace(/&acute;|&#180;|&#xB4;/g, "´");
+str = str.replace(/&times;|&#215;|&#xD7;/g, "×");
+str = str.replace(/&divide;|&#247;|&#xF7;/g, "÷");
+str = str.replace(/&amp;|&#38;|&#x26;/g, '&');
+str = str.replace(/&lt;|&#60;|&#x3c;/g, '<');
+str = str.replace(/&gt;|&#62;|&#x3e;/g, '>');
+return str;
+}
+
+// HTML 支持的其他实体
+function strOtherDiscode(str) {
+str = str.replace(/&OElig;|&#338;|&#x152;/g, 'Œ');
+str = str.replace(/&oelig;|&#339;|&#x153;/g, 'œ');
+str = str.replace(/&Scaron;|&#352;|&#x160;/g, 'Š');
+str = str.replace(/&scaron;|&#353;|&#x161;/g, 'š');
+str = str.replace(/&Yuml;|&#376;|&#x178;/g, 'Ÿ');
+str = str.replace(/&fnof;|&#402;|&#x192;/g, 'ƒ');
+str = str.replace(/&circ;|&#710;|&#x2c6;/g, 'ˆ');
+str = str.replace(/&tilde;|&#732;|&#x2dc;/g, '˜');
+str = str.replace(/&thinsp;|$#8201;|&#x2009;/g, '<span class=\'spaceshow\'> </span>');
+str = str.replace(/&zwnj;|&#8204;|&#x200C;/g, '<span class=\'spaceshow\'>‌</span>');
+str = str.replace(/&zwj;|$#8205;|&#x200D;/g, '<span class=\'spaceshow\'>‍</span>');
+str = str.replace(/&lrm;|$#8206;|&#x200E;/g, '<span class=\'spaceshow\'>‎</span>');
+str = str.replace(/&rlm;|&#8207;|&#x200F;/g, '<span class=\'spaceshow\'>‏</span>');
+str = str.replace(/&ndash;|&#8211;|&#x2013;/g, '–');
+str = str.replace(/&mdash;|&#8212;|&#x2014;/g, '—');
+str = str.replace(/&lsquo;|&#8216;|&#x2018;/g, '‘');
+str = str.replace(/&rsquo;|&#8217;|&#x2019;/g, '’');
+str = str.replace(/&sbquo;|&#8218;|&#x201a;/g, '‚');
+str = str.replace(/&ldquo;|&#8220;|&#x201c;/g, '“');
+str = str.replace(/&rdquo;|&#8221;|&#x201d;/g, '”');
+str = str.replace(/&bdquo;|&#8222;|&#x201e;/g, '„');
+str = str.replace(/&dagger;|&#8224;|&#x2020;/g, '†');
+str = str.replace(/&Dagger;|&#8225;|&#x2021;/g, '‡');
+str = str.replace(/&bull;|&#8226;|&#x2022;/g, '•');
+str = str.replace(/&hellip;|&#8230;|&#x2026;/g, '…');
+str = str.replace(/&permil;|&#8240;|&#x2030;/g, '‰');
+str = str.replace(/&prime;|&#8242;|&#x2032;/g, '′');
+str = str.replace(/&Prime;|&#8243;|&#x2033;/g, '″');
+str = str.replace(/&lsaquo;|&#8249;|&#x2039;/g, '‹');
+str = str.replace(/&rsaquo;|&#8250;|&#x203a;/g, '›');
+str = str.replace(/&oline;|&#8254;|&#x203e;/g, '‾');
+str = str.replace(/&euro;|&#8364;|&#x20ac;/g, '€');
+str = str.replace(/&trade;|&#8482;|&#x2122;/g, '™');
+str = str.replace(/&larr;|&#8592;|&#x2190;/g, '←');
+str = str.replace(/&uarr;|&#8593;|&#x2191;/g, '↑');
+str = str.replace(/&rarr;|&#8594;|&#x2192;/g, '→');
+str = str.replace(/&darr;|&#8595;|&#x2193;/g, '↓');
+str = str.replace(/&harr;|&#8596;|&#x2194;/g, '↔');
+str = str.replace(/&crarr;|&#8629;|&#x21b5;/g, '↵');
+str = str.replace(/&lceil;|&#8968;|&#x2308;/g, '⌈');
+str = str.replace(/&rceil;|&#8969;|&#x2309;/g, '⌉');
+str = str.replace(/&lfloor;|&#8970;|&#x230a;/g, '⌊');
+str = str.replace(/&rfloor;|&#8971;|&#x230b;/g, '⌋');
+str = str.replace(/&loz;|&#9674;|&#x25ca;/g, '◊');
+str = str.replace(/&spades;|&#9824;|&#x2660;/g, '♠');
+str = str.replace(/&clubs;|&#9827;|&#x2663;/g, '♣');
+str = str.replace(/&hearts;|&#9829;|&#x2665;/g, '♥');
+str = str.replace(/&diams;|&#9830;|&#x2666;/g, '♦');
+return str;
+}
+
+function strDiscode(str) {
+  str = strNumDiscode(str);
+  str = strGreeceDiscode(str);
+  str = strcharacterDiscode(str);
+  str = strOtherDiscode(str);
+  return str;
+}
+
+function urlToHttpUrl(url, domain) {
+  if (/^\/\//.test(url)) {
+    return `https:${url}`;
+  } else if (/^\//.test(url)) {
+    return `https://${domain}${url}`;
+  }
+  return url;
+}
+
+export default {
+  strDiscode,
+  urlToHttpUrl,
+};

+ 258 - 0
ctxx_xcx/components/gaoyia-parse/parse.css

@@ -0,0 +1,258 @@
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *         垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+/**
+ * 请在全局下引入该文件,@import '/static/wxParse.css';
+ */
+.wxParse {
+	user-select:none;
+	width: 100%;
+	font-family: Helvetica, "PingFangSC", 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
+	color: #333;
+	line-height: 1.5;
+	font-size: 1em;
+	text-align:justify;/* //左右两端对齐 */
+}
+.wxParse view ,.wxParse uni-view{
+	word-break: break-word;
+}
+.wxParse .p {
+	padding-bottom: 0.5em;
+	clear: both;
+	/* letter-spacing: 0;//字间距 */
+}
+.wxParse .inline {
+  display: inline;
+  margin: 0;
+  padding: 0;
+}
+
+.wxParse .div {
+  margin: 0;
+  padding: 0;
+  display: block;
+}
+
+.wxParse .h1{
+  font-size: 2em;
+  line-height: 1.2em;
+  margin: 0.67em 0;
+}
+.wxParse .h2{
+  font-size: 1.5em;
+  margin: 0.83em 0;
+}
+.wxParse .h3{
+  font-size: 1.17em;
+  margin: 1em 0;
+}
+.wxParse .h4{
+  margin: 1.33em 0;
+}
+.wxParse .h5{
+  font-size: 0.83em;
+  margin: 1.67em 0;
+}
+.wxParse .h6{
+  font-size: 0.83em;
+  margin: 1.67em 0;
+}
+
+.wxParse .h1,
+.wxParse .h2,
+.wxParse .h3,
+.wxParse .h4,
+.wxParse .h5,
+.wxParse .h6,
+.wxParse .b,
+.wxParse .strong{
+  font-weight: bolder;
+}
+
+.wxParse .i,
+.wxParse .cite,
+.wxParse .em,
+.wxParse .var,
+.wxParse .address {
+  font-style: italic;
+}
+.wxParse .spaceshow{
+	  white-space: pre;
+}
+.wxParse .pre,
+.wxParse .tt,
+.wxParse .code,
+.wxParse .kbd,
+.wxParse .samp {
+  font-family: monospace;
+}
+.wxParse .pre {
+  overflow: auto;
+  background: #f5f5f5;
+  padding: 16upx;
+  white-space: pre;
+  margin: 1em 0upx;
+  font-size: 24upx;
+}
+.wxParse .code {
+	overflow: auto;
+	padding: 16upx;
+	white-space: pre;
+	margin: 1em 0upx;
+	background: #f5f5f5;
+	font-size: 24upx;
+}
+
+.wxParse .big {
+  font-size: 1.17em;
+}
+
+.wxParse .small,
+.wxParse .sub,
+.wxParse .sup {
+  font-size: 0.83em;
+}
+
+.wxParse .sub {
+  vertical-align: sub;
+}
+.wxParse .sup {
+  vertical-align: super;
+}
+
+.wxParse .s,
+.wxParse .strike,
+.wxParse .del {
+  text-decoration: line-through;
+}
+
+.wxParse .strong,
+.wxParse .text,
+.wxParse .span,
+.wxParse .s {
+  display: inline;
+}
+
+.wxParse .a {
+  color: deepskyblue;
+}
+
+.wxParse .video {
+  text-align: center;
+  margin: 22upx 0;
+}
+
+.wxParse .video-video {
+  width: 100%;
+}
+.wxParse .uni-image{
+	max-width: 100%;
+}
+.wxParse .img {
+  display: block;
+  max-width: 100%;
+  margin-bottom: 0em;/* //与p标签底部padding同时修改 */
+  overflow: hidden;
+}
+
+.wxParse .blockquote {
+  margin: 10upx 0;
+  padding: 22upx 0 22upx 22upx;
+  font-family: Courier, Calibri, "宋体";
+  background: #f5f5f5;
+  border-left: 6upx solid #dbdbdb;
+}
+.wxParse .blockquote .p {
+  margin: 0;
+}
+.wxParse .ul, .wxParse .ol {
+  display: block;
+  margin: 1em 0;
+  padding-left: 2em;
+}
+.wxParse .ol {
+  list-style-type: disc;
+}
+.wxParse .ol {
+  list-style-type: decimal;
+}
+.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
+  display: list-item;
+  align-items: baseline;
+  text-align: match-parent;
+}
+
+.wxParse .ol>.li,.wxParse .ul>.li {
+  display: list-item;
+  align-items: baseline;
+  text-align: match-parent;
+}
+.wxParse .ul .ul, .wxParse .ol .ul {
+  list-style-type: circle;
+}
+.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
+    list-style-type: square;
+}
+
+.wxParse .u {
+  text-decoration: underline;
+}
+.wxParse .hide {
+  display: none;
+}
+.wxParse .del {
+  display: inline;
+}
+.wxParse .figure {
+  overflow: hidden;
+}
+.wxParse .tablebox{
+	overflow: auto;
+	background-color: #f5f5f5;
+	background: #f5f5f5;
+	font-size: 13px;
+	padding: 8px;
+}
+.wxParse .table .table,.wxParse .table{
+	border-collapse:collapse;
+	box-sizing: border-box;
+	/* 内边框 */
+	/* width: 100%; */
+	overflow: auto;
+	white-space: pre;
+}
+.wxParse .tbody{
+	border-collapse:collapse;
+	box-sizing: border-box;
+	/* 内边框 */
+	border: 1px solid #dadada;
+}
+.wxParse .table  .thead, .wxParse  .table .tfoot, .wxParse  .table .th{
+	border-collapse:collapse;
+	box-sizing: border-box;
+	background: #ececec;
+	font-weight: 40;
+}
+.wxParse  .table .tr {
+	border-collapse:collapse;
+	box-sizing: border-box;
+	/* border: 2px solid #F0AD4E; */
+	overflow:auto;
+}
+.wxParse  .table .th,
+.wxParse  .table .td{
+	border-collapse:collapse;
+	box-sizing: border-box;
+	border: 2upx solid #dadada;
+	overflow:auto;
+}
+.wxParse .audio, .wxParse .uni-audio-default{
+	display: block;
+}

+ 228 - 0
ctxx_xcx/components/gaoyia-parse/parse.vue

@@ -0,0 +1,228 @@
+<!--**
+ * forked from:https://github.com/F-loat/mpvue-wxParse
+ *
+ * github地址: https://github.com/dcloudio/uParse
+ *
+ * for: uni-app框架下 富文本解析
+ * 
+ * 优化 by gaoyia@qq.com  https://github.com/gaoyia/parse
+ */-->
+
+<template>
+	
+	<!--基础元素-->
+	<div class="wxParse" :class="className" :style="'user-select:' + userSelect">
+		<block v-for="(node, index) of nodes" :key="index" v-if="!loading">
+			<wxParseTemplate :node="node" />
+		</block>
+	</div>
+</template>
+
+<script>
+import HtmlToJson from './libs/html2json';
+import wxParseTemplate from './components/wxParseTemplate0';
+
+	
+	export default {
+		name: 'wxParse',
+		props: {
+			// user-select:none;
+			userSelect: {
+				type: String,
+				default: 'text' //none |text| all | element
+			},
+			imgOptions: {
+				type: [Object, Boolean],
+				default: function() {
+					return {
+						loop: false,
+						indicator: 'number',
+						longPressActions: false
+						// longPressActions: {
+						// 	 itemList: ['发送给朋友', '保存图片', '收藏'],
+						// 		success: function (res) {
+						// 			console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
+						// 		},
+						// 		fail: function (res) {
+						// 			console.log(res.errMsg);
+						// 		}    
+						// 	}
+						// }
+					}
+				}
+			},
+			loading: {
+				type: Boolean,
+				default: false
+			},
+			className: {
+				type: String,
+				default: ''
+			},
+			content: {
+				type: String,
+				default: ''
+			},
+			noData: {
+				type: String,
+				default: '<div style="color: red;">数据不能为空</div>'
+			},
+			startHandler: {
+				type: Function,
+				default () {
+					return node => {
+						node.attr.class = null;
+						node.attr.style = null;
+					};
+				}
+			},
+			endHandler: {
+				type: Function,
+				default: null
+			},
+			charsHandler: {
+				type: Function,
+				default: null
+			},
+			imageProp: {
+				type: Object,
+				default () {
+					return {
+						mode: 'aspectFit',
+						padding: 0,
+						lazyLoad: false,
+						domain: ''
+					};
+				}
+			}
+		},
+		components: {
+			wxParseTemplate
+		},
+		data() {
+			return {
+				nodes: {},
+				imageUrls: [],
+				wxParseWidth: {
+					value: 0
+				}
+			};
+		},
+		computed: {},
+		mounted() {
+			this.setHtml()
+		},
+		methods: {
+			setHtml() {
+				this.getWidth().then((data) => {
+					this.wxParseWidth.value = data;
+				})
+				let {
+					content,
+					noData,
+					imageProp,
+					startHandler,
+					endHandler,
+					charsHandler
+				} = this;
+				let parseData = content || noData;
+				let customHandler = {
+					start: startHandler,
+					end: endHandler,
+					chars: charsHandler
+				};
+				let results = HtmlToJson(parseData, customHandler, imageProp, this);
+
+				this.imageUrls = results.imageUrls;
+				// this.nodes = results.nodes;
+				
+				
+				this.nodes = [];
+				results.nodes.forEach((item) => {
+					setTimeout(() => {
+						this.nodes.push(item)
+					}, 0);
+				})
+			},
+			getWidth() {
+				return new Promise((res, rej) => {
+					// #ifndef MP-ALIPAY || MP-BAIDU
+					uni.createSelectorQuery()
+						.in(this)
+						.select('.wxParse')
+						.fields({
+								size: true,
+								scrollOffset: true
+							},
+							data => {
+								res(data.width);
+							}
+						).exec();
+					// #endif
+					// #ifdef MP-BAIDU
+					const query = swan.createSelectorQuery();
+					query.select('.wxParse').boundingClientRect();
+					query.exec(obj => {
+						const rect = obj[0]
+						if (rect) {
+							res(rect.width);
+						}
+					});
+					// #endif
+					// #ifdef MP-ALIPAY
+					my.createSelectorQuery()
+						.select('.wxParse')
+						.boundingClientRect().exec((ret) => {
+							res(ret[0].width);
+						});
+					// #endif
+				});
+			},
+			navigate(href, $event, attr) {
+				console.log(href, attr);
+				this.$emit('navigate', href, $event);
+			},
+			preview(src, $event) {
+				if (!this.imageUrls.length || typeof this.imgOptions === 'boolean') {
+
+				} else {
+					uni.previewImage({
+						current: src,
+						urls: this.imageUrls,
+						loop: this.imgOptions.loop,
+						indicator: this.imgOptions.indicator,
+						longPressActions: this.imgOptions.longPressActions
+					});
+				}
+				this.$emit('preview', src, $event);
+			},
+			removeImageUrl(src) {
+				const {
+					imageUrls
+				} = this;
+				imageUrls.splice(imageUrls.indexOf(src), 1);
+			}
+		},
+		// 父组件中提供
+		provide() {
+			return {
+				parseWidth: this.wxParseWidth,
+				parseSelect: this.userSelect
+				// 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
+			};
+		},
+		watch: {
+			content(){
+				this.setHtml()
+			}
+			// content: {
+			// 	handler: function(newVal, oldVal) {
+			// 		if (newVal !== oldVal) {
+			// 			
+			// 		}
+			// 	},
+			// 	deep: true
+			// }
+		}
+	};
+</script>

+ 79 - 0
ctxx_xcx/components/nav-bar/nav-bar.vue

@@ -0,0 +1,79 @@
+<template>
+  <view class="nav-bar" v-if="list!=''">
+    <view class="nav-bar-list" v-for="(item,index) in list" @click="navTap(item.path)">
+      <view class="imgs" v-if="navIndex!=index">
+        <image :src="item.image"></image>
+      </view>
+      <view class="imgs" v-else>
+        <image :src="item.sel_img"></image>
+      </view> 
+      <view class="texts"  :class="navIndex==index?'classStyle':''">{{item.name}}</view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'HeaderViewBar',
+  props: {
+    navIndex: {
+      type: Number,
+    },
+  },
+  data() {
+    return {
+      list:[
+        {"name":"首页","image":"../../static/index/index_nav_icon.png","id":1,"path":"/pages/index/index","sel_img":"../../static/index/index_nav_icon_sel.png"},
+        {"name":"商城","image":"../../static/index/shop_icon.png","id":2,"path":"/pages/shop/index","sel_img":"../../static/index/shop_icon_sel.png"},
+        {"name":"我的","image":"../../static/index/mine_icon.png","id":3,"path":"/pages/mine/index","sel_img":"../../static/index/mine_icon_sel.png"}
+      ]
+    };
+  },
+  created() {
+
+  },
+  methods: {
+    navTap(url,index){
+      uni.reLaunch({
+        url:url
+      })
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.classStyle{
+  color: #222!important;
+}
+.nav-bar{
+  position: fixed;
+  bottom: 0;
+  background-color: #fff;
+  height: 130rpx;
+  width: 100%;
+  padding-top: 20rpx;
+  left: 0;
+  display: flex;
+  z-index: 9999;
+  .nav-bar-list{
+    // display: flex;
+    justify-content: center;
+    align-items: center;
+    text-align: center;
+    flex:1;
+    .imgs{
+      image{
+        height: 52rpx;
+        width: 52rpx;
+      }
+
+    }
+    .texts{
+      font-size: 20rpx;
+      color: #999999;
+    }
+
+  }
+}
+</style>

+ 137 - 0
ctxx_xcx/components/pick-regions/pick-regions.vue

@@ -0,0 +1,137 @@
+<template>
+    <picker mode="multiSelector" 
+            :value="multiIndex" 
+            :range="multiArray" 
+            @change="handleValueChange"
+            @columnchange="handleColumnChange">
+        <slot></slot>
+    </picker>
+</template>
+
+<script>
+    const CHINA_REGIONS = require('./regions.json')
+	export default {
+        props:{
+            defaultRegions:{
+                type:Array,
+                default(){
+                    return []
+                }
+            },
+            defaultRegionCode:{
+                type:String
+            },
+            defaultRegion:[String,Array]
+        },
+		data() {
+			return {
+                cityArr:CHINA_REGIONS[0].childs,
+                districtArr:CHINA_REGIONS[0].childs[0].childs,
+                multiIndex: [0, 0, 0],
+                isInitMultiArray:true,
+			}
+		},
+        watch:{
+            defaultRegion:{
+                handler(region,oldRegion){
+                    if(Array.isArray(region)){
+                        // 避免传的是字面量的时候重复触发
+                        oldRegion = oldRegion || []
+                        if(region.join('')!==oldRegion.join('')){
+                            this.handleDefaultRegion(region)
+                        }
+                    }else if(region&&region.length == 6){
+                        this.handleDefaultRegion(region)
+                    }else{
+                        console.warn('defaultRegion非有效格式')
+                    }
+                },
+                immediate:true,
+            }
+        },
+        computed:{
+            multiArray(){
+                return this.pickedArr.map(arr=>arr.map(item=>item.name))
+            },
+            pickedArr(){
+                // 进行初始化
+                if(this.isInitMultiArray){
+                    return [
+                        CHINA_REGIONS,
+                        CHINA_REGIONS[0].childs,
+                        CHINA_REGIONS[0].childs[0].childs
+                    ]
+                }
+                return [CHINA_REGIONS,this.cityArr,this.districtArr];
+            }
+        },
+		methods: {
+            handleColumnChange(e){
+                // console.log(e);
+                this.isInitMultiArray = false;
+                const that = this;
+                let col = e.detail.column;
+                let row = e.detail.value;
+                that.multiIndex[col] = row;
+                try{
+                    switch(col){
+                        case 0:
+                            if(CHINA_REGIONS[that.multiIndex[0]].childs.length==0){
+                                that.cityArr = that.districtArr = [CHINA_REGIONS[that.multiIndex[0]]]
+                                break;
+                            }
+                            that.cityArr = CHINA_REGIONS[that.multiIndex[0]].childs
+                            that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[that.multiIndex[1]].childs
+                            break;
+                        case 1:
+                            that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[that.multiIndex[1]].childs
+                            break;
+                        case 2:
+                            break;
+                    }
+                }catch(e){
+                    // console.log(e);
+                    that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[0].childs
+                }
+                
+            },
+            handleValueChange(e){
+                // 结构赋值
+                let [index0,index1,index2] = e.detail.value;
+                let [arr0,arr1,arr2] = this.pickedArr;
+                let address = [arr0[index0],arr1[index1],arr2[index2]];
+                // console.log(address);
+                this.$emit('getRegion',address)
+            },
+            handleDefaultRegion(region){
+                const isCode = !Array.isArray(region)
+                this.isInitMultiArray = false;
+                let children = CHINA_REGIONS
+                for(let i=0;i<3;i++){
+                    for(let j=0;j<children.length;j++){
+                       let condition = isCode?children[j].code==region.slice(0,(i+1)*2):children[j].name.includes(region[i]);
+                       if(condition){
+                           // 匹配成功进行赋值
+                           // console.log(i,j,children.length-1);
+                           children = children[j].childs;
+                           if(i==0){
+                               this.cityArr = children
+                           }else if(i==1){
+                               this.districtArr = children
+                           }
+                           this.$set(this.multiIndex,i,j)
+                           // console.log(this.multiIndex);
+                           break;
+                       }else{
+                           // 首次匹配失败就用默认的初始化
+                           // console.log(i,j,children.length-1);
+                           if(i==0 && j==(children.length-1)){
+                               this.isInitMultiArray = true;
+                           }
+                       }
+                    }
+                }
+            }
+		},
+	}
+</script>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
ctxx_xcx/components/pick-regions/regions.json


+ 1247 - 0
ctxx_xcx/components/three-level-linkage/data-info/level-data.js

@@ -0,0 +1,1247 @@
+/* eslint-disable */
+var allData = [
+            {
+                "id":"1",
+                "name":"北京",
+                "code":"11",
+				"children":[
+					{
+					    "id":"1230040276324601858",
+					    "name":"北京大学",
+					    "code":"10001",
+						"children":[
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144593367408641",
+							    "name":"广播电视",
+							    "code":"guangbodianshi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							}
+						]
+					},
+					{
+					    "id":"1230040276500762626",
+					    "name":"清华大学",
+					    "code":"10003",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144272230522882",
+							    "name":"雕塑",
+							    "code":"diaosu"
+							},
+							{
+							    "id":"1219144319747792898",
+							    "name":"动漫",
+							    "code":"dongman"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144412131532802",
+							    "name":"服装设计",
+							    "code":"fuzhuangsheji"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144498089598978",
+							    "name":"工艺美术",
+							    "code":"gongyimeishu"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219144789576949761",
+							    "name":"绘画",
+							    "code":"huihua"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145078623215618",
+							    "name":"科普硕士",
+							    "code":"kepushuoshi"
+							},
+							{
+							    "id":"1219145224144592897",
+							    "name":"染织设计",
+							    "code":"ranzhisheji"
+							},
+							{
+							    "id":"1219145386988445697",
+							    "name":"摄影",
+							    "code":"sheying"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145533864583169",
+							    "name":"书法",
+							    "code":"shufa"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1227896860333654018",
+							    "name":"陶瓷陶艺",
+							    "code":"taocitaoyi"
+							},
+							{
+							    "id":"1219145760835149826",
+							    "name":"文物修复",
+							    "code":"wenwuxiufu"
+							},
+							{
+							    "id":"1219145971510845442",
+							    "name":"信息设计",
+							    "code":"xinxisheji"
+							},
+							{
+							    "id":"1219146010878582785",
+							    "name":"信息艺术设计",
+							    "code":"xinxiyishusheji"
+							},
+							{
+							    "id":"1219146055183015938",
+							    "name":"艺术管理",
+							    "code":"yishuguanli"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							},
+							{
+							    "id":"1219146300742737922",
+							    "name":"造型设计",
+							    "code":"zaoxingsheji"
+							},
+							{
+							    "id":"1219146338717966338",
+							    "name":"展示设计",
+							    "code":"zhanshisheji"
+							}
+						]
+					},
+					{
+					    "id":"1230040276454625281",
+					    "name":"北京航空航天大学",
+					    "code":"10006",
+						"children":[
+							{
+							    "id":"1219144319747792898",
+							    "name":"动漫",
+							    "code":"dongman"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144789576949761",
+							    "name":"绘画",
+							    "code":"huihua"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							}
+						]
+					},
+					{
+					    "id":"1230040276454625282",
+					    "name":"北京理工大学",
+					    "code":"10007",
+						"children":[
+							{
+							    "id":"1227895075556638722",
+							    "name":"不区分",
+							    "code":"buqufen"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145424410025986",
+							    "name":"实验艺术",
+							    "code":"shiyanyishu"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1219146259248488450",
+							    "name":"油画",
+							    "code":"youhua"
+							}
+						]
+					},
+					{
+					    "id":"1230040276458819585",
+					    "name":"北京师范大学",
+					    "code":"10027",
+						"children":[
+							{
+							    "id":"1219144237023535106",
+							    "name":"电影",
+							    "code":"dianying"
+							},
+							{
+							    "id":"1219144272230522882",
+							    "name":"雕塑",
+							    "code":"diaosu"
+							},
+							{
+							    "id":"1219144593367408641",
+							    "name":"广播电视",
+							    "code":"guangbodianshi"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144789576949761",
+							    "name":"绘画",
+							    "code":"huihua"
+							},
+							{
+							    "id":"1219145797497561090",
+							    "name":"舞蹈",
+							    "code":"wudao"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							},
+							{
+							    "id":"1219146169012232194",
+							    "name":"音乐",
+							    "code":"yinyue"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							},
+							{
+							    "id":"1219146259248488450",
+							    "name":"油画",
+							    "code":"youhua"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"2",
+                "name":"天津",
+                "code":"12",
+				"children":[
+					{
+					    "id":"1230040276496568322",
+					    "name":"南开大学",
+					    "code":"10055",
+						"children":[
+							{
+							    "id":"1219144412131532802",
+							    "name":"服装设计",
+							    "code":"fuzhuangsheji"
+							},
+							{
+							    "id":"1219144547225870338",
+							    "name":"公共艺术",
+							    "code":"gonggongyishu"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219144789576949761",
+							    "name":"绘画",
+							    "code":"huihua"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							}
+						]
+					},
+					{
+					    "id":"1230040276509151235",
+					    "name":"天津大学",
+					    "code":"10056",
+						"children":[
+							{
+							    "id":"1227895075556638722",
+							    "name":"不区分",
+							    "code":"buqufen"
+							},
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"6",
+                "name":"辽宁省",
+                "code":"21",
+				"children":[
+					{
+					    "id":"1230040276458819586",
+					    "name":"大连理工大学",
+					    "code":"10141",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219144789576949761",
+							    "name":"绘画",
+							    "code":"huihua"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							}
+						]
+					},
+					{
+					    "id":"1230040276467208193",
+					    "name":"东北大学",
+					    "code":"10145",
+						"children":[
+							{
+							    "id":"1219144498089598978",
+							    "name":"工艺美术",
+							    "code":"gongyimeishu"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"7",
+                "name":"吉林省",
+                "code":"22",
+				"children":[
+					{
+					    "id":"1230040276492374018",
+					    "name":"吉林大学",
+					    "code":"10183",
+						"children":[
+							{
+							    "id":"1227895075556638722",
+							    "name":"不区分",
+							    "code":"buqufen"
+							},
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"8",
+                "name":"黑龙江省",
+                "code":"23",
+				"children":[
+					{
+					    "id":"1230040276479791107",
+					    "name":"哈尔滨工业大学",
+					    "code":"10213",
+						"children":[
+							{
+							    "id":"1227895075556638722",
+							    "name":"不区分",
+							    "code":"buqufen"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144498089598978",
+							    "name":"工艺美术",
+							    "code":"gongyimeishu"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"9",
+                "name":"上海",
+                "code":"31",
+				"children":[
+					{
+					    "id":"1230040276479791106",
+					    "name":"复旦大学",
+					    "code":"10246",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145345833934850",
+							    "name":"设计学(工科)",
+							    "code":"shejixuegongke"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							}
+						]
+					},
+					{
+					    "id":"1230040276513345537",
+					    "name":"同济大学",
+					    "code":"10247",
+						"children":[
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							}
+						]
+					},
+					{
+					    "id":"1230040276509151233",
+					    "name":"上海交通大学",
+					    "code":"10248",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							}
+						]
+					},
+					{
+					    "id":"1230040276483985410",
+					    "name":"华东师范大学",
+					    "code":"10269",
+						"children":[
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144547225870338",
+							    "name":"公共艺术",
+							    "code":"gonggongyishu"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145018980212738",
+							    "name":"景观设计",
+							    "code":"jingguansheji"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							},
+							{
+							    "id":"1219146055183015938",
+							    "name":"艺术管理",
+							    "code":"yishuguanli"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"10",
+                "name":"江苏省",
+                "code":"32",
+				"children":[
+					{
+					    "id":"1230040276496568321",
+					    "name":"南京大学",
+					    "code":"10284",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144593367408641",
+							    "name":"广播电视",
+							    "code":"guangbodianshi"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219145116258705409",
+							    "name":"美术教育",
+							    "code":"meishujiaoyu"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							},
+							{
+							    "id":"1219146169012232194",
+							    "name":"音乐",
+							    "code":"yinyue"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							}
+						]
+					},
+					{
+					    "id":"1230040276471402497",
+					    "name":"东南大学",
+					    "code":"10286",
+						"children":[
+							{
+							    "id":"1219144272230522882",
+							    "name":"雕塑",
+							    "code":"diaosu"
+							},
+							{
+							    "id":"1219145148403851265",
+							    "name":"美术史",
+							    "code":"meishushi"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"13",
+                "name":"福建省",
+                "code":"35",
+				"children":[
+					{
+					    "id":"1230040276504956930",
+					    "name":"厦门大学",
+					    "code":"10384",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145018980212738",
+							    "name":"景观设计",
+							    "code":"jingguansheji"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							},
+							{
+							    "id":"1219146259248488450",
+							    "name":"油画",
+							    "code":"youhua"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"15",
+                "name":"山东省",
+                "code":"37",
+				"children":[
+					{
+					    "id":"1230040276504956931",
+					    "name":"山东大学",
+					    "code":"10422",
+						"children":[
+							{
+							    "id":"1219144498089598978",
+							    "name":"工艺美术",
+							    "code":"gongyimeishu"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1219145569100931073",
+							    "name":"数字媒体",
+							    "code":"shuzimeiti"
+							},
+							{
+							    "id":"1219145843601350658",
+							    "name":"戏剧影视",
+							    "code":"xijuyingshi"
+							},
+							{
+							    "id":"1219146169012232194",
+							    "name":"音乐",
+							    "code":"yinyue"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"18",
+                "name":"湖南省",
+                "code":"43",
+				"children":[
+					{
+					    "id":"1230040276483985409",
+					    "name":"湖南大学",
+					    "code":"10532",
+						"children":[
+							{
+							    "id":"1227895075556638722",
+							    "name":"不区分",
+							    "code":"buqufen"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219145148403851265",
+							    "name":"美术史",
+							    "code":"meishushi"
+							},
+							{
+							    "id":"1219145345833934850",
+							    "name":"设计学(工科)",
+							    "code":"shejixuegongke"
+							},
+							{
+							    "id":"1219145386988445697",
+							    "name":"摄影",
+							    "code":"sheying"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1219145717432492034",
+							    "name":"文创设计",
+							    "code":"wenchuangsheji"
+							},
+							{
+							    "id":"1219146169012232194",
+							    "name":"音乐",
+							    "code":"yinyue"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"19",
+                "name":"广东省",
+                "code":"44",
+				"children":[
+					{
+					    "id":"1230040276488179714",
+					    "name":"华南理工大学",
+					    "code":"10561",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219144940915826689",
+							    "name":"交互设计",
+							    "code":"jiaohusheji"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"23",
+                "name":"四川省",
+                "code":"51",
+				"children":[
+					{
+					    "id":"1230040276509151234",
+					    "name":"四川大学",
+					    "code":"10610",
+						"children":[
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144547225870338",
+							    "name":"公共艺术",
+							    "code":"gonggongyishu"
+							},
+							{
+							    "id":"1219144454728884225",
+							    "name":"工业设计",
+							    "code":"gongyesheji"
+							},
+							{
+							    "id":"1219144667669504001",
+							    "name":"环境设计",
+							    "code":"huanjingsheji"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145345833934850",
+							    "name":"设计学(工科)",
+							    "code":"shejixuegongke"
+							},
+							{
+							    "id":"1227896860333654018",
+							    "name":"陶瓷陶艺",
+							    "code":"taocitaoyi"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1227895184327524353",
+							    "name":"音乐舞蹈",
+							    "code":"yinyuewudao"
+							}
+						]
+					}
+				]
+            },
+            {
+                "id":"28",
+                "name":"甘肃省",
+                "code":"62",
+				"children":[
+					{
+					    "id":"1230040276492374019",
+					    "name":"兰州大学",
+					    "code":"10730",
+						"children":[
+							{
+							    "id":"1219143897435906050",
+							    "name":"壁画",
+							    "code":"bihua"
+							},
+							{
+							    "id":"1227895285913567233",
+							    "name":"城乡规划(城市规划)",
+							    "code":"chengxiangguihua"
+							},
+							{
+							    "id":"1219144373145477122",
+							    "name":"风景园林",
+							    "code":"fengjingyuanlin"
+							},
+							{
+							    "id":"1219144412131532802",
+							    "name":"服装设计",
+							    "code":"fuzhuangsheji"
+							},
+							{
+							    "id":"1219144628058497025",
+							    "name":"国画",
+							    "code":"guohua"
+							},
+							{
+							    "id":"1219144708824014849",
+							    "name":"环境艺术",
+							    "code":"huanjingyishu"
+							},
+							{
+							    "id":"1219144866961858562",
+							    "name":"建筑史",
+							    "code":"jianzhushi"
+							},
+							{
+							    "id":"1219144901711667202",
+							    "name":"建筑学",
+							    "code":"jianzhuxue"
+							},
+							{
+							    "id":"1219145018980212738",
+							    "name":"景观设计",
+							    "code":"jingguansheji"
+							},
+							{
+							    "id":"1219145148403851265",
+							    "name":"美术史",
+							    "code":"meishushi"
+							},
+							{
+							    "id":"1219145280591536130",
+							    "name":"设计史",
+							    "code":"shejishi"
+							},
+							{
+							    "id":"1219145461957435394",
+							    "name":"视觉传达",
+							    "code":"shijuechuanda"
+							},
+							{
+							    "id":"1227895002827407361",
+							    "name":"停招",
+							    "code":"tingzhao"
+							},
+							{
+							    "id":"1219146134597967873",
+							    "name":"艺术学理论",
+							    "code":"yishuxuelilun"
+							}
+						]
+					}
+				]
+            }
+        ]
+
+export default allData;

+ 443 - 0
ctxx_xcx/components/three-level-linkage/linkage.nvue

@@ -0,0 +1,443 @@
+<template>
+	<view class="linkage" v-if="showPopup" @touchmove.stop.prevent="clear">
+		<!-- 遮罩层 -->
+		<view class="linkage-mask" @touchmove.stop.prevent="clear" v-if="maskClick" :class="[ani+'-mask', animation ? 'mask-ani' : '']" :style="{
+					'background-color': maskBgColor
+				}"
+		 @tap="hideMask(true)"></view>
+
+		<view class="linkage-content linkage--fixed" :class="[type,ani+'-content', animation ? 'content-ani' : '']">
+			<view class="linkage__header">
+				<view class="linkage__header-btn-box" @click="pickerCancel">
+					<text class="linkage__header-text">取消</text>
+				</view>
+				<view class="linkage__header-btn-box" @click="pickerConfirm">
+					<text class="linkage__header-text" :style="{color:themeColor}">确定</text>
+				</view>
+			</view>
+			<view class="linkage__box">
+				<picker-view indicator-style="height: 70rpx;" class="linkage-view" :value="pickerValue" @change="pickerChange">
+
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" v-for="(item,index) in firstLevel" :key="index">{{item.name}}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" v-for="(item,index) in firstLevel" :key="index">{{item.name}}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column v-if="secondShow">
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" v-for="(item,index) in secondLevel" :key="index">{{item.name}}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" v-for="(item,index) in secondLevel" :key="index">{{item.name}}</text>
+						<!-- #endif -->
+
+					</picker-view-column>
+					<picker-view-column v-if="thirdShow">
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" v-for="(item,index) in thirdLevel" :key="index">{{item.name}}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" v-for="(item,index) in thirdLevel" :key="index">{{item.name}}</text>
+						<!-- #endif -->
+
+					</picker-view-column>
+
+				</picker-view>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "levelLinkage",
+		props: {
+			allData: {
+				type: Array,
+				default: []
+			},
+			// 开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			/* 弹出层类型,可选值;
+				bottom:底部弹出层
+			*/
+			type: {
+				type: String,
+				default: 'bottom'
+			},
+			// maskClick
+			maskClick: {
+				type: Boolean,
+				default: true
+			},
+			show: {
+				type: Boolean,
+				default: true
+			},
+			maskBgColor: {
+				type: String,
+				default: 'rgba(0, 0, 0, 0.4)', //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
+			},
+			themeColor: {
+				type: String,
+				default: '', // 主题色
+			},
+			/* 默认值 */
+			pickerValueDefault: {
+				type: Array,
+				default () {
+					return [0, 0, 0]
+				}
+			},
+		},
+		data() {
+			return {
+				secondShow: false,
+				thirdShow: false,
+				ani: '',
+				showPopup: false,
+				pickerValue: [0, 0, 0],
+				firstLevel: [],
+				secondLevel: [],
+				thirdLevel: [],
+				emptyList: [
+					{
+						id: "",
+						name: "",
+						code: "",
+						"children":[]
+					}
+				]
+			}
+		},
+		watch: {
+			show(newValue) {
+				if (newValue) {
+					this.open()
+				} else {
+					this.close()
+				}
+			},
+			pickerValueDefault() {
+				this.init();
+			}
+		},
+		created() {
+			this.init()
+		},
+		methods: {
+			init() {
+				this.handPickValueDefault(); // 对 pickerValueDefault 做兼容处理
+				this.firstLevel = this.allData;
+				
+				this.secondShow = this.pickerValueDefault[1] >= 0 ? true : false;
+				this.thirdShow = this.pickerValueDefault[2] >= 0 ? true : false;;
+				if(this.secondShow){
+					this.secondLevel = this.firstLevel[this.pickerValueDefault[0]].children.length == 0
+						? this.emptyList : this.firstLevel[this.pickerValueDefault[0]].children;
+				}else{
+					this.thirdShow = false;
+				}
+				
+				if(this.thirdShow){
+					this.thirdLevel = this.secondLevel[this.pickerValueDefault[1]].children.length == 0
+						? this.emptyList : this.secondLevel[this.pickerValueDefault[1]].children;
+				}
+				
+				this.pickerValue = this.pickerValueDefault;
+			},
+			handPickValueDefault() {
+				if (this.pickerValueDefault !== [0, 0, 0]) {
+					if (this.pickerValueDefault[0] > this.allData.length - 1) {
+						this.pickerValueDefault[0] = this.allData.length - 1;
+					}
+					if (this.secondShow && this.pickerValueDefault[1] > this.allData[this.pickerValueDefault[0]].children.length - 1) {
+						this.pickerValueDefault[1] = this.allData[this.pickerValueDefault[0]].children.length - 1;
+					}
+					if (this.thirdShow &&
+						this.pickerValueDefault[2] > 
+									this.allData[this.pickerValueDefault[0]].children[this.pickerValueDefault[1]].children.length - 1) {
+						this.pickerValueDefault[2] 
+									= this.allData[this.pickerValueDefault[0]].children[this.pickerValueDefault[1]].children.length - 1;
+					}
+				}
+			},
+			pickerChange(e) {
+				let changePickerValue = e.detail.value;
+				if (this.pickerValue[0] !== changePickerValue[0]) {
+					// 第一级发生滚动
+					if(this.secondShow){
+						this.secondLevel = this.firstLevel[changePickerValue[0]].children.length == 0 
+							? this.emptyList : this.firstLevel[changePickerValue[0]].children;
+						changePickerValue[1] = 0;
+					}
+					
+					if(this.thirdShow){
+						this.thirdLevel = this.secondLevel[0].children.length == 0 
+							? this.emptyList : this.secondLevel[0].children;
+						changePickerValue[2] = 0;
+					}
+				} else if (this.pickerValue[1] !== changePickerValue[1]) {
+					// 第二级滚动
+					if(this.thirdShow){
+						this.thirdLevel = this.secondLevel[changePickerValue[1]].children == 0 
+							? this.emptyList : this.secondLevel[changePickerValue[1]].children;
+						changePickerValue[2] = 0;
+					}
+				}
+				this.pickerValue = changePickerValue;
+				this._$emit('onChange');
+			},
+			_$emit(emitName) {
+				// 自定义选中项,选中内容
+				let firstPick = {};
+				let secondPick = {};
+				let thirdPick = {};
+				
+				firstPick = {
+					id: this._getFirst().id,
+					name: this._getFirst().name,
+					code: this._getFirst().code
+				}
+				if(this.secondShow){
+					secondPick = {
+						id: this._getSecond().id,
+						name: this._getSecond().name,
+						code: this._getSecond().code
+					}
+				}
+				
+				if(this.thirdShow){
+					thirdPick = {
+						id: this._getThird().id,
+						name: this._getThird().name,
+						code: this._getThird().code
+					}
+				}
+				
+				let pickObj = {
+					name: this._getLabel(),
+					value: this.pickerValue,
+					secondPick: secondPick,
+					thirdPick: thirdPick,
+					firstPick: firstPick
+				};
+				this.$emit(emitName, pickObj);
+			},
+			_getLabel() {
+				let pcikerLabel = 
+					this.firstLevel[this.pickerValue[0]].name;
+					
+				if(this.secondShow){
+					pcikerLabel = pcikerLabel + '-' +
+					this.secondLevel[this.pickerValue[1]].name
+				}
+				
+				if(this.thirdShow){
+					pcikerLabel = pcikerLabel + '-' +
+					this.thirdLevel[this.pickerValue[2]].name;
+				}
+					
+				return pcikerLabel;
+			},
+			_getSecond() {
+				if(this.secondShow){
+					return this.secondLevel[this.pickerValue[1]];
+				}
+				return this.emptyList;
+			},
+			_getFirst() {
+				return this.firstLevel[this.pickerValue[0]];
+			},
+			_getThird() {
+				if(this.thirdShow){
+					return this.thirdLevel[this.pickerValue[2]];
+				}
+				return this.emptyList;
+			},
+			clear() {
+
+			},
+			hideMask() {
+				this._$emit('onCancel');
+				this.close();
+			},
+			pickerCancel() {
+				this._$emit('onCancel');
+				this.close();
+			},
+			pickerConfirm() {
+				this._$emit('onConfirm');
+				this.close();
+			},
+			open() {
+				this.showPopup = true
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.ani = 'linkage-c-' + this.type
+					}, 100)
+				})
+			},
+			close(type) {
+				if (!this.maskClick && type) return;
+				this.ani = ''
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.linkage {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+	}
+
+	.linkage-mask {
+		position: fixed;
+		bottom: 0;
+		top: 0;
+		left: 0;
+		right: 0;
+
+		transition-property: opacity;
+		transition-duration: 0.3s;
+		opacity: 0;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+
+	.mask-ani {
+		transition-property: opacity;
+		transition-duration: 0.2s;
+	}
+
+	.linkage-c-bottom-mask {
+		opacity: 1;
+	}
+
+	.linkage-c-center-mask {
+		opacity: 1;
+	}
+
+	.linkage--fixed {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transform: translateY(460rpx);
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.linkage-content {
+		background-color: #FFFFFF;
+	}
+
+	.linkage-c-content-bottom {
+		bottom: 0;
+		left: 0;
+		right: 0;
+		transform: translateY(500rpx);
+	}
+
+	.content-ani {
+		transition-property: transform, opacity;
+		transition-duration: 0.2s;
+	}
+
+	.linkage-c-bottom-content {
+		transform: translateY(0);
+	}
+
+	.linkage-c-center-content {
+		transform: scale(1);
+		opacity: 1;
+	}
+
+	.linkage__header {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: nowrap;
+		justify-content: space-between;
+		border-bottom-color: #f2f2f2;
+		border-bottom-style: solid;
+		border-bottom-width: 1rpx;
+	}
+
+	.linkage--fixed-top {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: space-between;
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 1rpx;
+	}
+
+	.linkage__header-btn-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		height: 70rpx;
+	}
+
+	.linkage__header-text {
+		text-align: center;
+		font-size: $uni-font-size-base;
+		color: #1aad19;
+		line-height: 70rpx;
+		padding-left: 40rpx;
+		padding-right: 40rpx;
+	}
+
+	.linkage__box {
+		position: relative;
+	}
+
+	.linkage-view {
+		position: relative;
+		bottom: 0;
+		left: 0;
+		/* #ifndef APP-NVUE */
+		width: 100%;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		width: 750rpx;
+		/* #endif */
+		height: 408rpx;
+		background-color: rgba(255, 255, 255, 1);
+	}
+
+	.picker-item {
+		text-align: center;
+		line-height: 70rpx;
+		text-overflow: ellipsis;
+		font-size: 28rpx;
+	}
+</style>

+ 24 - 0
ctxx_xcx/components/wyb-noticeBar/iconfont.css

@@ -0,0 +1,24 @@
+@font-face {font-family: "iconfont";
+  src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOgAAsAAAAAB6QAAANUAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDFAqCcII5ATYCJAMQCwoABCAFhG0HPxuaBsg+QRxjA7halB7GlI0ehG66VIo+9u6LRQL1OX4SQbVfb8++PUT1MUTqVIDLEygAVlFIRkfYCBPh4tmRvv9dy1KgbAlU+1Jk+JmdpQyV2RIoQg2seiQB7amTp2/oXEsaDWTtkeIVNPG04vhvi8K3b+AyvAYQkUFaPOa9AMRILgcc9hrB5uZLSTSlL0B/BQH6PJfTm+LX+EA5rbVp8lEvwDiQAhxrUUCBFkhA3jK8djEd5GECdXNCGO3OK6lBljI8KhCXea4TWWbisqyUqkK5YmEWbyFcNT1DvkC8Cb4fv6GFJUmpgCfuOZvbgzK+WTbRCVDiEZBiOi+UZRRYB8nE8Ur/MSZRfh0Tdau3qQ2QsiykqaIAEFCG3NaWid6QP14iynBlE0ygUPANJk8MglWAIaiQ4GMYq1B2GvIINs9Mc23I0TNyd8S4faK5Z6U8WXbj1itXutYeT7iAnERPl5x79KLzfukLtRfDanc26dq+NvdXrf/rVeX6x18dfj64yvXrX3L9OEN9Y+3qJ+fT5/FgXbC2jletX9x3d354ZfNf/x4ZOaOox8247kfPJhs3ycSzLENJD719TnnqfSp4+/DO/A2xFHv75KXhG0PiRqNMtP3n+VpianLHm2AY2YP/13lp0MrHyx4TP6qn3GrfZL0Qa1bS0dzd6F1neiDsVepwTeY5mphff3WIkQBhKv0hQhSXjH87xY36Ob/xqT/b7Tb/gwy+7v8jiE9lw4zVcw4Ev0LRsSHbKuzI2VQzuRPIJqnREurqmIbDfb+nMI46VxKqRgmSilkUqpaRmV2HkoYJyqq2oW6t/OUNAxITkWtYYxYhdF0hafuMQtdHMrO/UDL2F2XdMEHdoRhs2LAieLxLgk4FekjXIOG7mYFSl4LD6irgenWdUloVcHUgyXyKRIZF5Ev5YABpiilyHxelKJRQielJHjoOdDpGBIlpoFsJUyuKkBQeTqteFNbN9AjbRQI6KUAPossggteNMaBeawUufL4K4PTS6SQ18FqSdYBExndPRAoT0YHM1xs68W7lGVkfThSFgiIoCaNH5CEv0JE8QwjV/TRAN0UY9YCsIEm40Ix21Yctb9S/4TaowzfmSFFEjpLiAes1O6VjMljcZgZuSM0jBA==') format('woff2')
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-right:before {
+  content: "\e636";
+}
+
+.icon-close:before {
+  content: "\e637";
+}
+
+.icon-tongzhi:before {
+  content: "\e608";
+}
+

+ 466 - 0
ctxx_xcx/components/wyb-noticeBar/wyb-noticeBar.vue

@@ -0,0 +1,466 @@
+<template>
+	<view class="container" v-if="show" 
+	style="margin: 0 auto;border-radius: 16rpx"
+	 :style="{
+		 width:wdithFix+'rpx'||'',
+		 background: bgColor || autoBgColor,
+		 height: height + 'rpx',
+		 border: hasBorder ? '1px solid' + color : 'none'}">
+	
+		<view class="close-box" v-if="showClose" @tap="show = false" 
+		 :style="{
+			width: autoCloseWidth + 'px',
+			height: height + 'rpx',
+			paddingLeft: showIcon ? '10rpx' : '0',
+			backgroundColor: bgColor || autoBgColor}">
+			<view class="iconfont icon-close" :style="{
+				 fontSize: autoCloseSize,
+				 color: color,
+				 lineHeight: height + 'rpx'}" />
+		</view>
+	
+		<view class="notice-box" v-if="showIcon" 
+		 :style="{
+			 width: autoNoticeWidth + 'px',
+			 height: height + 'rpx',
+			 backgroundColor: bgColor || autoBgColor}">
+			<view class="notices" v-if="icons==0">
+				<img style="width: 40rpx;height: 40rpx;margin-right: 10rpx" src="/static/index/notice-icon.png" alt="">
+			</view>
+			<view class="notices" v-else>
+				<img style="width: 40rpx;height: 40rpx;margin-right: 10rpx" src="/static/index/shop-icons.png" alt="">
+			</view>
+		</view>
+	
+		<view class="marquee-hori" v-if="type==='hori-connect'" @tap="showMoreExtendTap"
+		 :style="{
+			 width: autoMarQueeWidth + 'px',
+			 height: '105%',
+			 backgroundColor: bgColor || autoBgColor}">
+			 
+			<view class="box-hori" 
+			 :style="{
+				 width: autoBoxWidth + 'px',
+				 animationName: scroll ? '' : 'none',
+				 animationDuration: animDur}">
+				<text id="text" 
+				 :style="{
+					 whiteSpace: 'pre',
+					 color: color,
+					 fontWeight: fontWeight,
+					 fontSize: fontSize + 'rpx',
+					 lineHeight: height + 'rpx'}">{{text.length<=1 ? text[0] : text.join(join)}}</text>
+				<view :style="'width: ' + blockWidth + 'px; height: 100%'" />
+				<text 
+				 :style="{
+					 whiteSpace: 'pre',
+					 color: color,
+					 fontWeight: fontWeight,
+					 fontSize: fontSize + 'rpx',
+					 lineHeight: height + 'rpx'}">{{text.length<=1 ? text[0] : text.join(join)}}</text>
+				<view :style="'width: ' + blockWidth + 'px; height: 100%'" />
+			</view>
+		</view>
+		
+		<view class="marquee-vert" v-if="type==='vert' || type === 'hori-break'" @tap="showMoreExtendTap"
+		 :style="{
+			 width: autoMarQueeWidth + 'px',
+			 height: '100%',
+			 backgroundColor: bgColor || autoBgColor}">
+			<view class="box-vert">
+				<swiper
+				 class="swiper"
+				 :style="{height: fontSize  * 1.3 + 'rpx'}" 
+				 :autoplay="scroll" 
+				 :interval="time" 
+				 :duration="duration"
+				 :vertical="type === 'vert'" 
+				 :circular="true" 
+				 :touchable="false"
+				 :disable-touch="true"
+				 @animationfinish="swpChange">
+					<swiper-item 
+					 class="swiper-item" 
+					 v-for="(item,index) in text" :key="index" 
+					 v-if="text.length <= 2">
+						<text :style="{
+								  whiteSpace: 'pre',
+								  color: color,
+								  fontWeight: fontWeight,
+								  fontSize: fontSize + 'rpx'}">{{item}}</text>
+					</swiper-item>
+					
+					<swiper-item v-if="text.length > 2" class="swiper-item">
+						<text :style="{
+								  whiteSpace: 'pre',
+								  color: color,
+								  fontWeight: fontWeight,
+								  fontSize: fontSize + 'rpx'}">{{swp[0]}}</text>
+					</swiper-item>
+					<swiper-item v-if="text.length > 2" class="swiper-item">
+						<text :style="{
+								  whiteSpace: 'pre',
+								  color: color,
+								  fontWeight: fontWeight,
+								  fontSize: fontSize + 'rpx'}">{{swp[1]}}</text>
+					</swiper-item>
+					
+				</swiper>
+			</view>
+		</view>
+	
+		<view class="look-more-box" v-if="showMore" @tap="showMoreTap" :style="{
+			 width: autoMoreWidth + 'px',
+			 height: height + 'rpx',
+			 backgroundColor: bgColor || autoBgColor}">
+			<!-- <view class="iconfont icon-right" :style="{
+				 fontSize: autoMoreSize,
+				 color: color,
+				 lineHeight: height + 'rpx'}" /> -->
+		</view>
+	
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				show: true,
+				animDur: '5s',
+				autoBoxWidth: 0,
+				autoBoxHeight: 0,
+				textPercent: 0.77,
+				noticePercent: 0.075,
+				morePercent: 0.09,
+				closePercent: 0.065,
+				swp: this.text.slice(),
+				textIdx: 0,
+			}
+		},
+		computed: {
+			rpxWidth() {
+				return parseFloat(this.width) / uni.getSystemInfoSync().screenWidth * 750
+			},
+			autoMarQueeWidth() {
+				let percent = this.textPercent
+
+				if (!this.showClose) {
+					percent += this.closePercent
+				}
+				if (!this.showIcon) {
+					percent += this.noticePercent
+				}
+				if (!this.showMore) {
+					percent += this.morePercent
+				}
+
+				return parseFloat(this.width) * percent
+			},
+			autoNoticeWidth() {
+				return parseFloat(this.width) * this.noticePercent
+			},
+			autoMoreWidth() {
+				return parseFloat(this.width) * this.morePercent
+			},
+			autoCloseWidth() {
+				return parseFloat(this.width) * this.closePercent
+			},
+			blockWidth() {
+				let result = 0
+				let eleWidth = 0
+				this.getRect('#text').then(res => {
+					eleWidth = res.width
+				})
+				let comWidth = parseFloat(this.autoMarQueeWidth)
+				result = comWidth - parseFloat(eleWidth) - (this.spaceConst)
+				return result
+			},
+			autoBgColor() {
+				return this.RGBChange(this.color, 0.85, 'light')
+			},
+			autoNoticeSize() {
+				return parseFloat(this.width) * 0.087 + 'rpx'
+			},
+			autoMoreSize() {
+				return parseFloat(this.width) * 0.087 + 'rpx'
+			},
+			autoCloseSize() {
+				return parseFloat(this.width) * 0.087 + 'rpx'
+			}
+		},
+		props: {
+			// 整体配置参数
+			type: {
+				type: String,
+				default: 'hori-connect'
+			},
+			width: {
+				type: [String, Number],
+				default: uni.getSystemInfoSync().screenWidth
+			},
+			height: {
+				type: [String, Number],
+				default: 70
+			},
+			color: {
+				type: String,
+				default: '#fff'
+			},
+			bgColor: {
+				type: String,
+				default: '#222'
+			},
+			wdithFix:{
+				type:Number,
+				default:750 
+			}, 
+			text: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			fontWeight: {
+				type: String,
+				default: 'normal'
+			},
+			fontSize: {
+				type: [String, Number],
+				default: '27'
+			},
+			hasBorder: {
+				type: Boolean,
+				default: false,
+			},
+			scroll: {
+				type: Boolean,
+				default: true,
+			},
+			showIcon: {
+				type: Boolean,
+				default: true
+			},
+			showMore: {
+				type: Boolean,
+				default: true
+			},
+			showClose: {
+				type: Boolean,
+				default: false
+			},
+			url: {
+				type: String,
+				default: ''
+			},
+			extendMoreArea: {
+				type: Boolean,
+				default: false
+			},
+			// hori-connect配置参数
+			join: {
+				type: String,
+				default: '    '
+			},
+			spaceConst: {
+				type: Number,
+				default: 0
+			},
+			icons: {
+				type: Number,
+				default: 0
+			},
+			speed: {
+				type: Number,
+				default: 40
+			},
+			// vert和hori-break配置参数
+			time: {
+				type: Number,
+				default: 3000
+			},
+			duration: {
+				type: Number,
+				default: 1000
+			}
+		},
+		mounted() {
+			this.getRect('#text').then(res => {
+				this.autoBoxWidth = (res.width + this.blockWidth) * 2
+				this.animDur = parseFloat(res.width + this.blockWidth) / this.speed + 's'
+			})
+		},
+		methods: {
+			showMoreTap() {
+				if (this.url) {
+					uni.navigateTo({
+						url: this.url,
+						fail(msg) {
+							console.log(msg)
+						}
+					})
+				} else {
+					this.$emit('showMore')
+				}
+			},
+			showMoreExtendTap() {
+				if (this.extendMoreArea) {
+					this.showMoreTap()
+				}
+			},
+			swpChange(e) {
+				if (this.text.length > 2) {
+					let current = e.detail.current
+					if (current === 1) {
+						this.swp.splice(0, 1, this.swp[2])
+						this.swp.splice(2, 1)
+					} else if (current === 0) {
+						this.swp.splice(1, 1, this.swp[2])
+						this.swp.splice(2, 1)
+					}
+					this.swp.push(this.text[this.textIdx])
+					this.textIdx++
+					if (this.textIdx === this.text.length - 1) this.textIdx = 0
+				}
+			},
+			getRect(selector) {
+				return new Promise(resolve => {
+					uni.createSelectorQuery().in(this)['select'](selector).boundingClientRect(rect => {
+						if (rect) resolve(rect)
+					}).exec()
+				})
+			},
+			RGBChange(color, level, type) {
+				// hex转rgb
+				if (color.length === 4) {
+					let arr = color.split('')
+					color = '#' + arr[1] + arr[1] + arr[2] + arr[2] + arr[3] + arr[3]
+				}
+				let color16List = [color.substring(1, 3), color.substring(3, 5), color.substring(5, 7)]
+				let r = parseInt(color16List[0], 16)
+				let g = parseInt(color16List[1], 16)
+				let b = parseInt(color16List[2], 16)
+				let rgbc = [r, g, b]
+				// 减淡或加深
+				for (var i = 0; i < 3; i++)
+					type === 'light' ? rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]) : rgbc[i] = Math.floor(rgbc[i] * (1 -
+						level))
+				// rgb转hex
+				let R = rgbc[0].toString(16)
+				let G = rgbc[1].toString(16)
+				let B = rgbc[2].toString(16)
+				if (R.length === 1) R = '0' + R
+				if (G.length === 1) G = '0' + G
+				if (B.length === 1) B = '0' + B
+				return '#' + R + G + B
+			}
+		}
+	}
+</script>
+
+<style>
+	@import "./iconfont.css";
+
+	@keyframes hori-animation {
+		0% {
+			transform-origin: left;
+			transform: translateX(0);
+		}
+
+		100% {
+			transform-origin: left;
+			transform: translateX(-50%);
+		}
+	}
+	
+	.base {
+		
+	}
+
+	.container {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-around;
+		overflow: hidden;
+		padding: 0 30rpx;
+	}
+
+	.marquee-hori,
+	.marquee-vert{
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: clip;
+		position: relative;
+	}
+	
+	.marquee-vert {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: center;
+	}
+
+	.box-hori {
+		height: 100%;
+		display: flex;
+		flex-direction: row;
+		animation-name: hori-animation;
+		animation-duration: 5s;
+		animation-timing-function: linear;
+		animation-iteration-count: infinite;
+		animation-delay: 1s;
+		white-space: nowrap;
+	}
+	
+	.box-vert {
+		width: 100%;
+		padding-bottom: 4rpx;
+		display: flex;
+		flex-direction: column;
+		white-space: nowrap;
+	}
+	
+	.swiper {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: center;
+	}
+	
+	.swiper-item {
+		overflow: hidden;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: center;
+	}
+
+	.close-box {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		box-sizing: border-box;
+		overflow: hidden;
+	}
+
+	.notice-box {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: flex-start;
+		box-sizing: border-box;
+		overflow: hidden;
+		/* padding-left: 15rpx; */
+	}
+
+	.look-more-box {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		box-sizing: border-box;
+		overflow: hidden;
+	}
+</style>

+ 4 - 0
ctxx_xcx/config/env.js

@@ -0,0 +1,4 @@
+export default {
+	basePath: 'https://xixie.hdlkeji.com',
+
+}

+ 20 - 0
ctxx_xcx/index.html

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

+ 29 - 0
ctxx_xcx/main.js

@@ -0,0 +1,29 @@
+import App from './App'
+import uView from 'uview-ui'
+Vue.use(uView)
+// 如此配置即可
+uni.$u.config.unit = 'rpx'
+// #ifndef VUE3
+import Vue from 'vue'
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+    ...App
+})
+import global from './utils/global.js';
+Vue.prototype.$global = global
+
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+export function createApp() {
+  const app = createSSRApp(App)
+    app.config.globalProperties.$global = global;
+
+    return {
+    app
+  }
+}
+// #endif

+ 72 - 0
ctxx_xcx/manifest.json

@@ -0,0 +1,72 @@
+{
+    "name" : "潮庭洗鞋小程序",
+    "appid" : "__UNI__EDAB023",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wxc050ae7c325b487b",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "2"
+}

+ 16 - 0
ctxx_xcx/package-lock.json

@@ -0,0 +1,16 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "mp-html": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmmirror.com/mp-html/-/mp-html-2.4.0.tgz",
+      "integrity": "sha512-T8zcDoy+zR5VMQ9dnFK3bMAbibgVN8VitXNjuU9tuRPYSbo2qiGroYJSoAAF7XbFenMayKjeY8fkR0dxOD63sQ=="
+    },
+    "uview-ui": {
+      "version": "2.0.31",
+      "resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.31.tgz",
+      "integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw=="
+    }
+  }
+}

+ 142 - 0
ctxx_xcx/pages.json

@@ -0,0 +1,142 @@
+{
+	"easycom": {
+			"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
+		},
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "首页"
+			}
+		},
+		{
+			"path": "pages/userDeal/index",
+			"style": {
+				"navigationBarTitleText": "使用协议"
+			}
+		},
+		{
+			"path": "pages/shopNotice/index",
+			"style": {
+				"navigationBarTitleText": "商城公告"
+			}
+		},
+		{
+			"path": "pages/indexNotice/index",
+			"style": {
+				"navigationBarTitleText": "首页公告"
+			}
+		},
+		{
+			"path": "pages/mandate/index",
+			"style": {
+				"navigationBarTitleText": "微信授权页"
+			}
+		},
+		{
+			"path": "pages/loading/index",
+			"style": {
+				"navigationBarTitleText": "加载页"
+			}
+		},
+		{
+			"path": "pages/orderPay/index",
+			"style": {
+				"navigationBarTitleText": "确认订单"
+			}
+		},
+		{
+			"path": "pages/shoeOrderDetails/index",
+			"style": {
+				"navigationBarTitleText": "商品订单详情"
+			}
+		},
+		{
+			"path": "pages/goodsOrderDetail/index",
+			"style": {
+				"navigationBarTitleText": "洗鞋订单详情"
+			}
+		},
+		{
+			"path": "pages/subscribeList/index",
+			"style": {
+				"navigationBarTitleText": "我的预约"
+			}
+		},
+		{
+			"path": "pages/shoeList/index",
+			"style": {
+				"navigationBarTitleText": "洗鞋订单"
+			}
+		},
+		{
+			"path": "pages/shopList/index",
+			"style": {
+				"navigationBarTitleText": "商城订单"
+			}
+		},
+		{
+			"path": "pages/subscribeDetails/index",
+			"style": {
+				"navigationBarTitleText": "预约详情"
+			}
+		},
+		{
+			"path": "pages/userInfoUpdate/index",
+			"style": {
+				"navigationBarTitleText": "资料修改"
+			}
+		},
+		{
+			"path": "pages/shop/index",
+			"style": {
+				"navigationBarTitleText": "商城"
+			}
+		},
+		{
+			"path": "pages/mine/index",
+			"style": {
+				"navigationBarTitleText": "我的"
+			}
+		},
+		{
+			"path": "pages/goodsDetail/index",
+			"style": {
+				"navigationBarTitleText": "商品详情"
+			}
+		},
+		{
+			"path": "pages/shopesOrder/index",
+			"style": {
+				"navigationBarTitleText": "洗鞋下单"
+			}
+		},
+		{
+			"path": "pages/orderSuccess/index",
+			"style": {
+				"navigationBarTitleText": "下单成功"
+			}
+		},
+		{
+			"path": "pages/order_s/index",
+			"style": {
+				"navigationBarTitleText": "下单成功"
+			}
+		},
+		{
+			"path": "pages/subscribe/index",
+			"style": {
+				"navigationBarTitleText": "预约成功"
+			}
+		}
+	],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#F8F8F8",
+		"backgroundColor": "#F8F8F8"
+	},
+	// 原生的导航
+
+	"uniIdRouter": {}
+}

+ 410 - 0
ctxx_xcx/pages/goodsDetail/index.vue

@@ -0,0 +1,410 @@
+<template>
+	<view class="content">
+		<view class="swiper">
+				<swiper
+					  indicator-dots
+					  indicator-active-color="#FFFFFF"
+					  circular
+					  autoplay
+					>
+						<swiper-item  
+						  v-for="item in goodsInfo.content_arr"
+						  :key="item.id"
+						>
+							<image class="swiper-img" :src ="item"></image>
+						</swiper-item>
+					</swiper>
+		</view>
+		<view class="goods-content">
+			<view class="goods-list" v-for="(item,index) in goodsInfo.image_arr"  v-if="index<5">
+				<image :src="item"></image>
+			</view>
+		</view>
+		<view class="goods-detail">
+			<view class="money"> 
+				<text class="moneys">¥{{goodsInfo.low_price}}</text>
+				<text class="texts">(优惠价)</text>
+				<text class="price">¥{{goodsInfo.low_original}}</text>
+			</view>
+			<view class="goods-names">
+				{{goodsInfo.name}}
+        {{goodsInfo.desc}}
+			</view>
+		</view>  
+		<view class="goods-desc">
+			<view class="title">商品详情</view>
+			<view style="margin-top: 20rpx;"> 	
+				<mp-html class="style-s" :content="contenet" /> 
+			</view>
+		</view>
+		<view class="pay-bottom">
+			<view class="bottomStyle" @click="show1 = true">
+				<view class="shoes-icon">
+					<image src="/static/index/shoes-icon.png"></image>
+				</view>
+				<view class="texts" >线下试穿</view>
+			</view>
+			<view class="button" @click="show = true">立即购买</view>
+		</view>
+		<u-popup :show="show1" @close="close1">
+		    <view class="goods-bottoms">
+				<view class="goods">
+					<view class="goods-img">
+						<image :src="goodsInfo.cover"></image>
+					</view>
+					<view class="goods-name overflow2">{{goodsInfo.name}}  {{goodsInfo.desc}}</view>
+				</view>
+				<view class="texts">尺码</view>
+				<view class="goods-rule">
+					<view class="rule-list" @click="ruleTap(index)" :class="ruleIndex==index?'classStyle':''" v-for="(item,index) in goodsInfo.item_list" :key="index">
+						{{item.goods_spec}}
+					</view>
+				</view>
+				<view class="rule-bottom">
+					<view class="button" @click="fitting()" style="width: 520rpx;margin-left: 50rpx;">
+						预约试穿
+					</view>
+				</view>
+			</view>
+		</u-popup>
+		<u-popup :show="show" @close="close">
+		    <view class="goods-bottoms">
+				<view class="goods">
+					<view class="goods-img">
+						<image :src="goodsInfo.cover"></image>
+					</view>
+					<view class="goods-name overflow2">{{goodsInfo.name}}  {{goodsInfo.desc}}</view>
+				</view>
+				<view class="texts">尺码</view>
+				<view class="goods-rule">
+					<view class="rule-list" @click="ruleTaps(index)" :class="ruleIndexs==index?'classStyle':''" v-for="(item,index) in goodsInfo.item_list" :key="index">
+						{{item.goods_spec}}
+					</view>
+				</view>
+				<view class="rule-bottom">
+					<view class="rule-left">
+						<view class="moneys">¥{{goodsInfo.item_list[ruleIndexs].original_price}}</view>
+						<view class="price">¥<span>{{goodsInfo.item_list[ruleIndexs].sell_price}}</span></view>
+					</view>
+					<view class="button" @click="submit">
+						立即购买
+					</view>
+				</view>
+			</view>
+		</u-popup>
+
+
+
+
+
+	</view>
+</template>
+
+<script>
+	import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
+	import api from 'utils/api'
+	import wybNoticeBar from '@/components/wyb-noticeBar/wyb-noticeBar.vue'
+	import navBar from '@/components/nav-bar/nav-bar.vue'
+	export default {
+		components:{wybNoticeBar,navBar,mpHtml},
+		data() {
+			return {
+				contenet:'',
+				 html:'<div>Hello World!</div>',
+				 show: false,
+				 show1:false,
+				 ruleIndex:0,
+				 ruleIndexs:0,
+				list: [{
+						iconPath: "home",
+						selectedIconPath: "home-fill",
+						text: '首页',
+						count: 2,
+						isDot: true,
+						customIcon: false,
+					},
+					{
+						iconPath: "account",
+						selectedIconPath: "account-fill",
+						text: '我的',
+						count: 23,
+						isDot: false,
+						customIcon: false,
+					},
+				],
+				current: 0,
+				texts:{
+
+				},
+				array:['测试11', '测试11', '测试11', '测试11'],
+				title: 'Hello',
+				rotation: [
+						{
+							id: 1,
+							url: 'https://imgcps.jd.com/ling4/100035927374/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa42/60f03300/cr/s/q.jpg'
+						},
+						{
+							id: 2,
+							url: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/217650/27/18929/95548/627b69e5E7f4c1ff2/1a6be6e037e34e5c.jpg.webp'
+						},
+						{
+							id: 3,
+							url: 'https://imgcps.jd.com/ling4/100012043978/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa09/00d13111/cr/s/q.jpg'
+						},
+						{
+							id: 4,
+							url: 'https://imgcps.jd.com/ling4/100014348458/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa7f/aa5a1911/cr/s/q.jpg'
+						}
+				],
+				goodsInfo:'',//商品详情
+			}
+		},
+		onLoad(options) {
+			this.getGoodsDetails(options.id)
+		},
+		methods: {
+			//立即购买
+			submit(){
+				let index=this.ruleIndexs
+				let _goods=this.goodsInfo.item_list[index]
+				
+				uni.setStorageSync("goods",_goods); 
+				uni.setStorageSync("goodsInfo",this.goodsInfo);
+				uni.setStorageSync("status",1);
+				uni.navigateTo({
+					url:"/pages/orderPay/index"
+				})
+			},
+			//预约试穿
+			fitting(){
+				let index=this.ruleIndex
+				let _goods=this.goodsInfo.item_list[index]
+				uni.setStorageSync("goods",_goods);
+				uni.setStorageSync("goodsInfo",this.goodsInfo);
+				uni.setStorageSync("status",0);
+				uni.navigateTo({
+					url:"/pages/orderPay/index"
+				})
+			},
+			close(){
+				this.show=false
+			},
+			close1(){
+				this.show1=false
+			},
+			ruleTap(index){
+				this.ruleIndex=index;
+			},
+			ruleTaps(index){
+				this.ruleIndexs=index;
+			},
+			getGoodsDetails(id){
+				let that=this;
+				api.getGoodsDetail({"goods_id":id}).then((res)=>{
+					if(res.code==1){
+						this.goodsInfo=res.data.goods_info;
+						that.contenet=res.data.goods_info.detail;
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.style-s{
+		font-size: 24rpx;
+	}
+	.u-popup__content{
+		background: none !important;
+	}
+	.rule-bottom{
+		display: flex;
+		justify-content: space-between;
+		padding: 0 40rpx;
+		height: 150rpx;
+		margin-top: 100rpx;
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 400rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-left: 20rpx;
+			margin-top: 20rpx;
+		}
+		.rule-left{
+			.moneys{
+				color: #999;
+				font-size: 24rpx;
+				text-decoration: line-through;
+			}
+			.price{
+				color: #222;
+				font-size: 28rpx;
+				margin-top: 10rpx;
+				span{
+					font-weight: 600;
+					font-size: 40rpx;
+				}
+			}
+		}
+	}
+	.goods-bottoms{
+		width: 710rpx;
+		// height: 620rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx 16rpx 0px 0px;
+		padding: 20rpx;
+		.goods-rule{
+			display: flex;
+			flex-wrap: wrap;
+			margin-left: -50rpx;
+			.classStyle{
+				border: 2rpx solid #222222;
+			}
+			.rule-list{
+				box-sizing: border-box;
+				// width: 88rpx;
+				padding: 0 10rpx;
+				height: 48rpx;
+				background: #F4F4F4;
+				border-radius: 8rpx;
+				color: #222;
+				font-size: 24rpx;
+				margin-left: 60rpx;
+				text-align: center;
+				line-height: 48rpx;
+				margin-bottom: 10rpx;
+			}
+		}
+		.texts{
+			font-size: 28rpx;
+			color: #222;
+			margin: 20rpx 0;
+		}
+		.goods{
+			display: flex;
+			.goods-name{
+				margin: 20rpx 0 0 20rpx;
+				padding: 0 20rpx;
+				width: 500rpx;
+        height: 40px;
+			}
+			.goods-img{
+				image{
+					width: 120rpx;
+					height:120rpx;
+				}
+			}
+		}
+	}
+	.pay-bottom{
+		width: 100%;
+		height: 130rpx;
+		background: #FFFFFF;
+		position: fixed;
+		bottom: 0;
+		display: flex;
+		padding-top: 25rpx;
+		.bottomStyle{
+			width: 150rpx;
+			text-align: center;
+			margin-left: 40rpx;
+			.texts{
+				font-size: 24rpx;
+				color: #222;
+				font-weight: 600;
+			}
+			.shoes-icon{
+				image{
+					width: 48rpx;
+					height: 48rpx;
+				}
+			}
+		}
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 500rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-left: 20rpx; 	
+		}
+	}
+	.goods-desc{
+		background-color: #fff; 
+		padding: 30rpx;
+		width: 610rpx; 
+		margin: 0 auto;
+		margin-bottom: 200rpx;
+    border-radius: 16rpx;
+    .title{
+			color: #222;
+			font-size: 28rpx;
+		}
+	}
+	.goods-detail{
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+		border-radius: 16rpx;
+		margin: 30rpx auto;
+		width: 630rpx;
+		padding: 25rpx;
+		.goods-names{
+			width: 650rpx;
+			color: #222;
+			font-size: 28rpx;
+			margin-top: 10rpx;
+		}
+		.money{
+			.moneys{
+				color: #222;
+				font-size: 40rpx;
+			}
+			.texts{
+				color: #222;
+				font-size: 20rpx;
+				margin-left: 10rpx;
+			}
+			.price{
+				font-size: 24rpx;
+				color: #999;
+				margin-left: 10rpx;
+				text-decoration:line-through
+			}
+		}
+	}
+	.goods-content{
+		padding: 0 16rpx 0 4rpx;
+		display: flex;
+		justify-content: left;
+		margin-left: 30rpx;
+		.goods-list{
+			// flex: 1;
+			margin-left: 12rpx;
+			text-align: center;
+			image{
+				width: 104rpx;
+				height: 104rpx;
+			}
+		}
+	}
+	swiper{
+		height: 750rpx;
+	}
+	.swiper{
+		margin: 12rpx auto;
+		text-align: center;
+	}
+	.swiper-img{
+		width: 100%;
+		height: 750rpx;
+		text-align: center;
+		// border-radius: 16rpx;
+	}
+</style>

+ 437 - 0
ctxx_xcx/pages/goodsOrderDetail/index.vue

@@ -0,0 +1,437 @@
+<template>
+	<view>
+		<view class="content">
+			<view class="goodsList" v-for="(item,index) in info.order_item" :key="index">
+				<!-- <view class="order-time">剩余付款时间:{{item.time}}</view> -->
+				<view class="goods-content">
+					<view class="original-info">
+						<view class="original-img">
+							<img :src="item.cate_cover" alt="">
+						</view>
+						<view class="original-texts">
+							<view class="original-name">{{item.cate_name}}</view>
+							<view class="original-price-scope">
+								<view class="original-text">价格范围</view>
+								<view class="original-price">{{item.cate_price}}</view>
+							</view>
+						</view>
+
+					</view>
+					<view class="order-texts">原始照片</view>
+					<view class="contents">
+						<view class="photo-imgs" v-for="(items,index) in item.images_arr">
+							<view class="original-img">
+								<img :src="items" alt="">
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="remark">
+					备注:{{item.remark}}
+				</view>
+				<view class="bottoms">
+          <view style="color: #222;font-size: 24rpx">实付款</view>
+					<view class="money">¥<span>{{item.sell_price}}</span></view>
+				</view>
+
+			</view>
+			<view class="remarks">
+				<view class="title">详细信息</view>
+				<view class="user-views">
+					<view class="titles">
+						收货信息
+					</view>
+					<view class="user-info">
+						{{info.user_name}},{{info.phone}},
+						{{info.pro_name}}{{info.city_name}}{{info.county_name}}
+						{{info.add_detail}}
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						创建时间
+					</view>
+					<view class="user-info">
+						{{info.create_at}}
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						付款时间
+					</view>
+					<view class="user-info">
+						<span v-if="info.pay_at">{{info.pay_at}}</span>
+						<span style="color:#999" v-else >{{status[info.status]}}</span>
+					</view>
+				</view>
+				<!-- <view class="user-views">
+					<view class="titles">
+						备注信息
+					</view>
+					<view class="user-info">
+						请在早上10:00之前或下午5:00之后来,来之前记得打电话,敲三下门,两长一短。
+					</view>
+				</view> -->
+			</view>
+
+
+		</view>
+		<view class="buttons" @click="notMoreTap(info.id)" v-if="info.status==0">
+			立即付款
+		</view>
+		<view class="buttons" @click="cancels(info.id)" style="margin: 40rpx auto;" v-if="info.status==0">
+			取消订单
+		</view>
+<!--		<view class="buttons" @click="orderOk(info.id)" v-if="info.status==1">-->
+<!--			确认收货-->
+<!--		</view>-->
+		<view class="buttons" v-if="info.status==2">
+			已完成
+		</view>
+
+		<view style="height: 100rpx;"></view>
+
+	</view>
+
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+        clickName:false,
+				info:'',
+				status:{
+					"0":"待支付",
+					"1":"已支付",
+					"2":"已发货",
+					"4":"已完成",
+					"3":"已收货",
+					"9":"已取消"
+				},
+				id:'',
+				goodsList:[
+					{
+						image:"url",
+						name:"运动鞋",
+						price:2000,
+						remark:'备注111',
+						money:500,
+						time:"25分32秒",
+						photo:["1","2","3"]
+					},
+				]
+			}
+		},
+		onLoad(options) {
+			this.getWashOrderDetail(options.id)
+			this.id=options.id
+		},
+		methods: {
+			getWashOrderDetail(id){
+				api.getWashOrderDetail({"id":id}).then((res)=>{
+					if(res.code==1){
+						this.info=res.data.detail
+					}
+				})
+			},
+      notMoreTap(id) {
+        // means是点击后需要执行的方法
+        // clickName是一个变量的名字控制是否是第一次点击
+        if (!this.clickName) {
+          // 第一次点击
+          // means()
+          this.pay(id)
+          this.clickName = true;
+          setTimeout(()=>{
+            this.clickName = false;
+          },2000)
+        } else {
+
+        }
+      },
+			pay(id){
+				let that=this;
+				api.payOrders({"order_id":id}).then((ret)=>{
+						if(ret.code==1){
+							let config=ret.data.config.config;
+								uni.requestPayment({
+									provider: 'wxpay',
+									timeStamp: config.timestamp,
+									nonceStr: config.nonceStr,
+									package: config.package,
+									signType: config.signType,
+									paySign: config.paySign,
+									success: function(res) {
+										uni.showToast({
+											icon:"none",
+											title:"支付成功"
+										})
+										that.getWashOrderDetail(that.id)
+									},
+									fail: function(res) {
+										uni.showToast({
+											icon:"none",
+											title:"支付失败"
+										})
+									},
+									complete: function(res) {
+
+									}
+								});
+								}
+							})
+			},
+			orderOk(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否已完成订单?',
+					success(res) {
+						if (res.confirm) {
+							api.completeOrder({"id":id}).then((res)=>{
+								if(res.code==1){
+									uni.showToast({
+										icon:"none",
+										title:"订单完成"
+									})
+									that.getWashOrderDetail(that.id)
+								}
+							})
+						}
+					}
+				});
+			},
+			cancels(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否要取消订单?',
+					success(res) {
+						if (res.confirm) {
+							api.cancelOrders({"id":id}).then((res)=>{
+								if(res.code==1){
+									uni.showToast({
+										icon:"none",
+										title:"取消成功"
+									})
+									that.getWashOrderDetail(that.id)
+                  setTimeout(()=>{
+                    uni.navigateTo({
+                      url: "/pages/shoeList/index",
+
+                    })
+                  },1000)
+								}
+							})
+						}
+					}
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.buttons{
+		width: 320rpx;
+		height: 64rpx;
+		background: #222222;
+		border-radius: 16rpx;
+		text-align: center;
+		line-height: 64rpx;
+		color: #fff;
+		font-size: 32rpx;
+		margin: 120rpx auto 20rpx auto;
+	}
+	.remarks{
+		padding: 30rpx 30rpx;
+		background-color: #fff;
+		border-radius: 16rpx;
+		.title{
+			color: #222;
+			font-size: 28rpx;
+		}
+		.user-views{
+			margin-top: 30rpx;
+			.titles{
+				color: #222;
+				font-size: 24rpx;
+			}
+			display: flex;
+			justify-content: space-between;
+			.user-info{
+				width: 500rpx;
+				text-align: right;
+				color: #666;
+				font-size: 24rpx;
+				line-height: 30rpx;
+				border-bottom: 1rpx solid #f5f5f5;
+				padding-bottom: 20rpx;
+			}
+		}
+	}
+	page{
+		background-color: #F7F7F7;
+	}
+	.pay-bottom{
+		width: 100%;
+		height: 150rpx;
+		background: #FFFFFF;
+		position: fixed;
+		bottom: 0;
+		display: flex;
+		padding-top: 25rpx;
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-left: 20rpx;
+		}
+		.money{
+			margin-left: 80rpx;
+			color: #222;
+			font-size: 24rpx;
+			margin-top: 15rpx;
+			span{
+				font-size: 28rpx;
+				font-weight: bold;
+			}
+		}
+	}
+	.content{
+		padding:30rpx;
+		.bottom_s{
+			width: 626rpx;
+			height: 90rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			margin: 25rpx auto;
+			line-height: 90rpx;
+			padding: 0 30rpx;
+			display: flex;
+			.icon{
+				margin-top: 10rpx;
+				img{
+					width: 48rpx;
+					height: 48rpx;
+				}
+			}
+			.wx-text{
+				color: #222;
+				margin-left: 16rpx;
+				font-size: 28rpx;
+			}
+		}
+		.bottoms{
+			display: flex;
+			justify-content: space-between;
+			// padding: 30rpx;
+			height: 40rpx;
+			line-height: 40rpx;
+			padding: 20rpx 30rpx;
+			view{
+				color: #222;
+				font-size: 28rpx;
+			}
+			span{
+				color: #222222;
+				font-size: 40rpx;
+				font-weight: bold;
+			}
+		}
+		.remark{
+			color: #555;
+			font-size: 24rpx;
+			padding:0 30rpx;
+      flex-wrap: wrap;
+		}
+		.goodsList{
+			width: 686rpx;
+			// height: 400rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 2rpx 6rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			margin-bottom: 25rpx;
+			.goods-content{
+				padding: 30rpx 30rpx 30rpx 14rpx;
+				.contents{
+					display: flex;
+					flex-wrap: wrap;
+					.photo-imgs{
+						.original-img{
+							margin-left: 16rpx;
+							img{
+								width: 128rpx;
+								height: 128rpx;
+								border-radius: 8rpx;
+							}
+						}
+					}
+				}
+				.goods-contents{
+
+
+				}
+
+				.order-texts{
+					color: #555;
+					font-size: 24rpx;
+					margin: 16rpx 0 8rpx 14rpx;
+				}
+				.original-info{
+					display: flex;
+					margin-left: 14rpx;
+					.original-img{
+						img{
+							width: 128rpx;
+							height: 128rpx;
+						}
+					}
+					.original-texts{
+						margin-left: 16rpx;
+						.original-name{
+							color: #222;
+							font-size: 28rpx;
+							margin-top: 20rpx;
+						}
+						.original-price-scope{
+							display: flex;
+							margin-top: 15rpx;
+							.original-text{
+								color: #555;
+								font-size: 24rpx;
+							}
+							.original-price{
+								width: 132rpx;
+								height: 32rpx;
+								background: #222222;
+								border-radius: 8rpx;
+								color: #fff;
+								text-align: center;
+								line-height: 32rpx;
+								font-size: 20rpx;
+								margin-left: 30rpx;
+							}
+						}
+					}
+				}
+			}
+			.order-time{
+				border-radius: 16rpx 16rpx 0 0 ;
+				height: 64rpx;
+				background-color: #222;
+				font-size: 28rpx;
+				color: #fff;
+				line-height: 64rpx;
+				padding-left: 32rpx;
+			}
+		}
+	}
+</style>

+ 665 - 0
ctxx_xcx/pages/index/index.vue

@@ -0,0 +1,665 @@
+<template>
+	<view class="content">
+
+		<nav-bar :navIndex="0"></nav-bar>
+		<view class="swiper">
+				<swiper
+					  indicator-dots
+					  indicator-active-color="#FFFFFF"
+					  circular
+					  autoplay
+					>
+						<swiper-item
+						  v-for="item in rotation"
+
+						>
+
+							<image class="swiper-img" :src="item.cover"></image>
+						</swiper-item>
+					</swiper>
+		</view>
+		<view @click="navTaps" v-if="status!=''">
+			<wyb-noticeBar :text=array :wdithFix="630" />
+		</view>
+
+ 
+		<view class="titles" v-if="goodsList!=''">
+			<view class="lines"></view>
+			<view class="views">深度洗护</view>
+			<view class="lines" style="margin-left: 20rpx;"></view>
+		</view>
+		<view class="title-texts" v-if="goodsList!=''">5双及以上,工作人员将上门取货</view>
+		<view class="content-s" v-for="(item,index) in goodsList" >
+			<view class="cate-goods">
+				<view class="sort-goods">
+					<scroll-view  class="uni-swiper-tab" scroll-x>
+						<view class="shop-lists" v-for="(items,indexs) in item.list"  @click="shopNavTaps(item,indexs,index)">
+							<view class="name" :class="indexs==items.sortIndex?'nameStyles':''">{{items.title}}</view>
+							<view class="icons" v-if="indexs==shopIndex">
+								<img src="/static/index/index_icons.png" alt="">
+							</view>
+						</view>
+					</scroll-view>
+				</view>
+				<view class="cate-content">
+					<view class="goods-top">
+						<view class="images">
+							<image :src="item.list[item.indexs].logo"></image>
+						</view>
+						<view class="rights">
+							<view class="name">{{item.list[item.indexs].title}}</view>
+							<view class="box-list">
+								<view class="boxs"  @click="boxTaps(indexs,index,item)"
+								:class="indexs==items.checkIndex?'nameStyle':''"
+								v-for="(items,indexs) in item.list[item.indexs].ladder_set">
+									{{items.title}}
+								</view>
+							</view>
+							<view class="price"><size>¥</size>
+								{{item.list[item.indexs].ladder_set[item.checkIndexs].price}}
+							</view>
+						</view>
+					</view>
+					<view class="image-photo">
+						<view class="title">照片</view>
+						<view class="image">
+							<view class="image-lists" v-for="(itemss,indexss) in goodsList[index].imageList" :key="indexss">
+								<view class="img-width" v-if="itemss==''" @click="upLoadImg(index,indexss)">
+									<view class="photo-img">
+										<image src="../../static/index/photo-icon.png"></image>
+									</view>
+								</view>
+								<view v-else>
+									<view class="imgeLists">
+										<view class="close" @click="close(index,indexss)">
+											<image src="/static/index/close.png"></image>
+										</view>
+										<image :src="itemss"></image>
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+					<view class="image-photo">
+						<view class="title">备注信息</view>
+						<textarea v-model="item.remark" class="textarea" placeholder="备注信息…"></textarea>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="add-cate" @click="addGoodsCate" v-if="goodsList!=''">
+			<view class="add-icon">
+				<image src="/static/index/add-icon.png" alt=""></image>
+				<view class="names">再加一双</view>
+			</view>
+		</view>
+		<view class="titles" v-if="shopInfo!=''">
+			<view class="lines"></view>
+			<view class="views">店铺信息</view>
+			<view class="lines" style="margin-left: 20rpx;"></view>
+		</view>
+		<view class="index-bottoms">
+			<view class="shop-banner">
+				<img :src="shopInfo.app_logo" alt="">
+			</view>
+			<view class="shop-detail" v-if="shopInfo!=''">
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/phone-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.service_phone}}</view>
+				</view>
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/eimail-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.service_email}}</view>
+				</view>
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/address-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.app_address}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="bottom-s" v-if="goodsList!=''">
+			<view class="shopping">
+				<img src="../../static/index/shopping-icon.png">
+				<text>{{goodsList.length}}</text>
+			</view>
+			<view class="money">¥{{shoppingPrice}}</view>
+			<view class="buttons" @click="submits">去结算</view>
+		</view>
+
+
+	</view>
+</template>
+
+<script>
+	import __config from 'config/env';
+	import api from 'utils/api'
+	import wybNoticeBar from '@/components/wyb-noticeBar/wyb-noticeBar.vue'
+	import navBar from '@/components/nav-bar/nav-bar.vue'
+	export default {
+		components:{wybNoticeBar,navBar},
+		data() {
+			return {
+				status:'',
+				cateIndex:0,
+				list: [{
+						iconPath: "home",
+						selectedIconPath: "home-fill",
+						text: '首页',
+						count: 2,
+						isDot: true,
+						customIcon: false,
+					},
+					{
+						iconPath: "account",
+						selectedIconPath: "account-fill", 
+						text: '我的',
+						count: 23,
+						isDot: false,
+						customIcon: false,
+					},
+				],
+				current: 0,
+				texts:{
+
+				},
+				shopIndex:0,
+				goodsList:[],
+				shopInfo:'',
+				indexNav:0,
+				array:[''],
+				title: 'Hello',
+				template:'',//添加默认模板
+				rotation: [
+
+				],
+				shoppingCart:'',
+				shoppingPrice:'',
+			}
+		},
+		onLoad() {
+			uni.showLoading({
+				title:"正在加载",				
+			})
+			
+			this.getBanner();
+			this.getShopSet();
+			this.getGoodsSort();
+			this.sysConfig();
+		},
+		methods: {
+			navTaps(){
+				uni.navigateTo({
+					url:"/pages/indexNotice/index"
+				})
+			},
+			sysConfig(){
+				api.getSysConfig({"search_name":"notice_title"}).then((res)=>{
+						if(res.code==1){
+							this.array[0]=res.data.notice_title;
+							this.status=res.data
+					}
+				})
+			},
+			submits(){
+				for(let i=0;i<this.goodsList.length;i++){
+					for(let j=0;j<this.goodsList[i].imageList.length;j++){
+						this.goodsList[i].imageLiss=this.goodsList[i].imageList;
+						this.goodsList[i].imageLiss = this.goodsList[i].imageLiss.filter((item) => {
+							return item != ''
+						})
+					}
+				}
+				uni.navigateTo({
+					url:"/pages/shopesOrder/index?price="+this.shoppingPrice
+				})
+				uni.setStorageSync("goodsList",JSON.stringify(this.goodsList))
+
+			},
+			fomatFloat(num){
+				 var result = parseFloat(num);
+				  if (isNaN(result)) {
+				     alert('传递参数错误,请检查!');
+				     return false;
+				  }
+				  result = Math.round(num * 100) / 100;
+				  return result;
+
+
+			},
+			//计算商品的价格
+			getUserPrice(){
+				let count=this.shoppingPrice;
+				let price=0;
+				for(let i=0;i<this.goodsList.length;i++){
+					price+=(this.fomatFloat(this.goodsList[i].price))
+				}
+
+				price=price.toFixed(2)
+				this.shoppingPrice=price
+			},
+			close(indexs,index){
+				this.$set(this.goodsList[indexs].imageList,index,'')
+			},
+			upLoadImg(indexs,index){
+				let that=this;
+				let _url = __config.basePath + '/api/upload/upload'
+					uni.chooseImage({
+						success: (chooseImageRes) => {
+							const tempFilePaths = chooseImageRes.tempFilePaths;
+							uni.uploadFile({
+								url: _url,
+								filePath: tempFilePaths[0],
+								file: tempFilePaths[0],
+								name: 'file',
+								success: (res) => {
+									let _res=JSON.parse(res.data)
+									if(_res.code==1){
+										that.goodsList[indexs].imageList[index]=_res.data;
+
+										that.$set(that.goodsList[indexs].imageList,index,_res.data)
+										// item.imageList[index]=_res.data
+										console.error(that.goodsList)
+
+									}
+								}
+							});
+						}
+					});
+			},
+			addGoodsCate(){
+				let temp=JSON.parse(JSON.stringify(this.template))
+				this.goodsList.push(temp)
+				setTimeout(()=>{
+					this.getUserPrice()
+				},50)
+			},
+			//标签切换
+			boxTaps(index,index_s,item){
+				let indexs=item.indexs;
+				for(let j=0;j<this.goodsList[index_s].list[indexs].ladder_set.length;j++){
+					this.goodsList[index_s].list[indexs].ladder_set[j].checkIndex=index
+					this.goodsList[index_s].checkIndexs=index
+				}
+				this.goodsList[index_s].price=this.goodsList[index_s].list[indexs].ladder_set[index].price
+				setTimeout(()=>{
+					this.getUserPrice()
+				},50)
+			},
+			//分类切换
+			shopNavTaps(item,index,indexs){
+				this.shopIndex=index;
+				for(let j=0;j<this.goodsList.length;j++){
+					if(item.list[j]){
+						item.list[j].sortIndex=index
+					}
+					item.checkIndexs=0
+					item.indexs=index
+
+				}
+				for(let i=0;i<item.list[index].ladder_set.length;i++){
+					item.list[index].ladder_set[i].checkIndex=0
+				}
+				this.goodsList[indexs].price=item.list[index].ladder_set[0].price
+				setTimeout(()=>{
+					this.getUserPrice()
+				},50)
+			},
+			//获取商品分类
+			getGoodsSort(){
+				api.getWashCate().then((res)=>{
+				   if(res.code==1){
+					   res.data.imageList=[[],[],[],[]]
+					   res.data.img=[]
+					   res.data.img1=[]
+					   res.data.remark="";
+					   // res.data.index=0;
+					   res.data.indexs=0;
+					   res.data.checkIndexs=0; //价格区分
+					   let list=res.data.list;
+					   res.data.price=res.data.list[0].ladder_set[0].price;
+					   console.error()
+					   for(let i=0;i<list.length;i++){
+						   list[i].sortIndex=0
+						  for(let j=0;j<list[i].ladder_set.length;j++){
+							  list[i].ladder_set[j].checkIndex=0
+						  }
+					   }
+					   this.shoppingPrice=res.data.list[0].ladder_set[0].price;
+					   console.error(this.shoppingPrice)
+					   this.template=JSON.parse(JSON.stringify(res.data))
+					   this.goodsList.push(res.data);
+				   }
+				})
+			},
+			//获取店铺设置
+			getShopSet(){
+			   api.getShopSet().then((res)=>{
+				   if(res.code==1){
+					   this.shopInfo=res.data
+				   }
+			   })
+			},
+			//获取首页轮播图
+			getBanner(){
+				api.getBanner({"num":5}).then((res)=>{
+					if(res.code==1){
+						this.rotation=res.data.list
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.imgeLists{
+		position: relative;
+		.close{
+			position: absolute;
+			right: -7rpx;
+			top: -7rpx;
+			image{
+				width: 40rpx;
+				height: 40rpx;
+			}
+		}
+		image{
+			width: 130rpx;
+			height: 130rpx;
+			border-radius: 8rpx;
+			margin-right: 16rpx;
+		}
+	}
+	.photo-img{
+		image{
+			width: 36rpx;
+			height: 36rpx;
+		}
+	}
+	.add-cate{
+		height: 72rpx;
+		background: #222222;
+		box-shadow: 0px 4rpx 40rpx 0px rgba(142,142,142,0.07);
+		border-radius: 16rpx;
+		width: 690rpx;
+		margin: 20rpx auto;
+		line-height: 72rpx;
+		.names{
+			color: #fff;
+			font-size: 28rpx;
+			text-align: center;
+		}
+		.add-icon{
+			display: flex;
+			justify-content: center;
+			image{
+				width: 32rpx;
+				height: 32rpx;
+				margin: 20rpx 20rpx 0 0;
+			}
+		}
+	}
+	.nameStyle{
+		color: #fff!important;
+		background-color: #222222!important;
+	}
+	.shop-lists{
+		position: relative;
+		margin-left: 25rpx;
+		// width: 150rpx;
+		display: inline-block;
+
+		padding: 0;
+		.name{
+			color: #eee;
+			font-size: 28rpx;
+		}
+
+		.nameStyles{
+			color: #fff;
+			font-size: 28rpx;
+			font-weight: 600;
+		}
+		.icons{
+			margin-top: 20rpx;
+			text-align: center;
+			position: absolute;
+			top: 0rpx;
+			left: 50%;
+			margin-left:-15rpx;
+
+			img{
+				width: 20rpx;
+				height: 8rpx;
+			}
+		}
+	}
+	.uni-swiper-tab{
+		white-space: nowrap;
+	}
+	.bottom-s{
+		width: 100%;
+		height: 88rpx;
+		position: fixed;
+		bottom: 150rpx;
+		background: #fff;
+		display: flex;
+		padding: 0 30rpx;
+		line-height: 88rpx;
+		font-weight: 600;
+		justify-content: space-between;
+		.buttons{
+			width: 160rpx;
+			height: 52rpx;
+			line-height: 52rpx;
+			background: #222222;
+			color: #fff;
+			font-size: 28rpx;
+			border-radius: 30rpx;
+			text-align: center;
+			margin-right: 70rpx;
+			margin-top: 20rpx;
+		}
+		.money{
+			color: #FE022B;
+			margin-left: 25rpx;
+			font-size: 32rpx;
+			flex: 1;
+		}
+		.shopping{
+			position: relative;
+			width: 80rpx;
+			text{
+				position: absolute;
+				width: 28rpx;
+				// padding: 0 8rpx;
+				height: 28rpx;
+				background: #FE022B;
+				border: 1rpx solid #FFFFFF;
+				border-radius: 50%;
+				font-size: 20rpx;
+				text-align: center;
+				color: #fff;
+				line-height: 28rpx;
+				right: 0;
+				margin-top: -5rpx;
+				// margin-left: 30rpx;
+			}
+			img{
+				width: 72rpx;
+				height: 72rpx;
+			}
+		}
+	}
+	.index-bottoms{
+		margin-top: 15rpx;
+		padding:0 30rpx;
+		.shop-detail{
+			padding-bottom: 260rpx;
+			margin-bottom: 100rpx;
+			.views{
+				margin-bottom: 10rpx;
+				display: flex;
+				line-height: 30rpx;
+				.texts{
+					color: #222;
+					font-size: 20rpx;
+					margin-left: 10rpx;
+				}
+				.shop-icons{
+					img{
+						width: 24rpx;
+						height: 24rpx;
+					}
+				}
+			}
+		}
+		.shop-banner{
+			img{
+				width: 688rpx;
+				height: 284rpx;
+				border-radius: 16rpx;
+			}
+		}
+	}
+	.title-texts{
+		color: #222;
+		font-size: 20rpx;
+		text-align: center;
+		margin-top: 10rpx;
+	}
+	.titles{
+		text-align: center;
+		display: flex;
+		justify-content: center;
+		margin-top: 35rpx;
+		.lines{
+			width: 18rpx;
+			height: 4rpx;
+			background: #000000;
+			border-radius: 4rpx;
+			margin: 18rpx 20rpx 0 0;
+		}
+		.views{
+			font-size: 28rpx;
+			color: #222;
+		}
+	}
+	.content-s{
+		.cate-goods{
+			.sort-goods{
+				width: 690rpx;
+				height: 80rpx;
+				background: #222222;
+				border-radius: 16rpx 16rpx 0px 0px;
+				line-height: 80rpx;
+				display: flex;
+				margin: 30rpx auto 0 auto;
+			}
+			.cate-content{
+				margin:0 auto 50rpx auto;
+				width: 630rpx;
+				background: #FFFFFF;
+				box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+				border-radius: 16rpx;
+				padding: 30rpx;
+				.image-photo{
+					margin-top: 20rpx;
+					.textarea{
+						width: 600rpx;
+						height: 126rpx;
+						background: #F7F7F9;
+						border-radius: 16rpx;
+						margin-top: 20rpx;
+						font-size: 24rpx;
+						padding: 10rpx 20rpx;
+					}
+					.title{
+						font-size: 24rpx;
+						color: #555;
+					}
+					.image{
+						display: flex;
+						.image-lists{
+							margin-top: 20rpx;
+							.img-width{
+								width: 130rpx;
+								height: 130rpx;
+								background: #F7F7F9;
+								border-radius: 8rpx;
+								margin-right: 16rpx;
+								display: flex;
+								justify-content: center;
+								align-items: center;
+
+							}
+						}
+					}
+				}
+				.goods-top{
+					display: flex;
+					.box-list{
+						display: flex;
+						flex-wrap: wrap;
+						.boxs{
+							padding: 3rpx 20rpx;
+							height: 32rpx;
+							font-size: 20rpx;
+							color:#555555;
+							line-height: 32rpx;
+							margin-right: 16rpx;
+							background: #EEEEEE;
+							border-radius: 8rpx;
+						}
+					}
+					.rights{
+						.price{
+							color: #FE022B;
+							font-size: 28rpx;
+							margin-top: 24rpx;
+							size{
+								font-size: 20rpx;
+							}
+						}
+						margin-left: 30rpx;
+						.name{
+							color: #555;
+							font-size: 24rpx;
+							margin: 12rpx 0 14rpx 0;
+						}
+					}
+					.images{
+						image{
+							width: 160rpx;
+							height: 160rpx;
+						}
+					}
+				}
+			}
+		}
+
+
+	}
+	.contents{
+
+	}
+	swiper{
+		height: 1334rpx;
+	}
+	.swiper{
+		margin: 12rpx auto;
+		text-align: center;
+	}
+	.swiper-img{
+		width: 684rpx;
+		height: 1334rpx;
+		text-align: center;
+		border-radius: 16rpx;
+	}
+</style>

+ 55 - 0
ctxx_xcx/pages/indexNotice/index.vue

@@ -0,0 +1,55 @@
+<template>
+	<view class="content">
+		<view class="title">{{title}}</view>
+		<mp-html class="style-s" :content="contenet" />
+			<!-- <rich-text class="style-s" :nodes="contenet"></rich-text> -->
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	import util from 'utils/util'
+	import uParse from '@/components/gaoyia-parse/parse.vue'
+	export default {
+		 components: {
+		    uParse
+		  },
+		data() {
+			return {
+				contenet:'',
+				title:''
+			}
+		},
+		onLoad() {
+			api.getSysConfig({}).then((res)=>{
+				if(res.code==1){
+					this.contenet=res.data.notice_content.replace(/\<img/gi, '<img style=max-width:100%;height:auto')
+					this.title=res.data.notice_title
+				}
+			})
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss">
+.style-s{
+  font-size: 24rpx;
+}
+	.title{
+		padding: 20rpx 0;
+		font-size: 32rpx;
+		color: #222;
+		font-weight: bold;
+		text-align: center;
+	}
+	.content{
+		padding:30rpx;
+		background-color: #fff;
+		width: 640rpx;
+		margin: 0 auto;
+		border-radius: 16rpx;
+	}
+</style>

+ 52 - 0
ctxx_xcx/pages/loading/index.vue

@@ -0,0 +1,52 @@
+<template>
+	<view class="content">
+		<view class="swiper">111</view>
+		<view class="gg">
+			<view class="gg-list" v-for="item in 10">
+				11
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		display: grid;
+		padding: 20rpx 30rpx;
+		grid-template-rows: 600rpx 100rpx;
+		// grid-template-columns: 700rpx auto;
+		.gg{
+			background-color: red;
+			line-height: 100rpx;
+			grid-template-columns: repeat(auto-fill,100rpx);
+			grid-gap: 20rpx 20rpx;
+			.gg-list{
+				padding: 30rpx;
+				background-color: #000;
+				color: #fff;
+			}
+		}
+		.swiper{
+			background-color: #333;
+			padding: 20rpx;
+		}
+		view{
+			display: inline-grid;
+		}
+	}
+</style>

+ 178 - 0
ctxx_xcx/pages/mandate/index.vue

@@ -0,0 +1,178 @@
+<template>
+	<view class="content">
+		<view class="bg-image">
+			<img src="/static/index/index_bg.png" alt="">
+		</view>
+		<view class="index_content">
+			<view class="title">潮庭 </view>
+			<view class="names">欢迎回来!</view>
+		</view>
+		<view class="index_contents">
+			<view class="index-icon">
+				<img src="/static/index/index-icons.png" alt="">
+			</view>
+			<view class="line"></view>
+			<view class="index-text">诚当您鞋子的管家!</view>
+		</view>
+		<view class="index-bottom"  @click="check=!check">
+			<view class="check">
+				<img v-if="!check" src="/static/index/check-icon.png" alt="">
+				<img v-else src="/static/index/check-icon-sel.png" alt="">
+			</view>
+			<view class="texts">登录即同意<span @click.stop="sqTap">《潮庭洗鞋小程序》</span></view>
+		</view>
+		<view class="button" @click="$global.clicks(wxLogin)">
+			<view class="logo">
+				<img src="/static/index/wx-icon.png" alt="">
+			</view>
+			<view class="login-name" >微信登录</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+				title: 'Hello',
+				check:false,
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			sqTap(){
+				uni.navigateTo({
+					url:"/pages/userDeal/index"
+				})
+			},
+			wxLogin(){
+				if(!this.check){
+					uni.showToast({
+						icon:"none",
+						title:"请勾选隐私政策"
+					})
+				}else{
+					uni.login({
+						provider:"weixin",
+						success: (loginRes) => {
+						api.weChatLogin({"code":loginRes.code}).then(res => {
+							if(res.code==1){
+								uni.setStorageSync("third_session",res.data.token)
+								 uni.showToast({
+									icon: "none",
+									title: "授权成功",
+									duration: 2000,
+									success: function success() {
+									  setTimeout(function () {
+											uni.navigateBack({ delta: 1 });
+									  }, 1000);
+									} });
+
+							}
+						});
+						}
+
+					})
+				}
+
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		height: 100%;
+		.button{
+			width: 510rpx;
+			height: 88rpx;
+			line-height: 88rpx;
+			box-shadow: 0px 4rpx 40rpx 0px rgba(142,142,142,0.07);
+			border-radius: 50rpx;
+			background-color: #0089FF;
+			margin: 20rpx auto;
+			display: flex;
+			.login-name{
+				color: #fff;
+				font-size: 40rpx;
+				margin-left: 15rpx;
+			}
+			.logo{
+				margin: 0 0 0 134rpx;
+				img{
+					margin-top: 18rpx;
+					width: 58rpx;
+					height: 58rpx;
+				}
+			}
+		}
+		.index-bottom{
+			margin-top: 300rpx;
+			padding: 0 180rpx;
+			display: flex;
+			line-height: 28rpx;
+			.texts{
+				color: #fff;
+				font-size: 24rpx;
+				margin-left: 20rpx;
+				span{
+					color: #4A88FF;
+				}
+			}
+			.check{
+				img{
+					width: 30rpx;
+					height: 30rpx;
+				}
+			}
+		}
+		.index_content{
+			padding: 290rpx 0 0 60rpx;
+			.title{
+				color: #fff;
+				font-size: 92rpx;
+			}
+			.names{
+				color: #fff;
+				font-size: 64rpx;
+				margin-top:20rpx;
+			}
+		}
+		.index_contents{
+			display: flex;
+			margin-top: 36rpx;
+			padding: 0 60rpx;
+			.index-text{
+				color: #fff;
+				font-size: 32rpx;
+			}
+			.line{
+				width: 2rpx;
+				height: 38rpx;
+				background: #FFFFFF;
+				margin: 0 26rpx;
+			}
+			.index-icon{
+				img{
+					width: 72rpx;
+					height: 40rpx;
+				}
+			}
+		}
+		.bg-image{
+			image{
+				 position: absolute;
+				  left: 0;
+				  bottom: 0;
+				  display: block;
+				  width: 100%;
+				  height: 100%;
+				  z-index: -999;
+
+			}
+		}
+	}
+</style>

+ 284 - 0
ctxx_xcx/pages/mine/index.vue

@@ -0,0 +1,284 @@
+<template>
+	<view class="content">
+		<nav-bar :navIndex="2"></nav-bar>
+		<view class="user-info" @click="userTap()">
+			<view class="avatar">
+				<image  :src="userInfos.headimg"></image>
+			</view>
+			<view class="user-s">
+				<view class="name">你好!</view>
+				<view class="desc overflow1">{{userInfos.name}}</view>
+			</view>
+			<view class="rightIcon">
+				<image src="../../static/index/mine-icon1.png"></image>
+			</view>
+		</view>
+		<view class="user-info" style="height: 120rpx;">
+			<view class="user-views" @click="navTaps(item.url)" v-for="(item,index) in navs" :key="index">
+				<view class="icons">
+					<image :src="item.imageUrl"></image>
+				</view>
+				<view class="name">{{item.name}}</view>
+			</view>
+		</view>
+		<view class="titles">
+			<view class="lines"></view>
+			<view class="views">店铺信息</view>
+			<view class="lines" style="margin-left: 20rpx;"></view>
+		</view>
+		<view class="index-bottoms">
+			<view class="shop-banner">
+				<img :src="shopInfo.app_logo" alt="">
+			</view>
+			<view class="shop-detail">
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/phone-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.service_phone}}</view>
+				</view>
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/eimail-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.service_email}}</view>
+				</view>
+				<view class="views">
+					<view class="shop-icons">
+						<img src="/static/index/address-icon.png" alt="">
+					</view>
+					<view class="texts">{{shopInfo.app_address}}</view>
+				</view>
+			</view>
+		</view>
+	
+	 
+
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	import wybNoticeBar from '@/components/wyb-noticeBar/wyb-noticeBar.vue'
+	import navBar from '@/components/nav-bar/nav-bar.vue'
+	export default {
+		components:{wybNoticeBar,navBar},
+		data() {
+			return {
+				navs:[
+					{"url":1,name:"洗鞋订单","imageUrl":"/static/index/mine-icon3.png","url":"/pages/shoeList/index"},
+					{"url":1,name:"我的预约","imageUrl":"/static/index/mine-icon2.png","url":"/pages/subscribeList/index"},
+					{"url":1,name:"商城订单","imageUrl":"/static/index/mine-icon4.png","url":"/pages/shopList/index"}
+				],
+				list: [{
+						iconPath: "home",
+						selectedIconPath: "home-fill",
+						text: '首页',
+						count: 2,
+						isDot: true,
+						customIcon: false,
+					},
+					{
+						iconPath: "account",
+						selectedIconPath: "account-fill",
+						text: '我的',
+						count: 23,
+						isDot: false,
+						customIcon: false,
+					},
+				],
+				current: 0,
+				texts:{
+					
+				},
+				shopInfo:'',
+				array:['测试11', '测试11', '测试11', '测试11'],
+				title: 'Hello',
+				userInfos:'',
+				rotation: [
+						{
+							id: 1,
+							url: 'https://imgcps.jd.com/ling4/100035927374/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa42/60f03300/cr/s/q.jpg'
+						},
+						{
+							id: 2,
+							url: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/217650/27/18929/95548/627b69e5E7f4c1ff2/1a6be6e037e34e5c.jpg.webp'
+						},
+						{
+							id: 3,
+							url: 'https://imgcps.jd.com/ling4/100012043978/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa09/00d13111/cr/s/q.jpg'
+						},
+						{
+							id: 4,
+							url: 'https://imgcps.jd.com/ling4/100014348458/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa7f/aa5a1911/cr/s/q.jpg'
+						}
+				]
+			}
+		},
+		onLoad() {
+			
+			
+		},
+		onShow() {
+			
+			this.getShopSet();
+			this.getUserInfo();
+		},
+		methods: {
+			navTaps(url){
+				uni.navigateTo({
+					url:url
+				})
+			},
+			userTap(){
+				uni.navigateTo({
+					url:"/pages/userInfoUpdate/index"
+				})
+			},
+			//获取用户信息
+			getUserInfo(){
+				api.getUserInfo().then((res)=>{
+					console.error(res)
+					if(res.code==1){
+						this.userInfos=res.data.detail
+					}
+				})
+			},
+			//获取店铺设置
+			getShopSet(){
+			   api.getShopSet().then((res)=>{
+				   if(res.code==1){
+					   this.shopInfo=res.data
+				   }
+			   })
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.user-info{
+		border-radius: 16rpx;
+		width: 630rpx;
+		height: 140rpx;
+		background-color: #fff;
+		display: flex;
+		margin: 20rpx auto;
+		padding: 30rpx;
+		position: relative;
+		.user-views{
+			flex: 1;
+			text-align: center;
+			.name{
+				color: #222;
+				font-size: 28rpx;
+				margin-top: 5rpx;
+			}
+			.icons{
+				image{
+					width: 60rpx;
+					height: 60rpx;
+				}
+			}
+		}
+		.rightIcon{
+			position: absolute;
+			right: 30rpx;
+			top: 76rpx;
+			image{
+				width: 40rpx;
+				height: 40rpx;
+			}
+		}
+		.user-s{
+			margin: 20rpx 0 0 30rpx;
+			.name{
+				color: #222;
+				font-size: 28rpx;
+				margin-top: 5rpx;
+			}
+			.desc{
+				color: #222;
+				font-size: 32rpx;
+				margin-top: 5rpx;
+			}
+		}
+		.avatar{
+			image{
+				width: 128rpx;
+				height: 128rpx;
+				border-radius: 50%;
+			}
+		}
+	}
+	.index-bottoms{
+		margin-top: 15rpx;
+		padding:0 30rpx;
+		.shop-detail{
+			padding-bottom: 180rpx;
+			margin-bottom: 100rpx;
+			.views{
+				margin-top: 10rpx;
+				display: flex;
+				line-height: 30rpx;
+				.texts{
+					color: #222;
+					font-size: 20rpx;
+					margin-left: 10rpx;
+				}
+				.shop-icons{
+					img{
+						width: 24rpx;
+						height: 24rpx;
+					}
+				}
+			}
+		}
+		.shop-banner{
+			img{
+				width: 688rpx;
+				height: 284rpx;
+				border-radius: 16rpx;
+			}
+		}
+	}
+	.title-texts{
+		color: #222;
+		font-size: 20rpx;
+		text-align: center;
+		margin-top: 10rpx;
+	}
+	.titles{
+		text-align: center;
+		display: flex;
+		justify-content: center;
+		margin-top: 35rpx;
+		.lines{
+			width: 18rpx;
+			height: 4rpx;
+			background: #000000;
+			border-radius: 4rpx;
+			margin: 18rpx 20rpx 0 0;
+		}
+		.views{
+			font-size: 28rpx;
+			color: #222;
+		}
+	}
+	.contents{
+		
+	}
+	swiper{
+		height: 328rpx;
+	}
+	.swiper{
+		margin: 12rpx auto;
+		text-align: center;
+	}
+	.swiper-img{
+		width: 684rpx;
+		height: 328rpx;
+		text-align: center;
+		border-radius: 16rpx;
+	}
+</style>

+ 488 - 0
ctxx_xcx/pages/orderPay/index.vue

@@ -0,0 +1,488 @@
+<template>
+	<view>
+		<view class="content">
+			<view class="user-info">
+				<view class="title">
+					填写收货地址
+				</view>
+				<view style="height: 20rpx;"></view>
+				<view class="views" >
+					<view class="name">收货人</view>
+					<view class="input" >
+						<input v-model="from.userName" style="margin-left: 55rpx;" type="text" class="inputs" placeholder="填写姓名"/>
+					</view>
+				</view>
+				<view class="views">
+					<view class="name">联系电话</view>
+					<view class="input">
+						<input maxlength="11" v-model="from.userPhone" class="inputs" type="number" placeholder="填写手机号"/>
+					</view>
+				</view>
+				<pick-regions :defaultRegion="defaultRegionCode" @getRegion="handleGetRegion">
+				<view class="views">
+					<view class="name">所在区域</view>
+					<view class="input">
+						<input disabled="disabled" v-model="from.address" class="inputs" placeholder="选择收件地区(省、市、区)"/>
+					</view>
+				</view>
+				</pick-regions>
+				<view class="views">
+					<view class="name">详细地址</view>
+					<view class="input">
+						<input v-model="from.addDetail" class="inputs" placeholder="例如门牌号、小区、楼层等"/>
+					</view>
+				</view>
+
+			</view>
+				<view class="remark">
+					<view class="title">
+						预约备注
+					</view>
+					<textarea v-model="from.remark" placeholder-class="place" class="text-area" placeholder="请填写方便的时间段,以便工作人员到访。"></textarea>
+				</view>
+				<view class="goods-infos">
+					<view class="goods-img">
+						<image :src="goodsInfo.cover"></image>
+					</view>
+					<view class="goods-right">
+						<view class="goods-name overflow2">{{goodsInfo.name}} {{goodsInfo.desc}}</view>
+						<view class="goods-rule">{{goods.goods_spec}}</view>
+					</view>
+				</view>
+				<view class="pay" v-if="status==1">
+					<view class="wx-icon">
+						<image src="../../static/index/wxIcon.png"></image>
+					</view>
+					<view class="texts">微信支付</view>
+          <view class="wxIcon">
+            <image src="../../static/index/check-icons.png"></image>
+
+          </view>
+				</view>
+				<view style="height: 200rpx;"></view>
+
+		</view>
+		<view class="pay-bottom" v-if="status==1">
+			<view class="money">实付款:<span>¥<span style="font-size: 40rpx;">{{goods.sell_price}}</span></span></view>
+			<view class="button" @click="$global.clicks(pay)">立即购买</view>
+		</view>
+		<view class="pay-bottom" v-if="status==0">
+			<view class="button" @click="$global.clicks(submit)" style="width: 520rpx;margin-left: 120rpx;">确定预约</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+import api from 'utils/api'
+import pickRegions from '@/components/pick-regions/pick-regions.vue'
+	export default {
+		components:{pickRegions},
+		data() {
+			return {
+				 from:{
+					 "userName":"",
+					 "userPhone":"",
+					 "userDetail":"",
+					 "proName":"",
+					 "cityName":"",
+					 "countyName":"",
+					 "addDetail":"",
+					 "remark":"",
+					 "address":""
+				 },
+				 pickerValueDefault: [0, 0, 0],
+				 pickerText: '',
+				 status:0,//0代表是预约 1代表下单购买
+				 goods:'',
+			     region:[],
+				 goodsInfo:'',
+				 }
+		},
+		onLoad(options) {
+			this.goods=uni.getStorageSync("goods")
+			this.goodsInfo=uni.getStorageSync("goodsInfo")
+			this.status=uni.getStorageSync("status")
+			// let infos=uni.getStorageSync("userInfo")
+			api.getAddress().then((res)=>{
+				if(res.code==1 && res.data!=''){					
+					this.from.userName=res.data.user_name
+					this.from.userPhone=res.data.phone
+					// this.from.userDetail=infos.userDetail
+					this.from.proName=res.data.pro_name
+					this.from.cityName=res.data.city_name
+					this.from.countyName=res.data.county_name
+					this.from.addDetail=res.data.add_detail
+					// this.from.remark=infos.remark
+					this.from.address=res.data.pro_name+','+res.data.city_name+','+res.data.county_name
+				}
+			})
+			// this.getAddress()
+		},
+		onUnload() {
+			let from=this.from;
+			uni.setStorageSync("userInfo",from)
+			uni.removeStorageSync("goodsInfo")
+			uni.removeStorageSync("status")
+			uni.removeStorageSync("goods")
+		},
+		onShow() {
+			this.getUserInfo();
+		},
+		methods: {
+			//获取用户信息
+			getUserInfo(){
+				api.getUserInfo().then((res)=>{
+					console.error(res)
+					if(res.code==1){
+						this.userInfos=res.data.detail
+					}
+				})
+			},
+			 tojson(arr){
+				if(!arr.length) return null;
+
+				var i = 0;
+				len = arr.length,
+				array = [];
+				for(;i<len;i++){
+					array.push({"projectname":arr[i][0],"projectnumber":arr[i][1]});
+				}
+				return JSON.stringify(array);
+			},
+			//下单
+			pay(){
+				let from=this.from;
+				if(from.userName==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入姓名"
+					})
+					return;
+				}
+				if(from.userPhone==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入手机号"
+					})
+					return;
+				}
+				if(!(/^1[3456789]\d{9}$/.test(from.userPhone))){
+					uni.showToast({
+						icon:"none",
+						title:"请输入正确的手机号"
+					})
+					return;
+				}
+				if(from.address==''){
+					uni.showToast({
+						icon:"none",
+						title:"请选择区域"
+					})
+					return;
+				}
+				if(from.addDetail==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入详细地址"
+					})
+					return;
+				}
+				let data={
+					"goods_json":"",
+					"pro_name":from.proName,
+					"city_name":from.cityName,
+					"county_name":from.countyName,
+					"add_detail":from.addDetail,
+					"phone":from.userPhone,
+					"user_name":from.userName,
+					"remark":from.remark,
+				}
+				let data_s={'goods_id':this.goodsInfo.id,"spec_id":this.goods.id,'num':1}
+				// let array=[]
+				// array.push(data_s)
+				let datas=[];
+				let data_ss=[];
+				data_ss.push(data_s)
+				// data_ss.push(datas)
+				// console.error(JSON.stringify(data_ss))
+				// return
+				let arrs=data_ss
+				data.goods_json=JSON.stringify(data_ss)
+
+
+
+				api.createOrder(data).then((res)=>{
+					if(res.code==1){
+						api.payOrder({"order_id":res.data.order_id}).then((ret)=>{
+
+							if(ret.code==1){
+								let config=ret.data.config.config;
+									uni.requestPayment({
+										provider: 'wxpay',
+										timeStamp: config.timestamp,
+										nonceStr: config.nonceStr,
+										package: config.package,
+										signType: config.signType,
+										paySign: config.paySign,
+										success: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付成功"
+											})
+											uni.navigateTo({
+												url:"/pages/orderSuccess/index"
+											})
+										},
+										fail: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付失败"
+											})
+										},
+										complete: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付取消"
+											})
+										}
+									});
+							}
+						})
+					}
+				})
+			},
+			 handleGetRegion(e){
+                this.region = e
+				// e 确认后选中的数据
+				this.pickerText = JSON.stringify(e)
+				this.from.proName=e[0].name;
+				this.from.cityName=e[1].name;
+				this.from.countyName=e[2].name;
+				this.from.address=e[0].name+','+e[1].name+','+e[2].name
+            },
+			getAddress(){
+				api.getAreaTree({"level":3}).then((res)=>{
+					if(res.code==1){
+						this.treeData=res.data.list;
+						console.error(res.data.list)
+					}
+				})
+			},
+			//预约订单
+			submit(){
+				let from=this.from;
+				if(from.userName==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入姓名"
+					})
+					return;
+				}
+				if(from.userPhone==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入手机号"
+					})
+					return;
+				}
+				if(!(/^1[3456789]\d{9}$/.test(from.userPhone))){
+					uni.showToast({
+						icon:"none",
+						title:"请输入正确的手机号"
+					})
+					return;
+				}
+				if(from.address==''){
+					uni.showToast({
+						icon:"none",
+						title:"请选择区域"
+					})
+					return;
+				}
+				if(from.addDetail==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入详细地址"
+					})
+					return;
+				}
+				let data={
+					"goods_id":this.goodsInfo.id,
+					"spec_id":this.goods.id,
+					"pro_name":from.proName,
+					"city_name":from.cityName,
+					"county_name":from.countyName,
+					"add_detail":from.addDetail,
+					"phone":from.userPhone,
+					"user_name":from.userName,
+					"remark":from.remark,
+				}
+				api.makeAppointment(data).then((res)=>{
+					if(res.code==1){
+						uni.showToast({
+							icon:"none",
+							title:"预约成功",
+							success() {
+								setTimeout(()=>{
+									uni.navigateTo({
+										url:"/pages/subscribe/index"
+									})
+								},2000)
+							}
+						})
+					}
+				})
+			},
+
+		}
+	}
+</script>
+
+<style lang="scss">
+.wxIcon{
+  margin-right: 32rpx;
+  image{
+    width: 32rpx;
+    height: 32rpx;
+  }
+}
+	.pay-bottom{
+    justify-content: space-between;
+		width: 100%;
+		height: 150rpx;
+		background: #FFFFFF;
+		position: fixed;
+		bottom: 0;
+		display: flex;
+		padding-top: 25rpx;
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-right: 50rpx;
+		}
+		.money{
+			//margin-left: 80rpx;
+			color: #222;
+			font-size: 24rpx;
+			margin-top: 15rpx;
+      margin-right: 20rpx;
+      text-align: right;
+      flex: 1;
+			span{
+				font-size: 28rpx;
+				font-weight: bold;
+			}
+		}
+	}
+	.content{
+		padding: 30rpx;
+
+		.pay{
+			height: 90rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			display: flex;
+      justify-content: space-between;
+			margin: 25rpx 0;
+			line-height: 90rpx;
+			.texts{
+				color: #222;
+				font-size: 28rpx;
+				margin-left: 15rpx;
+        flex: 1;
+			}
+			.wx-icon{
+				image{
+					margin: 20rpx 0 0 30rpx;
+					width: 48rpx;
+					height: 48rpx;
+				}
+			}
+		}
+		.goods-infos{
+			height: 124rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			padding: 30rpx;
+			display: flex;
+			.goods-img{
+				image{
+					width: 120rpx;
+					height: 120rpx;
+				}
+			}
+			.goods-right{
+				margin-left: 20rpx;
+				.goods-name{
+					color: #222;
+					font-size: 24rpx;
+				}
+				.goods-rule{
+					color: #666;
+					font-size: 20rpx;
+					margin-top: 15rpx;
+				}
+			}
+		}
+		.remark{
+			height: 252rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			margin:25rpx 0;
+			padding: 30rpx;
+			.title{
+				font-size: 28rpx;
+				color: #222;
+			}
+			.place{
+				color: #999;
+			}
+			.text-area{
+				font-size: 24rpx;
+				color: #333;
+				margin-top: 25rpx;
+			}
+		}
+		.user-info{
+			height:400rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4px 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			width: 630rpx;
+			background-color: #fff;
+			padding: 30rpx;
+
+			.views{
+				display: flex;
+				// margin-top: 30rpx;
+				height: 80rpx;
+				line-height: 80rpx;
+				font-size: 24rpx;
+				.input{
+					.inputs{
+
+						height: 80rpx;
+						line-height: 80rpx;
+						border-bottom: 1rpx solid #f5f5f5;
+						width: 400rpx;
+						margin-left: 30rpx;
+					}
+				}
+			}
+			.title{
+				font-size: 28rpx;
+				color: #222;
+
+			}
+		}
+	}
+</style>

+ 58 - 0
ctxx_xcx/pages/orderSuccess/index.vue

@@ -0,0 +1,58 @@
+<template>
+	<view class="content">
+		<view class="order-icon">
+			<img src="/static/index/oder-ok.png" alt="">
+		</view>
+		<view class="order-text">下单成功</view>
+		<view class="button" @click="indexTaps">
+			返回首页
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			indexTaps(){
+				uni.reLaunch({
+					url:"/pages/index/index"
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		text-align: center;
+		.order-icon{
+			margin-top: 120rpx;
+			img{
+				width: 160rpx;
+				height: 160rpx;
+			}
+		}
+		.order-text{
+			color: #222;
+			font-size: 36rpx;
+			margin-top: 20rpx;
+		}
+		.button{
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			border-radius: 40rpx;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			margin: 120rpx auto;
+		}
+	}	
+</style>

+ 64 - 0
ctxx_xcx/pages/order_s/index.vue

@@ -0,0 +1,64 @@
+<template>
+	<view class="content">
+		<view class="order-icon">
+			<img src="/static/index/oder-ok.png" alt="">
+		</view>
+		<view class="order-text">下单成功</view>
+		<view class="texts">潮庭工作人员正在为您安排配送</view>
+		<view class="button" @click="indexTaps">
+			返回首页
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			indexTaps(){
+				uni.reLaunch({
+					url:"/pages/index/index"
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		text-align: center;
+		.order-icon{
+			margin-top: 120rpx;
+			img{
+				width: 160rpx;
+				height: 160rpx;
+			}
+		}
+		.order-text{
+			color: #222;
+			font-size: 36rpx;
+			margin-top: 20rpx;
+		}
+		.texts{
+			font-size: 28rpx;
+			color: #222;
+			margin-top: 25rpx;
+		}
+		.button{
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			border-radius: 40rpx;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			margin: 120rpx auto;
+		}
+	}	
+</style>

+ 210 - 0
ctxx_xcx/pages/shoeList/index.vue

@@ -0,0 +1,210 @@
+<template>
+	<view class="content">
+		<view class="shoe-top">
+			<view class="views" @click="navTopIndex(index)" :class="navIndex==index?'classStyle':''" v-for="(item,index) in nav">
+				<view>{{item}}</view>
+				<view class="line" v-if="navIndex==index"></view>
+			</view>
+		</view>
+		<view class="sub-lists" v-for="(item,index) in goodsList" @click="orderTap(item.id)">
+			<view class="sub-tops">
+				<view>订单号:{{item.order_no}}</view>
+			</view>
+			<view class="contents">
+				<view class="sub-img">
+					<img :src="item.order_item[0].cate_cover" alt="">
+				</view>
+				<view class="goods">
+					<view class="goods-name overflow2">{{item.order_item[0].cate_name}}</view>
+					<view class="scope-texts">
+						<view class="texts">价格范围</view>
+						<view class="scope">{{item.order_item[0].cate_title}}</view>
+						<view class="money">¥<span>{{item.price_total}}</span></view>
+					</view>
+          <view  style="clear:both"></view>
+				</view>
+			</view>
+			<view class="remark">
+				备注:{{item.order_item[0].remark}}
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+				nav:["未付款","已付款"],
+				navIndex:0,
+				pages:{
+					page:1,
+					page_num:10
+				},
+				goodsList:'',
+				loadmore: true,
+
+			}
+		},
+		onLoad() {
+			this.getWashOrderList(0);
+		},
+		onReachBottom() {
+			if (this.loadmore) {
+				this.pages.page = this.pages.page + 1;
+				this.getWashOrderList();
+			}
+		},
+		methods: {
+			navTopIndex(index){
+				this.navIndex=index;
+				this.goodsList=[]
+				this.pages.page=1;
+				this.getWashOrderList();
+				this.loadmore=true
+
+			},
+			orderTap(id){
+				uni.navigateTo({
+					url:"/pages/goodsOrderDetail/index?id="+id
+				})
+			},
+			getWashOrderList(){
+				let data={
+					page:this.pages.page,
+					page_num:this.pages.page_num,
+					status:this.navIndex
+				}
+				api.getWashOrderList(data).then((res)=>{
+					if(res.code==1){
+						let goodsList=res.data.list
+						this.goodsList = [...this.goodsList, ...goodsList];
+						if (res.data.list=='') {
+							this.loadmore = false;
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		padding: 20rpx 30rpx;
+		.shoe-top{
+			height: 72rpx;
+			background: #222222;
+			box-shadow: 0px 4rpx 40rpx 0px rgba(142,142,142,0.07);
+			border-radius: 16rpx;
+			line-height: 72rpx;
+			display: flex;
+			margin-bottom: 30rpx;
+			.classStyle{
+				color: #fff!important;
+			}
+			.views{
+				flex: 1;
+				color: #DDDDDD;
+				text-align: center;
+				position: relative;
+				.line{
+					width: 32rpx;
+					height: 4rpx;
+					background: #FFFFFF;
+					border-radius: 2rpx 2rpx 0px 0px;
+					position: absolute;
+					bottom: 5rpx;
+					left: 150rpx;
+				}
+			}
+		}
+		.sub-lists{
+			.remark{
+				color: #555;
+				font-size: 24rpx;
+				padding: 20rpx 30rpx;
+				border-radius: 32rpx;
+				background-color: #fff;
+			}
+			.contents{
+
+				display: flex;
+				padding: 20rpx 30rpx;
+				background-color: #fff;
+				.goods{
+					margin-left: 20rpx;
+					.scope-texts{
+						//justify-content: space-between;
+						//display: flex;
+						margin-top: 15rpx;
+						height: 50rpx;
+						width:480rpx;
+						line-height: 32rpx;
+						.texts{
+							font-size: 24rpx;
+						    float: left;
+							color: #555;
+						}
+						.scope{
+						  float: left;
+						  padding: 0 20rpx;
+							height: 32rpx;
+							background: #222222;
+							border-radius: 8rpx;
+							text-align: center;
+							line-height: 32rpx;
+							color: #fff;
+							font-size: 20rpx;
+							margin-left: 30rpx;
+						}
+						.money{
+              float: right;
+							color: #FE022B;
+							font-size: 20rpx;
+							// margin-left: 160rpx;
+							span{
+								font-weight: 600;
+								font-size: 32rpx;
+							}
+						}
+					}
+					.goods-rule{
+						font-size: 20rpx;
+						color: #666;
+						margin-top: 15rpx;
+					}
+					.goods-name{
+						color: #222;
+						font-size: 28rpx;
+						// margin-top: 15rpx;
+					}
+				}
+				.sub-img{
+					image{
+						width: 120rpx;
+						height: 120rpx;
+						margin-top: 10rpx;
+					}
+				}
+			}
+			width: 690rpx;
+			border-radius: 16rpx;
+			background-color: #fff;
+			margin-bottom: 25rpx;
+			.contents{
+				display: flex;
+			}
+			.sub-tops{
+				height: 64rpx;
+				background: #222222;
+				border-radius: 16rpx 16rpx 0px 0px;
+				line-height: 64rpx;
+				padding: 0 30rpx;
+				color: #fff;
+				font-size: 28rpx;
+			}
+		}
+	}
+</style>

+ 472 - 0
ctxx_xcx/pages/shoeOrderDetails/index.vue

@@ -0,0 +1,472 @@
+<template>
+	<view>
+		<view class="content">
+			<view class="goodsList">
+				<view class="order-time">订单号:{{info.order_no}}</view>
+				<view class="goods-content">
+					<view class="original-info">
+						<view class="original-img">
+							<img :src="info.order_item[0].cover" alt="">
+						</view>
+						<view class="original-texts">
+							<view class="original-name overflow2">{{info.order_item[0].name}}
+							
+							{{info.order_item[0].desc}}
+							</view>
+							<view class="rule">{{info.order_item[0].goods_spec}}</view>
+						</view>
+
+					</view>
+
+				</view>
+
+				<view class="bottoms">
+          <view style="color: #222;font-size: 24rpx">实付款</view>
+					<view class="money">¥<span>{{info.order_item[0].sell_price}}</span></view>
+				</view>
+			</view>
+			<view class="remarks">
+				<view class="title">详细信息</view>
+				<view class="user-views">
+					<view class="titles">
+						收货信息
+					</view>
+					<view class="user-info">
+						{{info.user_name}},{{info.phone}},
+						{{info.pro_name}}{{info.city_name}}{{info.county_name}}
+						{{info.add_detail}}
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						创建时间
+					</view>
+					<view class="user-info">
+						{{info.create_at}}
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						发货状态
+					</view>
+					<view class="user-info">
+						{{express[info.express_state]}}
+					</view>
+				</view>
+				<view class="user-views" v-if="express_state>0">
+					<view class="titles">
+						快递公司
+					</view>
+					<view class="user-info">
+						{{info.express_company_title}}
+					</view>
+				</view>
+				<view class="user-views" v-if="express_state>0">
+					<view class="titles">
+						物流单号
+					</view>
+					<view class="user-info">
+						{{info.express_company_title}}
+					</view>
+				</view>
+				<view class="user-views" v-if="express_state>0">
+					<view class="titles">
+						发货时间
+					</view>
+					<view class="user-info">
+						{{info.express_company_title}}
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						付款时间
+					</view>
+					<view class="user-info">
+						<span v-if="info.pay_at">{{info.pay_at}}</span>
+						<span style="color:#999" v-else >{{status[info.status]}}</span>
+					</view>
+				</view>
+				<view class="user-views">
+					<view class="titles">
+						备注信息
+					</view>
+					<view class="user-info">
+						{{info.remark}}
+					</view>
+				</view>
+			</view>
+
+
+		</view>
+		<view class="buttons" @click="notMoreTap(info.id)" v-if="info.status==0">
+			立即付款
+		</view>
+		<view class="buttons" @click="orderOk(info.id)" v-if="info.status==1">
+			确认收货
+		</view>
+		<view class="buttons" v-if="info.status==2">
+			已完成
+		</view>
+		<view class="buttons" @click="cancels(info.id)" style="margin: 40rpx auto;" v-if="info.status==0">
+			取消订单
+		</view>
+	</view>
+
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+
+				goodsList:[
+					{
+						image:"url",
+						name:"运动鞋",
+						price:2000,
+						remark:'备注111',
+						money:500,
+						time:"25分32秒",
+						photo:["1","2","3"]
+					},
+					{
+						image:"url",
+						name:"运动鞋",
+						price:2000,
+						remark:'备注111',
+						money:500,
+						time:"25分32秒",
+						photo:["1","2","3"]
+					},
+				],
+				info:'',
+				status:{
+					"0":"待支付",
+					"1":"已支付",
+					"2":"已发货",
+					"4":"已完成",
+					"3":"已收货",
+					"9":"已取消"
+				},
+				express:{
+					"0":"未发货",
+					"1":"已发货",
+					"2":"已签收",
+				},
+				id:""
+			}
+		},
+		onLoad(options) {
+			this.getOrderDetail(options.id)
+			this.id=options.id
+		},
+		methods: {
+			orderOk(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否已确认收货?',
+					success(res) {
+						if (res.confirm) {
+							api.confirmReceipt({"order_id":id}).then((res)=>{
+								if(res.code==1){
+									uni.showToast({
+										icon:"none",
+										title:"收货完成"
+									})
+									that.getOrderDetail(that.id)
+								}
+							})
+						}
+					}
+				});
+			},
+      notMoreTap(id) {
+        // means是点击后需要执行的方法
+        // clickName是一个变量的名字控制是否是第一次点击
+        if (!this.clickName) {
+			console.error(111)
+          // 第一次点击
+          // means()
+          this.pay(id)
+          this.clickName = true;
+          setTimeout(()=>{
+            this.clickName = false;
+          },3000)
+        }
+      },
+			pay(id){
+				api.payOrder({"order_id":id}).then((ret)=>{
+						if(ret.code==1){
+							let config=ret.data.config.config;
+								uni.requestPayment({
+									provider: 'wxpay',
+									timeStamp: config.timestamp,
+									nonceStr: config.nonceStr,
+									package: config.package,
+									signType: config.signType,
+									paySign: config.paySign,
+									success: function(res) {
+										uni.showToast({
+											icon:"none",
+											title:"支付成功"
+										})
+										that.getOrderDetail(that.id)
+									},
+									fail: function(res) {
+										uni.showToast({
+											icon:"none",
+											title:"支付失败"
+										})
+									},
+									complete: function(res) {
+
+									}
+								});
+								}
+							})
+			},
+			cancels(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否要取消订单?',
+					success(res) {
+						if (res.confirm) {
+							api.cancelOrder({"order_id":id}).then((res)=>{
+								if(res.code==1){
+									uni.showToast({
+										icon:"none",
+										title:"取消成功"
+									})
+									that.getOrderDetail(that.id)
+                 setTimeout(()=>{
+                   uni.navigateTo({
+                     url: "/pages/shopList/index",
+
+                   })
+                 },1000)
+								}
+							})
+						}
+					}
+				});
+			},
+			getOrderDetail(id){
+				api.getOrderDetail({"order_id":id}).then((res)=>{
+					this.info=res.data.detail
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.buttons{
+		width: 320rpx;
+		height: 64rpx;
+		background: #222222;
+		border-radius: 16rpx;
+		text-align: center;
+		line-height: 64rpx;
+		color: #fff;
+		font-size: 32rpx;
+		margin: 120rpx auto 20rpx auto;
+	}
+	.remarks{
+		padding: 30rpx 30rpx;
+		background-color: #fff;
+		border-radius: 16rpx;
+		.title{
+			color: #222;
+			font-size: 28rpx;
+		}
+		.user-views{
+			margin-top: 30rpx;
+			.titles{
+				color: #222;
+				font-size: 24rpx;
+			}
+			display: flex;
+			justify-content: space-between;
+			.user-info{
+				word-break: break-all;
+				width: 500rpx;
+				text-align: right;
+				color: #666;
+				font-size: 24rpx;
+				line-height: 30rpx;
+				border-bottom: 1rpx solid #f5f5f5;
+				padding-bottom: 20rpx;
+			}
+		}
+	}
+	page{
+		background-color: #F7F7F7;
+	}
+	.pay-bottom{
+		width: 100%;
+		height: 150rpx;
+		background: #FFFFFF;
+		position: fixed;
+		bottom: 0;
+		display: flex;
+		padding-top: 25rpx;
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-left: 20rpx;
+		}
+		.money{
+			margin-left: 80rpx;
+			color: #222;
+			font-size: 24rpx;
+			margin-top: 15rpx;
+			span{
+				font-size: 28rpx;
+				font-weight: bold;
+			}
+		}
+	}
+	.content{
+		padding:30rpx;
+		.bottom_s{
+			width: 626rpx;
+			height: 90rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			margin: 25rpx auto;
+			line-height: 90rpx;
+			padding: 0 30rpx;
+			display: flex;
+			.icon{
+				margin-top: 10rpx;
+				img{
+					width: 48rpx;
+					height: 48rpx;
+				}
+			}
+			.wx-text{
+				color: #222;
+				margin-left: 16rpx;
+				font-size: 28rpx;
+			}
+		}
+		.bottoms{
+			display: flex;
+			justify-content: space-between;
+			// padding: 30rpx;
+			height: 40rpx;
+			line-height: 40rpx;
+			padding: 20rpx 30rpx;
+			view{
+				color: #222;
+				font-size: 24rpx;
+			}
+			span{
+				color: #222222;
+				font-size: 40rpx;
+				font-weight: bold;
+			}
+		}
+		.remark{
+			color: #555;
+			font-size: 24rpx;
+			padding:0 30rpx;
+		}
+		.goodsList{
+			width: 686rpx;
+			// height: 400rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 2rpx 6rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			margin-bottom: 25rpx;
+			padding-bottom: 20rpx;
+			.goods-content{
+				padding: 30rpx 30rpx 30rpx 14rpx;
+				.contents{
+					display: flex;
+					flex-wrap: wrap;
+					.photo-imgs{
+						.original-img{
+							margin-left: 16rpx;
+							img{
+								width: 128rpx;
+								height: 128rpx;
+								border-radius: 8rpx;
+							}
+						}
+					}
+				}
+				.goods-contents{
+
+
+				}
+
+				.order-texts{
+					color: #555;
+					font-size: 24rpx;
+					margin: 16rpx 0 8rpx 14rpx;
+				}
+				.original-info{
+					display: flex;
+					margin-left: 14rpx;
+					.original-img{
+						img{
+							width: 128rpx;
+							height: 128rpx;
+						}
+					}
+					.original-texts{
+						margin-left: 16rpx;
+						.rule{
+							color: #666;
+							font-size: 20rpx;
+							margin-top: 10rpx;
+						}
+						.original-name{
+							color: #222;
+							font-size: 28rpx;
+							margin-top: 5rpx;
+						}
+						.original-price-scope{
+							display: flex;
+							margin-top: 15rpx;
+							.original-text{
+								color: #555;
+								font-size: 24rpx;
+							}
+							.original-price{
+								width: 132rpx;
+								height: 32rpx;
+								background: #222222;
+								border-radius: 8rpx;
+								color: #fff;
+								text-align: center;
+								line-height: 32rpx;
+								font-size: 20rpx;
+								margin-left: 30rpx;
+							}
+						}
+					}
+				}
+			}
+			.order-time{
+				border-radius: 16rpx 16rpx 0 0 ;
+				height: 64rpx;
+				background-color: #222;
+				font-size: 28rpx;
+				color: #fff;
+				line-height: 64rpx;
+				padding-left: 32rpx;
+			}
+		}
+	}
+</style>

+ 270 - 0
ctxx_xcx/pages/shop/index.vue

@@ -0,0 +1,270 @@
+<template>
+	<view class="content">
+		<nav-bar :navIndex="1"></nav-bar>
+		<view @click="navTaps">
+			<wyb-noticeBar  :text=array bgColor="#fff" color="#666" icons="1"/>
+		</view>
+		<view class="shop-top">
+			<view class="content-s">
+				<scroll-view  class="uni-swiper-tab" scroll-x>
+				<view class="shop-lists" v-for="(item,index) in navList" :key="index" @click="notMoreTap(index,item.id)">
+					<view class="name" :class="index==indexs?'nameStyle':''">{{item.title}}</view>
+					<view class="icons" v-if="index==indexs">
+						<img src="/static/index/shopIcons.png" alt="">
+					</view>
+
+				</view>
+				</scroll-view>
+			</view>
+
+		</view>
+		<view class="goods-content">
+
+			<view class="goods-lists" @click="goodsTap(item.id)" v-for="(item,index) in goodsList" :key="index">
+				<view class="goods-img">
+					<image :src="item.cover"></image>
+				</view>
+				<view class="goods-name overflow2">
+					{{item.name}}
+				</view>
+				<view class="money">
+					¥<span>{{item.low_price}}</span>
+				</view>
+			</view> 
+			<view v-if="goodsList.length>=4" style="height: 200rpx;width: 100%;"></view>
+		</view>
+
+
+
+
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	import wybNoticeBar from '@/components/wyb-noticeBar/wyb-noticeBar.vue'
+	import navBar from '@/components/nav-bar/nav-bar.vue'
+	export default {
+		components:{wybNoticeBar,navBar},
+		data() {
+			return {
+				clickName:false,
+				loadmore:true,
+				sortId:'',
+				pages:{
+					page:1,
+					pageNum:10
+				},
+				array:['测试11'],
+				navList:["回力","PRADA","耐克","耐克1","耐克2","耐克3","耐克4","耐克5"],
+				indexs:0,
+				goodsList:[
+
+					],
+			}
+		},
+		onLoad() {
+			this.getShopSort()
+			this.sysConfig()
+			
+		},
+		onShow() {
+			// this.goodsList=[]
+			
+		},
+		onReachBottom() {
+			if (this.loadmore) {
+				this.pages.page = this.pages.page + 1;
+				this.getGoodsList(this.sortId);
+			}
+		},
+		notMoreTap(id) {
+			this.loadmore=true;
+		  // means是点击后需要执行的方法
+		  // clickName是一个变量的名字控制是否是第一次点击
+		  if (!this.clickName) {
+		    // 第一次点击
+		    // means()
+			
+		    this.getGoodsList()
+		    this.clickName = true;
+		    setTimeout(()=>{
+		      this.clickName = false;
+		    },1000)
+		  } else {
+		
+		  }
+		},
+		methods: {
+			notMoreTap(index,id) {
+			  // means是点击后需要执行的方法
+			  // clickName是一个变量的名字控制是否是第一次点击
+			  if (!this.clickName) {
+			    // 第一次点击
+			    // means()
+				this.pages.page=1;
+				this.goodsList=[]
+				this.indexs=index;
+				this.getShopSort(id)
+				uni.showLoading({
+					title:"正在加载"
+				})
+			    this.clickName = true;
+			    setTimeout(()=>{
+			      this.clickName = false;
+			    },1000)
+			  }
+			},				
+			navTaps(){
+				uni.navigateTo({
+					url:"/pages/shopNotice/index"
+				})
+			},
+			sysConfig(){
+				api.getSysConfig({"search_name":"notice_title"}).then((res)=>{
+						if(res.code==1){
+							this.array[0]=res.data.notice_title
+					}
+				})
+			},
+			goodsTap(id){
+				uni.navigateTo({
+					url:"/pages/goodsDetail/index?id="+id
+				})
+			},			
+			
+			//获取商品分类 
+			getShopSort(id){
+				api.getGoodsCate().then((res)=>{
+					if(res.code==1){					
+						this.navList=res.data.list 
+						this.getGoodsList(id?id:res.data.list[0].id)
+						this.sortId=res.data.list[0].id
+					}
+				})
+			},
+			
+			//根据分类ID获取商品列表
+			getGoodsList(id){
+				
+				let data={
+					page:this.pages.page,
+					page_num:this.pages.pageNum,
+					first_classify:id,
+					sort_type: "1",
+				} 
+				api.getGoodsList(data).then((res)=>{
+					if(res.code==1){	 
+						uni.hideLoading() 
+						let goodsList=res.data.list 
+						this.goodsList = [...this.goodsList, ...goodsList];
+						console.error(res.data.list)
+						if (res.data.list=='') {
+							this.loadmore = false;
+						}
+					}
+				})
+			}
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	.class-s{
+		padding-bottom: 200rpx;
+	}
+	.uni-swiper-tab{
+		white-space: nowrap;
+	}
+	.content{
+		.goods-content{
+			background-color: #FFFFFF;
+			display: flex;
+			flex-wrap: wrap;
+			padding: 30rpx;
+			margin-bottom: 200rpx;
+			.goods-lists:nth-child(even){
+				margin-left: 25rpx;
+			}
+			.goods-lists{
+				width: 332rpx;
+				padding-bottom: 20rpx;
+				background: #FFFFFF;
+				box-shadow: 0px 4rpx 20rpx 0px rgba(142,142,142,0.13);
+				border-radius: 16rpx;
+				margin-bottom: 20rpx;
+				.goods-name{
+					width: 300rpx;
+					color: #222;
+					font-size: 24rpx;
+					margin-left: 12rpx;
+				}
+				.money{
+					color: #222;
+					font-size: 20rpx;
+					margin: 10rpx 0 0 10rpx;
+					span{
+						font-weight: 600;
+						font-size: 32rpx;
+					}
+				}
+				.goods-img{
+					image{
+						width: 330rpx;
+						height: 330rpx;
+						border-radius: 16rpx 16rpx 0 0;
+					}
+				}
+			}
+		}
+		.shop-top{
+			width: 100%;
+			height: 80rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			margin: 25rpx 0;
+			line-height: 80rpx;
+			display: flex;
+			.content-s{
+				display: flex;
+				width: 750rpx;
+				overflow-x: auto;
+				margin-left: 30rpx;
+				margin-right: 30rpx;
+				.shop-lists{
+					position: relative;
+					margin-left: 25rpx;
+					// width: 150rpx;
+					display: inline-block;
+					padding: 0;
+					.name{
+						color: #999;
+						font-size: 28rpx;
+					}
+
+					.nameStyle{
+						color: #222;
+						font-size: 28rpx;
+						font-weight: 600;
+					}
+					.icons{
+						margin-top: 20rpx;
+						text-align: center;
+						position: absolute;
+						top: 0rpx;
+						left: 50%;
+						margin-left:-15rpx;
+
+						img{
+							width: 20rpx;
+							height: 8rpx;
+						}
+					}
+				}
+			}
+
+
+		}
+	}
+</style>

+ 206 - 0
ctxx_xcx/pages/shopList/index.vue

@@ -0,0 +1,206 @@
+<template>
+	<view class="content">
+		<view class="shoe-top">
+			<view class="views" @click="navTopIndex(index)" :class="navIndex==index?'classStyle':''" v-for="(item,index) in nav">
+				<view>{{item}}</view>
+				<view class="line" v-if="navIndex==index"></view>
+			</view>
+		</view>
+		<view class="sub-lists" @click="goodsTap(item.id)" v-for="(item,index) in goodsList">
+			<view class="sub-tops">
+				<view>订单号:{{item.order_no}}</view>
+			</view>
+			<view class="contents">
+				<view class="sub-img">
+					<img :src="item.order_item[0].goods_cover" alt="">
+				</view>
+				<view class="goods">
+					<view class="goods-name overflow2">
+					
+					{{item.order_item[0].goods_name}}
+					
+					{{item.order_item[0].desc}}
+					</view>
+					<view class="scope-texts">
+						<view class="texts">{{item.order_item[0].goods_spec}}</view>
+						<view class="money">¥<span>{{item.order_item[0].sell_price}}</span></view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+				nav:["未付款","已付款"],
+				navIndex:0,
+				pages:{
+					page:1,
+					pageNum:10
+				},
+				goodsList:[],
+				loadmore:true,
+			} 
+		},
+		onLoad() {
+			this.getOrderList();
+		},
+		onReachBottom() {
+			if (this.loadmore) {
+			 	this.pages.page = this.pages.page + 1;
+				this.getOrderList();
+			}
+		},
+		methods: { 
+			goodsTap(id){
+				uni.navigateTo({
+					url:"/pages/shoeOrderDetails/index?id="+id
+				}) 
+			},
+			getOrderList(){	
+				let data={
+					"page":this.pages.page,
+					"page_num":this.pages.pageNum,
+					// "status":this.navIndex,
+					"pay_state":this.navIndex, 
+				}
+				api.getOrderList(data).then((res)=>{
+					if(res.code==1){
+						let goodsList=res.data.list
+						this.goodsList = [...this.goodsList, ...goodsList];
+						if (res.data.list=='') {
+							this.loadmore = false;
+						}
+					}
+				})
+			},
+			navTopIndex(index){
+				this.navIndex=index;
+				this.goodsList=[]
+				this.pages.page=1;
+				this.getOrderList();
+				this.loadmore=true
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		padding: 20rpx 30rpx;
+		.shoe-top{
+			height: 72rpx;
+			background: #222222;
+			box-shadow: 0px 4rpx 40rpx 0px rgba(142,142,142,0.07);
+			border-radius: 16rpx;
+			line-height: 72rpx;
+			display: flex;
+			margin-bottom: 30rpx;
+			.classStyle{
+				color: #fff!important;
+			}
+			.views{
+				flex: 1;
+				color: #DDDDDD;
+				text-align: center;
+				position: relative;
+				.line{
+					width: 32rpx;
+					height: 4rpx;
+					background: #FFFFFF;
+					border-radius: 2rpx 2rpx 0px 0px;
+					position: absolute;
+					bottom: 5rpx;
+					left: 150rpx;
+				}
+			}
+		}
+		.sub-lists{
+			.remark{
+				color: #555;
+				font-size: 24rpx;
+				padding: 20rpx 30rpx;
+				border-radius: 32rpx;
+				background-color: #fff;
+			}
+			.contents{
+				
+				display: flex;
+				padding: 20rpx 30rpx;
+				background-color: #fff;
+				.goods{
+					width: 100%;
+					margin-left: 20rpx;
+					.scope-texts{
+						display: flex;
+						margin-top: 15rpx;
+						line-height: 32rpx;
+						justify-content: space-between;
+						.texts{
+							font-size: 24rpx;
+							color: #555;
+						}
+						.scope{
+							width: 132rpx;
+							height: 32rpx;
+							background: #222222;
+							border-radius: 8rpx;
+							text-align: center;
+							line-height: 32rpx;
+							color: #fff;
+							font-size: 20rpx;
+							margin-left: 30rpx;
+						}
+						.money{
+							color: #FE022B;
+							font-size: 20rpx;
+							margin-left: 160rpx;
+							span{
+								font-weight: 600;
+								font-size: 32rpx;
+							}
+						}
+					}
+					.goods-rule{
+						font-size: 20rpx;
+						color: #666;
+						margin-top: 15rpx;
+					}
+					.goods-name{
+						width: 500rpx;
+						color: #222;
+						font-size: 28rpx;
+						margin-top: 7rpx;
+					}
+				}
+				.sub-img{
+					image{
+						width: 120rpx;
+						height: 120rpx;
+						margin-top: 10rpx;
+					}
+				}
+			}
+			width: 690rpx;
+			border-radius: 16rpx;
+			background-color: #fff;
+			margin-bottom: 25rpx;
+			.contents{
+				display: flex;
+			}
+			.sub-tops{
+				height: 64rpx;
+				background: #222222;
+				border-radius: 16rpx 16rpx 0px 0px;
+				line-height: 64rpx;
+				padding: 0 30rpx;
+				color: #fff;
+				font-size: 28rpx;
+			}
+		}
+	}
+</style>

+ 54 - 0
ctxx_xcx/pages/shopNotice/index.vue

@@ -0,0 +1,54 @@
+<template>
+	<view class="content">
+		<view class="title">{{title}}</view>
+			<mp-html class="style-s" :content="contenet" />
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	import util from 'utils/util'
+	import uParse from '@/components/gaoyia-parse/parse.vue'
+	export default {
+		 components: {
+		    uParse
+		  },
+		data() {
+			return {
+				contenet:'',
+				title:''
+			}
+		},
+		onLoad() {
+			api.getSysConfig({}).then((res)=>{
+				if(res.code==1){
+					  this.contenet=res.data.mall_notice_content
+					  this.title=res.data.mall_notice_title
+				}
+			})
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss">
+  .style-s{
+    font-size: 24rpx;
+  }
+	.title{
+		padding: 20rpx 0;
+		font-size: 32rpx;
+		color: #222;
+		font-weight: bold;
+		text-align: center;
+	}
+	.content{
+		padding:30rpx;
+		background-color: #fff;
+		width: 640rpx;
+		margin: 0 auto;
+		border-radius: 16rpx;
+	}
+</style>

+ 638 - 0
ctxx_xcx/pages/shopesOrder/index.vue

@@ -0,0 +1,638 @@
+<template>
+	<view>
+		<view class="content">
+		<view class="goodsList" v-for="(item,index) in goodsList" :key="index">
+			<!-- <view class="order-time">剩余付款时间:{{item.time}}</view> -->
+			<view class="goods-content">
+				<view class="original-info">
+					<view class="original-img">
+						<img :src="item.list[item.indexs].logo" alt="">
+					</view>
+					<view class="original-texts">
+						<view class="original-name">{{item.list[item.indexs].title}}</view>
+						<view class="original-price-scope">
+							<view class="original-text">价格范围</view>
+							<view class="original-price">
+							{{item.list[item.indexs].ladder_set[item.checkIndexs].title}}
+							</view>
+						</view>
+					</view>
+
+				</view>
+				<view class="order-texts">原始照片</view>
+				<view class="contents">
+					<view class="photo-imgs" v-for="(items,index) in item.imageLiss">
+						<view class="original-img" v-if="items">
+							<img :src="items" alt="">
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="remark">
+				备注:{{item.remark}}
+			</view>
+			<view class="bottoms">
+				<view style="color: #222;font-size: 24rpx">实付款</view>
+				<view class="money">¥<span>{{item.list[item.indexs].ladder_set[item.checkIndexs].price}}</span></view>
+			</view>
+		</view>
+			<view class="user-info">
+				<view class="title">
+					填写收货地址
+				</view>
+				<view style="height: 20rpx;"></view>
+				<view class="views" >
+					<view class="name">收货人</view>
+					<view class="input" >
+						<input v-model="from.userName" style="margin-left: 55rpx;" type="text" class="inputs" placeholder="填写姓名"/>
+					</view>
+				</view>
+				<view class="views">
+					<view class="name">联系电话</view>
+					<view class="input">
+						<input maxlength="11" v-model="from.userPhone" class="inputs" type="number" placeholder="填写手机号"/>
+					</view>
+				</view>
+				<pick-regions :defaultRegion="defaultRegionCode" @getRegion="handleGetRegion">
+				<view class="views">
+					<view class="name">所在区域</view>
+					<view class="input">
+						<input disabled="disabled" v-model="from.address" class="inputs" placeholder="选择收件地区(省、市、区)"/>
+					</view>
+				</view>
+				</pick-regions>
+				<view class="views">
+					<view class="name">详细地址</view>
+					<view class="input">
+						<input v-model="from.addDetail" class="inputs" placeholder="例如门牌号、小区、楼层等"/>
+					</view>
+				</view>
+
+			</view>
+
+				<!-- <view class="goods-infos">
+					<view class="goods-img">
+						<image :src="goods.cover"></image>
+					</view>
+					<view class="goods-right">
+						<view class="goods-name overflow2">{{goodsInfo.name}} {{goodsInfo.desc}}</view>
+						<view class="goods-rule">{{goods.goods_spec}}</view>
+					</view>
+				</view> -->
+				<view class="pay" >
+					<view class="wx-icon">
+						<image src="../../static/index/wxIcon.png"></image>
+					</view>
+					<view class="texts" style="flex:1">微信支付</view>
+          <view class="wxIcon">
+            <image src="../../static/index/check-icons.png"></image>
+
+          </view>
+				</view>
+				<view style="height: 200rpx;"></view>
+
+		</view>
+		<view class="pay-bottom">
+			<view class="money">实付款:<span>¥<span style="font-size: 40rpx;">{{price}}</span></span></view>
+      <view class="button" @click="$global.clicks(pay)">立即购买</view>
+
+    </view>
+	</view>
+
+</template>
+
+<script>
+import api from 'utils/api'
+import pickRegions from '@/components/pick-regions/pick-regions.vue'
+	export default {
+		components:{pickRegions},
+		data() {
+			return {
+				goodsList:[
+					{
+						image:"url",
+						name:"运动鞋",
+						price:2000,
+						remark:'备注111',
+						money:500,
+						time:"25分32秒",
+						photo:["1","2","3"]
+					},
+					{
+						image:"url",
+						name:"运动鞋",
+						price:2000,
+						remark:'备注111',
+						money:500,
+						time:"25分32秒",
+						photo:["1","2","3"]
+					},
+				],
+				 from:{
+					 "userName":"",
+					 "userPhone":"",
+					 "userDetail":"",
+					 "proName":"",
+					 "cityName":"",
+					 "countyName":"",
+					 "addDetail":"",
+					 "remark":"",
+					 "address":""
+				 },
+				 pickerValueDefault: [0, 0, 0],
+				 pickerText: '',
+				 status:0,//0代表是预约 1代表下单购买
+				 goods:'',
+			     region:[],
+				 goodsInfo:'',
+				 price:'',
+				 }
+		},
+		onShow() {
+			this.getUserInfo();
+		},
+		onLoad(options) {
+			let goods=JSON.parse(uni.getStorageSync("goodsList"))
+			if(goods){
+				this.goodsList=goods;
+				let arr = {};
+				let arrs=[];
+				console.error(goods)
+
+			}
+			if(options){
+				this.price=options.price
+			}
+			let infos=uni.getStorageSync("userInfo")
+			if(infos){
+				this.from.userName=infos.userName
+				this.from.userPhone=infos.userPhone
+				this.from.userDetail=infos.userDetail
+				this.from.proName=infos.proName
+				this.from.cityName=infos.cityName
+				this.from.countyName=infos.countyName
+				this.from.addDetail=infos.addDetail
+				this.from.remark=infos.remark
+				this.from.address=infos.address
+			}
+			// this.getAddress()
+		},
+		onUnload() {
+			let from=this.from;
+			uni.setStorageSync("userInfo",from)
+		},
+		methods: {
+			//获取用户信息
+			getUserInfo(){
+				api.getUserInfo().then((res)=>{
+					console.error(res)
+					if(res.code==1){
+						this.userInfos=res.data.detail
+					}
+				})
+			},
+			 tojson(arr){
+				if(!arr.length) return null;
+
+				var i = 0;
+				len = arr.length,
+				array = [];
+				for(;i<len;i++){
+					array.push({"projectname":arr[i][0],"projectnumber":arr[i][1]});
+				}
+				return JSON.stringify(array);
+			},
+			//下单
+			pay(){
+				let from=this.from;
+				if(from.userName==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入姓名"
+					})
+					return;
+				}
+				if(from.userPhone==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入手机号"
+					})
+					return;
+				}
+				if(!(/^1[3456789]\d{9}$/.test(from.userPhone))){
+					uni.showToast({
+						icon:"none",
+						title:"请输入正确的手机号"
+					})
+					return;
+				}
+				if(from.address==''){
+					uni.showToast({
+						icon:"none",
+						title:"请选择区域"
+					})
+					return;
+				}
+				if(from.addDetail==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入详细地址"
+					})
+					return;
+				}
+
+
+				let data={
+					"goods_json":"",
+					"pro_name":from.proName,
+					"city_name":from.cityName,
+					"county_name":from.countyName,
+					"add_detail":from.addDetail,
+					"phone":from.userPhone,
+					"user_name":from.userName,
+					"remark":from.remark,
+				}
+				let goodsList=this.goodsList;
+				let data_ss=[];
+				let lists="";
+				let arr=[];
+				for(let i=0;i<goodsList.length;i++){
+					let index_s=goodsList[i].indexs
+					let _index=goodsList[i].checkIndexs
+					lists={"cate_id":goodsList[i].list[index_s].id,
+					ladder_key:goodsList[i].list[index_s].ladder_set[_index].ladder_key,
+					images:goodsList[i].imageLiss?goodsList[i].imageLiss.join(','):[],remark:goodsList[i].remark}
+					data_ss.push(lists)
+				}
+				data.goods_json=JSON.stringify(data_ss)
+				api.createOrders(data).then((res)=>{
+					if(res.code==1){
+						api.payOrders({"order_id":res.data.order_id}).then((ret)=>{
+
+							if(ret.code==1){
+								let config=ret.data.config.config;
+									uni.requestPayment({
+										provider: 'wxpay',
+										timeStamp: config.timestamp,
+										nonceStr: config.nonceStr,
+										package: config.package,
+										signType: config.signType,
+										paySign: config.paySign,
+										success: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付成功"
+											})
+											uni.navigateTo({
+												url:"/pages/orderSuccess/index"
+											})
+										},
+										fail: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付失败"
+											})
+										},
+										complete: function(res) {
+											uni.showToast({
+												icon:"none",
+												title:"支付取消"
+											})
+										}
+									});
+							}
+						})
+					}
+				})
+			},
+			 handleGetRegion(e){
+                this.region = e
+				// e 确认后选中的数据
+				this.pickerText = JSON.stringify(e)
+				this.from.proName=e[0].name;
+				this.from.cityName=e[1].name;
+				this.from.countyName=e[2].name;
+				this.from.address=e[0].name+','+e[1].name+','+e[2].name
+            },
+			getAddress(){
+				api.getAreaTree({"level":3}).then((res)=>{
+					if(res.code==1){
+						this.treeData=res.data.list;
+						console.error(res.data.list)
+					}
+				})
+			},
+			//预约订单
+			submit(){
+				let from=this.from;
+				if(from.userName==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入姓名"
+					})
+					return;
+				}
+				if(from.userPhone==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入手机号"
+					})
+					return;
+				}
+				if(!(/^1[3456789]\d{9}$/.test(from.userPhone))){
+					uni.showToast({
+						icon:"none",
+						title:"请输入正确的手机号"
+					})
+					return;
+				}
+				if(from.address==''){
+					uni.showToast({
+						icon:"none",
+						title:"请选择区域"
+					})
+					return;
+				}
+				if(from.addDetail==''){
+					uni.showToast({
+						icon:"none",
+						title:"请输入详细地址"
+					})
+					return;
+				}
+				let data={
+					"goods_id":this.goodsInfo.id,
+					"spec_id":this.goods.id,
+					"pro_name":from.proName,
+					"city_name":from.cityName,
+					"county_name":from.countyName,
+					"add_detail":from.addDetail,
+					"phone":from.userPhone,
+					"user_name":from.userName,
+					"remark":from.remark,
+				}
+				api.makeAppointment(data).then((res)=>{
+					if(res.code==1){
+						uni.showToast({
+							icon:"none",
+							title:"预约成功",
+							success() {
+								setTimeout(()=>{
+									uni.navigateTo({
+										url:"/pages/subscribe/index"
+									})
+								},2000)
+							}
+						})
+					}
+				})
+			},
+
+		}
+	}
+</script>
+
+<style lang="scss">
+.wxIcon{
+  margin-right: 32rpx;
+  image{
+    width: 32rpx;
+    height: 32rpx;
+  }
+}
+	.bottoms{
+		display: flex;
+		justify-content: space-between;
+		padding:30rpx;
+    .money{
+      font-size: 28rpx;
+      color: #222;
+      span{
+        font-size: 40rpx;
+        font-weight: 600;
+      }
+    }
+	}
+	.goodsList{
+		width: 686rpx;
+		// height: 400rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 2rpx 6rpx 0px rgba(231,231,231,0.41);
+		border-radius: 16rpx;
+		margin-bottom: 25rpx;
+		.goods-content{
+			padding: 30rpx 30rpx 30rpx 14rpx;
+			.contents{
+				display: flex;
+				flex-wrap: wrap;
+				.photo-imgs{
+					.original-img{
+						margin-left: 16rpx;
+						img{
+							width: 128rpx;
+							height: 128rpx;
+							border-radius: 8rpx;
+						}
+					}
+				}
+			}
+			.goods-contents{
+
+
+			}
+
+			.order-texts{
+				color: #555;
+				font-size: 24rpx;
+				margin: 16rpx 0 8rpx 14rpx;
+			}
+			.original-info{
+				display: flex;
+				margin-left: 14rpx;
+				.original-img{
+					img{
+						width: 128rpx;
+						height: 128rpx;
+					}
+				}
+				.original-texts{
+					margin-left: 16rpx;
+					.original-name{
+						color: #222;
+						font-size: 28rpx;
+						margin-top: 20rpx;
+					}
+					.original-price-scope{
+						display: flex;
+						margin-top: 15rpx;
+						.original-text{
+							color: #555;
+							font-size: 24rpx;
+						}
+						.original-price{
+							width: 132rpx;
+							height: 32rpx;
+							background: #222222;
+							border-radius: 8rpx;
+							color: #fff;
+							text-align: center;
+							line-height: 32rpx;
+							font-size: 20rpx;
+							margin-left: 30rpx;
+						}
+					}
+				}
+			}
+		}
+		.order-time{
+			border-radius: 16rpx 16rpx 0 0 ;
+			height: 64rpx;
+			background-color: #222;
+			font-size: 28rpx;
+			color: #fff;
+			line-height: 64rpx;
+			padding-left: 32rpx;
+		}
+	}
+	.pay-bottom{
+		width: 100%;
+		height: 110rpx;
+		background: #FFFFFF;
+		position: fixed;
+    z-index: 111;
+    justify-content: space-between;
+		bottom: 0;
+		display: flex;
+		padding: 40rpx 20rpx 0 20rpx;
+		.button{
+			text-align: center;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			margin-right: 50rpx;
+		}
+		.money{
+      text-align: right;
+      flex: 1;
+      margin-right: 20rpx;
+			//margin-left: 120rpx;
+			color: #222;
+			font-size: 24rpx;
+			margin-top: 15rpx;
+			span{
+				font-size: 28rpx;
+				font-weight: bold;
+			}
+		}
+	}
+	.content{
+		padding: 30rpx;
+
+		.pay{
+			height: 90rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			display: flex;
+			margin: 25rpx 0;
+			line-height: 90rpx;
+      justify-content: space-between;
+			.texts{
+				color: #222;
+				font-size: 28rpx;
+				margin-left: 15rpx;
+			}
+			.wx-icon{
+				image{
+					margin: 20rpx 0 0 30rpx;
+					width: 48rpx;
+					height: 48rpx;
+				}
+			}
+		}
+		.goods-infos{
+			height: 124rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			padding: 30rpx;
+			display: flex;
+			.goods-img{
+				image{
+					width: 120rpx;
+					height: 120rpx;
+				}
+			}
+			.goods-right{
+				margin-left: 20rpx;
+				.goods-name{
+					color: #222;
+					font-size: 24rpx;
+				}
+				.goods-rule{
+					color: #666;
+					font-size: 20rpx;
+					margin-top: 15rpx;
+				}
+			}
+		}
+		.remark{
+			// height: 252rpx;
+			// background: #FFFFFF;
+			// box-shadow: 0px 4rpx 12rpx 0px rgba(231,231,231,0.41);
+      flex-wrap: wrap;
+      color: #555;
+      font-size: 24rpx;
+			border-radius: 16rpx;
+			margin:25rpx 0;
+			padding: 30rpx;
+			.title{
+				font-size: 28rpx;
+				color: #222;
+			}
+			.place{
+				color: #999;
+			}
+			.text-area{
+				font-size: 24rpx;
+				color: #333;
+				margin-top: 25rpx;
+			}
+		}
+		.user-info{
+			height:400rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4px 12rpx 0px rgba(231,231,231,0.41);
+			border-radius: 16rpx;
+			width: 630rpx;
+			background-color: #fff;
+			padding: 30rpx;
+
+			.views{
+				display: flex;
+				// margin-top: 30rpx;
+				height: 80rpx;
+				line-height: 80rpx;
+				font-size: 24rpx;
+				.input{
+					.inputs{
+
+						height: 80rpx;
+						line-height: 80rpx;
+						border-bottom: 1rpx solid #f5f5f5;
+						width: 400rpx;
+						margin-left: 30rpx;
+					}
+				}
+			}
+			.title{
+				font-size: 28rpx;
+				color: #222;
+
+			}
+		}
+	}
+</style>

+ 64 - 0
ctxx_xcx/pages/subscribe/index.vue

@@ -0,0 +1,64 @@
+<template>
+	<view class="content">
+		<view class="order-icon">
+			<img src="/static/index/subscribe.png" alt="">
+		</view>
+		<view class="order-text">预约成功</view>
+		<view class="order-text">
+			潮庭工作人员将在9:00上班后和您联系,请保持手机通畅
+		</view>
+		<view class="button" @click="indexTaps">
+			返回首页
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			indexTaps(){
+				uni.reLaunch({
+					url:"/pages/index/index"
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		text-align: center;
+		.order-icon{
+			margin-top: 120rpx;
+			img{
+				width: 160rpx;
+				height: 160rpx;
+			}
+		}
+		.order-text{
+			color: #222;
+			font-size: 36rpx;
+			// margin-top: 20rpx;
+			width: 600rpx;
+			margin: 20rpx auto 0 auto;
+			line-height: 50rpx;
+		}
+		.button{
+			width: 320rpx;
+			height: 80rpx;
+			background: #222222;
+			border-radius: 40rpx;
+			color: #fff;
+			font-size: 32rpx;
+			line-height: 80rpx;
+			margin: 120rpx auto;
+		}
+	}	
+</style>

+ 208 - 0
ctxx_xcx/pages/subscribeDetails/index.vue

@@ -0,0 +1,208 @@
+<template>
+	<view class="content">
+		<view class="sub-lists">
+			<view class="sub-tops">
+				<view>预约号:{{info.code}}</view>
+			</view>
+			<view class="contents">
+				<view class="sub-img">
+					<img :src="info.cover" alt="">
+				</view>
+				<view class="goods">
+					<view class="goods-name overflow2">{{info.goods_name}}
+					{{info.desc}}
+					</view>
+					<view class="goods-rule">{{info.goods_spec}}</view>
+					
+				</view>
+			</view>
+		</view>
+		<view class="remarks">
+			<view class="title">详细信息</view>
+			<view class="user-views">
+				<view class="titles">
+					收货信息
+				</view>
+				<view class="user-info">
+					{{info.user_name}},{{info.phone}},
+					{{info.pro_name}}{{info.city_name}}{{info.county_name}}
+					{{info.add_detail}}
+					
+				</view>
+			</view>
+			<view class="user-views">
+				<view class="titles">
+					预约备注
+				</view>
+				<view class="user-info">
+					{{info.remark}}
+					
+				</view>
+			</view>
+		</view>
+		<view v-if="info.status==0" @click="cancel(info.id)" class="cancel">取消预约</view>
+		<view v-if="info.status==0" @click="submits(info.id)" class="cancel">完成预约</view>
+		<!-- <view v-if="info.status==1" class="cancel">已完成</view> -->
+		<view v-if="info.status==9" class="cancel color-s">已取消</view>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+
+	export default {
+		data() {
+			return {
+				info:{},
+				id:''
+			}
+		},
+		onLoad(options) {
+			if(options){
+				this.getAppointmentInfo(options.id);
+				this.id=options.id
+			}
+		},
+		methods: {
+			submits(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否已完成预约?',
+					success(res) {
+						if (res.confirm) {
+							api.completeAppointment({"id":id}).then((res)=>{
+								if(res.code==1){
+									that.getAppointmentInfo(that.id)
+								}
+								uni.showToast({
+									icon:"none",
+									title:"预约完成"
+								})
+							})
+						}
+					}
+				});
+			},
+			cancel(id){
+				let that=this;
+				 uni.showModal({
+					title: '提示',
+					content: '是否要取消预约?',
+					success(res) {
+						if (res.confirm) {
+							api.cancelAppointment({"id":id,"cancel_desc":""}).then((res)=>{
+								if(res.code==1){
+									that.getAppointmentInfo(that.id)
+								}
+							})
+							uni.showToast({
+								icon:"none",
+								title:"预约已取消"
+							})
+						}
+					}
+				});
+			},
+			getAppointmentInfo(id){
+				api.getAppointmentInfo({"id":id}).then((res)=>{
+					if(res.code==1){
+						this.info=res.data.detail
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.color-s{
+		background-color: #999!important;
+	}
+	.cancel{
+		width: 320rpx;
+		text-align: center;
+		height: 64rpx;
+		line-height:64rpx;
+		color: #fff;
+		font-size: 32rpx;
+		background: #222222;
+		margin: 70rpx auto;
+		border-radius: 16rpx;
+	}
+	.content{
+		padding: 20rpx 30rpx;
+		.remarks{
+			padding: 30rpx 30rpx;
+			background-color: #fff;
+			border-radius: 16rpx;
+			.title{
+				color: #222;
+				font-size: 28rpx;
+			}
+			.user-views{
+				margin-top: 30rpx;
+				.titles{
+					color: #222;
+					font-size: 24rpx;
+				}
+				display: flex;
+				justify-content: space-between;
+				.user-info{
+					word-break: break-all;
+					width: 500rpx;
+					// flex-wrap: wrap;
+					color: #666;
+					font-size: 24rpx;
+					line-height: 30rpx;
+					border-bottom: 1rpx solid #f5f5f5;
+					padding-bottom: 20rpx;
+				}
+			}
+		}
+		.sub-lists{
+			.contents{
+				display: flex;
+				padding:30rpx;
+				width: 100%;
+				background-color: #fff;
+				.goods{
+					margin-left: 20rpx;
+					
+					.goods-rule{
+						font-size: 20rpx;
+						color: #666;
+						margin-top: 15rpx;
+					}
+					.goods-name{
+						width: 480rpx;
+						color: #222;
+						font-size: 24rpx;
+					}
+				}
+				.sub-img{
+					image{
+						width: 120rpx;
+						height: 120rpx;
+					}
+				}
+			}
+			width: 630rpx;
+			background-color: #fff;
+			margin-bottom: 25rpx;
+			.contents{
+				display: flex;
+			}
+			.sub-tops{
+				height: 64rpx;
+				background: #222222;
+				border-radius: 16rpx 16rpx 0px 0px;
+				line-height: 64rpx;
+				width: 100%;
+				padding: 0 30rpx;
+				color: #fff;
+				font-size: 28rpx;
+			}
+		}
+	}
+</style>

+ 122 - 0
ctxx_xcx/pages/subscribeList/index.vue

@@ -0,0 +1,122 @@
+<template>
+	<view class="content">
+		<view class="sub-lists" v-for="(item,index) in list" @click="goodsTap(item.id)" >
+			<view class="sub-tops">
+				<view>预约号:{{item.code}}</view>
+			</view>
+			<view class="contents">
+				<view class="sub-img">
+					<img :src="item.cover" alt="">
+				</view>
+				<view class="goods">
+					<view class="goods-name overflow2">{{item.goods_name}} 
+					{{item.desc}}
+					</view>
+					<view class="goods-rule">{{item.goods_spec}}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	export default {
+		data() {
+			return {
+				pages:{
+					page:1,
+					pageNum:10
+				},
+				list:[],
+				loadmore: true,
+			}
+		},
+		onLoad() {
+
+		},
+		onReachBottom() {
+			if (this.loadmore) {
+				this.pages.page = this.pages.page + 1;
+				this.getAppointmentList();
+			}
+		},
+		onShow() {
+			this.getAppointmentList();
+		},
+		methods: {
+			goodsTap(id){
+				console.error(id)
+				uni.navigateTo({
+					url:"/pages/subscribeDetails/index?id="+id
+				})
+			},
+			getAppointmentList(){
+				let data={
+					page:this.pages.page,
+					page_num:this.pages.pageNum,
+					status:-1,
+				}
+				api.getAppointmentList(data).then((res)=>{
+					if(res.code==1){
+						// this.list=res.data.list
+						let goodsList=res.data.list
+						this.list = [...this.list, ...goodsList];
+						if (res.data.list=='') {
+							this.loadmore = false;
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		padding: 20rpx 30rpx;
+		.sub-lists{
+			.contents{
+				display: flex;
+				padding: 20rpx 30rpx;
+				width: 100%;
+				background-color: #fff;
+				.goods{
+					margin-left: 20rpx;
+					.goods-rule{
+						font-size: 20rpx;
+						color: #666;
+						margin-top: 15rpx;
+					}
+					.goods-name{
+						width: 470rpx;
+						color: #222;
+						font-size: 24rpx;
+					}
+				}
+				.sub-img{
+					image{
+						width: 120rpx;
+						height: 120rpx;
+					}
+				}
+			}
+			width: 630rpx;
+			background-color: #fff;
+			margin-bottom: 25rpx;
+			.contents{
+				display: flex;
+			}
+			.sub-tops{
+				height: 64rpx;
+				background: #222222;
+				border-radius: 16rpx 16rpx 0px 0px;
+				line-height: 64rpx;
+				width: 100%;
+				padding: 0 30rpx;
+				color: #fff;
+				font-size: 28rpx;
+			}
+		}
+	}
+</style>

+ 50 - 0
ctxx_xcx/pages/userDeal/index.vue

@@ -0,0 +1,50 @@
+<template>
+	<view class="content">
+		<view class="title">潮庭洗鞋小程序使用协议</view>
+			<rich-text :nodes="contenet"></rich-text>
+	</view>
+</template>
+
+<script>
+	import api from 'utils/api'
+	import util from 'utils/util'
+	import uParse from '@/components/gaoyia-parse/parse.vue'
+	export default {
+		 components: {
+		    uParse
+		  },
+		data() {
+			return {
+				contenet:'',
+			}
+		},
+		onLoad() {
+			api.getSysConfig({"search_name":"agreement"}).then((res)=>{
+				if(res.code==1){
+					this.contenet=res.data.agreement.replace(/\<img/gi, '<img style=max-width:100%;height:auto')
+
+				}
+			})
+		},
+		methods: {
+											
+		}
+	}
+</script>
+
+<style lang="scss">
+	.title{
+		padding: 20rpx 0;
+		font-size: 32rpx;
+		color: #222;
+		font-weight: bold;
+		text-align: center;
+	}
+	.content{
+		padding:30rpx;
+		background-color: #fff;
+		width: 640rpx;
+		margin: 0 auto;
+		border-radius: 16rpx;
+	}
+</style>

+ 266 - 0
ctxx_xcx/pages/userInfoUpdate/index.vue

@@ -0,0 +1,266 @@
+<template>
+	<view class="content">
+		<view class="user-info" @click="upLoadImg" style="display: inherit;">
+			<view class="avatar-name">
+				头像
+			</view>
+			<view style="display: flex;">
+				<view class="avatar">
+					<image :src="userInfos.headimg"></image>
+				</view>
+				<view class="texts">
+					修改头像
+				</view>
+				<view class="rightIcon">
+					<image src="../../static/index/mine-icon1.png"></image>
+				</view>
+			</view>
+		</view>
+		
+		<view class="user-info" style="display: inherit;">
+			<view>昵称</view>
+			<view class="user-name">
+				<input @input="getUserName" v-model="userInfos.name"  />
+			</view>
+		</view>
+		<view class="submit" @click="updateUserInfo">确定</view>
+		
+	
+	 
+
+	</view>
+</template>
+
+<script>
+	import __config from 'config/env';
+	import api from 'utils/api'
+	import wybNoticeBar from '@/components/wyb-noticeBar/wyb-noticeBar.vue'
+	import navBar from '@/components/nav-bar/nav-bar.vue'
+	export default {
+		components:{wybNoticeBar,navBar},
+		data() {
+			return {
+				userInfos:{
+					"name":"",
+					"headimg":"",
+				},
+			}
+		},
+		onLoad() {
+		
+		},
+		onShow() {
+			this.getUserInfo();
+		},
+		methods: {
+			getUserName(e){
+				this.userInfos.name=e.detail.value
+			},
+			upLoadImg(){
+				let that=this;
+				let _url = __config.basePath + '/api/upload/upload'
+					uni.chooseImage({
+						success: (chooseImageRes) => {
+							const tempFilePaths = chooseImageRes.tempFilePaths;
+							uni.uploadFile({
+								url: _url,
+								filePath: tempFilePaths[0],							
+								file: tempFilePaths[0],
+								name: 'file',
+								success: (res) => {
+									let _res=JSON.parse(res.data)
+									if(_res.code==1){
+										this.$set(that.userInfos,"headimg",_res.data)
+									}
+								}
+							});
+						}
+					});
+			},
+			getUserInfo(){
+				api.getUserInfo().then((res)=>{
+					if(res.code==1){
+						this.userInfos.name=res.data.detail.name
+						this.userInfos.headimg=res.data.detail.headimg
+					}
+				})
+			},
+			updateUserInfo(){
+				let data={
+					"name":this.userInfos.name,
+					"headimg":this.userInfos.headimg
+				}
+				api.updateUserInfo(data).then((res)=>{
+					if(res.code==1){
+						uni.showToast({
+							icon:"none",
+							title:"修改成功",
+							duration:2000,
+							success() {
+								setTimeout(()=>{
+									uni.navigateTo({
+										url:"/pages/mine/index"
+									})
+								},2000)
+							}
+						})
+						
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.submit{
+		color: #fff;
+		font-size: 32rpx;
+		width: 320rpx;
+		height: 64rpx;
+		line-height: 64rpx;
+		text-align: center;
+		background: #222222;
+		border-radius: 16rpx;
+		margin: 120rpx auto;
+	}
+	.avatar-name{
+		color: #222;
+		font-size: 28rpx;
+		margin-left: 20rpx;
+		margin-bottom: 25rpx;
+	}
+	.user-info{
+		border-radius: 16rpx;
+		width: 630rpx;
+		// height: 140rpx;
+		background-color: #fff;
+		display: flex;
+		margin: 20rpx auto;
+		padding: 30rpx;
+		position: relative;
+		.user-name{
+			background: #F1F1F1;
+			border-radius: 16rpx;
+			height: 56rpx;
+			line-height: 56rpx;
+			width: 650rpx;
+			margin: 20rpx 0 0 0;
+			input{
+				font-size: 28rpx;
+				height: 56rpx;
+				line-height: 56rpx;
+				padding-left: 15rpx;
+			}
+		}
+		.user-views{
+			flex: 1;
+			text-align: center;
+			.name{
+				color: #222;
+				font-size: 28rpx;
+				margin-top: 5rpx;
+			}
+			.icons{
+				image{
+					width: 60rpx;
+					height: 60rpx;
+				}
+			}
+		}
+		.texts{
+			position: absolute;
+			right: 100rpx;
+			top: 125rpx;
+		}
+		.rightIcon{
+			position: absolute;
+			right: 30rpx;
+			top: 125rpx;
+			image{
+				width: 40rpx;
+				height: 40rpx;
+			}
+		}
+		.user-s{
+			margin: 20rpx 0 0 30rpx;
+		}
+		.avatar{
+			image{
+				width: 128rpx;
+				height: 128rpx;
+				border-radius: 50%;
+			}
+		}
+	}
+	.index-bottoms{
+		margin-top: 15rpx;
+		padding:0 30rpx;
+		.shop-detail{
+			padding-bottom: 180rpx;
+			margin-bottom: 100rpx;
+			.views{
+				margin-top: 10rpx;
+				display: flex;
+				line-height: 30rpx;
+				.texts{
+					color: #222;
+					font-size: 20rpx;
+					margin-left: 10rpx;
+				}
+				.shop-icons{
+					img{
+						width: 24rpx;
+						height: 24rpx;
+					}
+				}
+			}
+		}
+		.shop-banner{
+			img{
+				width: 688rpx;
+				height: 284rpx;
+				border-radius: 16rpx;
+			}
+		}
+	}
+	.title-texts{
+		color: #222;
+		font-size: 20rpx;
+		text-align: center;
+		margin-top: 10rpx;
+	}
+	.titles{
+		text-align: center;
+		display: flex;
+		justify-content: center;
+		margin-top: 35rpx;
+		.lines{
+			width: 18rpx;
+			height: 4rpx;
+			background: #000000;
+			border-radius: 4rpx;
+			margin: 18rpx 20rpx 0 0;
+		}
+		.views{
+			font-size: 28rpx;
+			color: #222;
+		}
+	}
+	.contents{
+		
+	}
+	swiper{
+		height: 328rpx;
+	}
+	.swiper{
+		margin: 12rpx auto;
+		text-align: center;
+	}
+	.swiper-img{
+		width: 684rpx;
+		height: 328rpx;
+		text-align: center;
+		border-radius: 16rpx;
+	}
+</style>

BIN
ctxx_xcx/static/index/add-icon.png


BIN
ctxx_xcx/static/index/add-icons.png


BIN
ctxx_xcx/static/index/address-icon.png


BIN
ctxx_xcx/static/index/check-icon-sel.png


BIN
ctxx_xcx/static/index/check-icon.png


BIN
ctxx_xcx/static/index/check-icons.png


BIN
ctxx_xcx/static/index/close.png


BIN
ctxx_xcx/static/index/eimail-icon.png


BIN
ctxx_xcx/static/index/index-icons.png


BIN
ctxx_xcx/static/index/index_bg.png


BIN
ctxx_xcx/static/index/index_icons.png


BIN
ctxx_xcx/static/index/index_nav_icon.png


BIN
ctxx_xcx/static/index/index_nav_icon_sel.png


BIN
ctxx_xcx/static/index/mine-icon1.png


BIN
ctxx_xcx/static/index/mine-icon2.png


BIN
ctxx_xcx/static/index/mine-icon3.png


BIN
ctxx_xcx/static/index/mine-icon4.png


BIN
ctxx_xcx/static/index/mine_icon.png


BIN
ctxx_xcx/static/index/mine_icon_sel.png


BIN
ctxx_xcx/static/index/notice-icon.png


BIN
ctxx_xcx/static/index/oder-ok.png


BIN
ctxx_xcx/static/index/phone-icon.png


BIN
ctxx_xcx/static/index/photo-icon.png


BIN
ctxx_xcx/static/index/shoes-icon.png


BIN
ctxx_xcx/static/index/shop-icons.png


BIN
ctxx_xcx/static/index/shopIcons.png


BIN
ctxx_xcx/static/index/shop_icon.png


BIN
ctxx_xcx/static/index/shop_icon_sel.png


BIN
ctxx_xcx/static/index/shopping-icon.png


BIN
ctxx_xcx/static/index/subscribe.png


BIN
ctxx_xcx/static/index/trumpet-icon.png


BIN
ctxx_xcx/static/index/wx-icon.png


BIN
ctxx_xcx/static/index/wxIcon.png


+ 77 - 0
ctxx_xcx/uni.scss

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

+ 191 - 0
ctxx_xcx/uni_modules/mp-html/README.md

@@ -0,0 +1,191 @@
+## 为减小组件包的大小,默认组件包中不包含编辑、latex 公式等扩展功能,需要使用扩展功能的请参考下方的 插件扩展 栏的说明
+
+## 功能介绍
+- 全端支持(含 `v3、NVUE`)
+- 支持丰富的标签(包括 `table`、`video`、`svg` 等)
+- 支持丰富的事件效果(自动预览图片、链接处理等)
+- 支持设置占位图(加载中、出错时、预览时)
+- 支持锚点跳转、长按复制等丰富功能
+- 支持大部分 *html* 实体
+- 丰富的插件(关键词搜索、内容编辑、`latex` 公式等)
+- 效率高、容错性强且轻量化
+
+查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
+
+## 使用方法
+- `uni_modules` 方式  
+  1. 点击右上角的 `使用 HBuilder X 导入插件` 按钮直接导入项目或点击 `下载插件 ZIP` 按钮下载插件包并解压到项目的 `uni_modules/mp-html` 目录下  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <!-- 不需要引入,可直接使用 -->
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     export default {
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时在 `HBuilder X` 中右键 `uni_modules/mp-html` 目录选择 `从插件市场更新` 即可  
+
+- 源码方式  
+  1. 从 [github](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 或 [gitee](https://gitee.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 下载源码  
+     插件市场的 **非 uni_modules 版本** 无法更新,不建议从插件市场获取  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from '@/components/mp-html/mp-html'
+     export default {
+       // HBuilderX 2.5.5+ 可以通过 easycom 自动引入
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+
+- npm 方式  
+  1. 在项目根目录下执行  
+     ```bash
+     npm install mp-html
+     ```
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
+     export default {
+       // 不可省略
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时执行以下命令即可  
+     ```bash
+     npm update mp-html
+     ```
+  
+  使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)  
+  如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行  
+
+查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
+
+## 组件属性
+
+| 属性 | 类型 | 默认值 | 说明 |
+|:---:|:---:|:---:|---|
+| container-style | String |  | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
+| content | String |  | 用于渲染的 html 字符串 |
+| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
+| domain | String |  | 主域名(用于链接拼接) |
+| error-img | String |  | 图片出错时的占位图链接 |
+| lazy-load | Boolean | false | 是否开启图片懒加载 |
+| loading-img | String |  | 图片加载过程中的占位图链接 |
+| pause-video | Boolean | true | 是否在播放一个视频时自动暂停其他视频 |
+| preview-img | Boolean | true | 是否允许图片被点击时自动预览 |
+| scroll-table | Boolean | false | 是否给每个表格添加一个滚动层使其能单独横向滚动 |
+| selectable | Boolean | false | 是否开启文本长按复制 |
+| set-title | Boolean | true | 是否将 title 标签的内容设置到页面标题 |
+| show-img-menu | Boolean | true | 是否允许图片被长按时显示菜单 |
+| tag-style | Object |  | 设置标签的默认样式 |
+| use-anchor | Boolean | false | 是否使用锚点链接 |
+
+查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
+
+## 组件事件
+
+| 名称 | 触发时机 |
+|:---:|---|
+| load | dom 树加载完毕时 |
+| ready | 图片加载完毕时 |
+| error | 发生渲染错误时 |
+| imgtap | 图片被点击时 |
+| linktap | 链接被点击时 |
+| play | 音视频播放时 |
+
+查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
+
+## api
+组件实例上提供了一些 `api` 方法可供调用
+
+| 名称 | 作用 |
+|:---:|---|
+| in | 将锚点跳转的范围限定在一个 scroll-view 内 |
+| navigateTo | 锚点跳转 |
+| getText | 获取文本内容 |
+| getRect | 获取富文本内容的位置和大小 |
+| setContent | 设置富文本内容 |
+| imgList | 获取所有图片的数组 |
+| pauseMedia | 暂停播放音视频([2.2.2+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v222)) |
+| setPlaybackRate | 设置音视频播放速率([2.4.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v240)) |
+
+查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
+
+## 插件扩展  
+除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
+
+| 名称 | 作用 |
+|:---:|---|
+| audio | 音乐播放器 |
+| editable | 富文本 **编辑**([示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip)) |
+| emoji | 解析 emoji |
+| highlight | 代码块高亮显示 |
+| markdown | 渲染 markdown |
+| search | 关键词搜索 |
+| style | 匹配 style 标签中的样式 |
+| txv-video | 使用腾讯视频 |
+| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
+| latex | 渲染 latex 公式 by [@Zeng-J](https://github.com/Zeng-J) |
+
+从插件市场导入的包中 **不含有** 扩展插件,使用插件需通过微信小程序 `富文本插件` 获取或参考以下方法进行打包:  
+1. 获取完整组件包  
+   ```bash
+   npm install mp-html
+   ```
+2. 编辑 `tools/config.js` 中的 `plugins` 项,选择需要的插件  
+3. 生成新的组件包  
+   在 `node_modules/mp-html` 目录下执行  
+   ```bash
+   npm install
+   npm run build:uni-app
+   ```
+4. 拷贝 `dist/uni-app` 中的内容到项目根目录  
+
+查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
+
+## 关于 nvue
+`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面  
+由于渲染方式与其他端不同,有以下限制:  
+1. 不支持 `lazy-load` 属性
+2. 视频不支持全屏播放
+3. 如果在 `flex-direction: row` 的容器中使用,需要给组件设置宽度或设置 `flex: 1` 占满剩余宽度
+
+纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)  
+
+## 立即体验
+![富文本插件](https://mp-html.oss-cn-hangzhou.aliyuncs.com/qrcode.jpg)
+
+## 问题反馈
+遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题  
+可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)  
+提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复  
+
+欢迎加入 `QQ` 交流群:`699734691`  
+
+查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多

+ 114 - 0
ctxx_xcx/uni_modules/mp-html/changelog.md

@@ -0,0 +1,114 @@
+## v2.4.0(2022-08-27)
+1. `A` 增加了 [setPlaybackRate](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#setPlaybackRate) 的 `api`,可以设置音视频的播放速率 [详细](https://github.com/jin-yufeng/mp-html/issues/452)
+2. `A` 示例小程序代码开源 [详细](https://github.com/jin-yufeng/mp-html-demo)
+3. `U` 优化 `ready` 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
+4. `U` `highlight` 插件在编辑状态下不进行高亮处理,便于编辑
+5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
+6. `F` 修复了 `selectable` 属性没有设置 `force` 也可能出现渲染异常的问题
+7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
+8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
+9. `F` 修复了 `editable` 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
+10. `F` 修复了 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
+## v2.3.2(2022-08-13)
+1. `A` 增加 [latex](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#latex) 插件,可以渲染数学公式 [详细](https://github.com/jin-yufeng/mp-html/pull/447) by [@Zeng-J](https://github.com/Zeng-J)
+2. `U` 优化根节点下有很多标签的长内容渲染速度
+3. `U` `highlight` 插件适配 `lang-xxx` 格式
+4. `F` 修复了 `table` 标签设置 `border` 属性后可能无法修改边框样式的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/439) by [@zouxingjie](https://github.com/zouxingjie)
+5. `F` 修复了 `editable` 插件输入连续空格无效的问题
+6. `F` 修复了 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
+7. `F` 修复了 `vue3` 使用 `table` 可能报错的问题
+## v2.3.1(2022-05-20)
+1. `U` `app` 端支持使用本地图片
+2. `U` 优化了微信小程序 `selectable` 属性在 `ios` 端的处理 [详细](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable)
+3. `F` 修复了 `editable` 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
+4. `F` 修复了 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
+5. `F` 修复了 `vue3` 部分标签可能被错误换行的问题
+6. `F` 修复了 `editable` 插件 `app` 端插入视频无法预览的问题
+## v2.3.0(2022-04-01)
+1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
+2. `U` `show-img-menu` 属性支持控制预览时是否长按弹出菜单
+3. `U` 优化 `wxs` 处理,提高渲染性能 [详细](https://developers.weixin.qq.com/community/develop/article/doc/0006cc2b204740f601bd43fa25a413)  
+4. `U` `video` 标签支持 `object-fit` 属性
+5. `U` 增加支持一些常用实体编码 [详细](https://github.com/jin-yufeng/mp-html/issues/418)
+6. `F` 修复了图片仅设置高度可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/410)
+7. `F` 修复了 `video` 标签高度设置为 `auto` 不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/411)
+8. `F` 修复了使用 `grid` 布局时可能样式错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/413)
+9. `F` 修复了含有合并单元格的表格部分情况下显示异常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/417)
+10. `F` 修复了 `editable` 插件连续插入内容时顺序不正确的问题
+11. `F` 修复了 `uni-app` 包 `vue3` 使用 `audio` 插件报错的问题
+12. `F` 修复了 `uni-app` 包 `highlight` 插件使用自定义的 `prism.min.js` 报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/416)
+## v2.2.2(2022-02-26)
+1. `A` 增加了 [pauseMedia](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
+2. `U` 优化了长内容的加载速度  
+3. `U` 适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
+4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
+5. `F` 修复了 `highlight` 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
+## v2.2.1(2021-12-24)
+1. `A` `editable` 插件增加上下移动标签功能
+2. `U` `editable` 插件支持在文本中间光标处插入内容
+3. `F` 修复了 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
+4. `F` 修复了 `highlight` 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
+5. `F` 修复了编辑状态下使用 `emoji` 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
+6. `F` 修复了使用 `editable` 插件后将 `selectable` 属性设置为 `force` 不生效的问题
+## v2.2.0(2021-10-12)
+1. `A` 增加 `customElements` 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
+2. `A` `editable` 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
+3. `A` `editable` 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
+4. `U` `editable` 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
+5. `U` `editable` 插入图片和音视频时支持拼接 `domian` 主域名
+6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
+7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
+8. `F` 修复了 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
+## v2.1.5(2021-08-13)
+1. `A` 增加支持标签的 `dir` 属性
+2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
+3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
+4. `F` 修复了 `externStyle` 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+5. `F` 修复了 `h5` 端引入 `externStyle` 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+## v2.1.4(2021-07-14)
+1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
+2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
+3. `F` 修复了 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
+4. `F` 修复了 `editable` 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
+## v2.1.3(2021-06-12)
+1. `A` `editable` 插件增加 `insertTable` 方法
+2. `U` `editable` 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
+3. `F` 修复了 `externStyle` 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
+4. `F` 修复了多个组件同时使用时 `tag-style` 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
+5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
+6. `F` 修复了编译到头条小程序时可能报错的问题
+7. `F` 修复了 `nvue` 端不触发 `click` 事件的问题
+8. `F` 修复了 `editable` 插件尾部插入时无法撤销的问题
+9. `F` 修复了 `editable` 插件的 `insertHtml` 方法只能在末尾插入的问题
+10. `F` 修复了 `editable` 插件插入音频不显示的问题
+## v2.1.2(2021-04-24)
+1. `A` 增加了 [img-cache](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#img-cache) 插件,可以在 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
+2. `U` 支持通过 `container-style` 属性设置 `white-space` 来保留连续空格和换行符 [详细](https://jin-yufeng.gitee.io/mp-html/#/question/faq#space)
+3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
+4. `U` `editable` 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
+5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
+6. `F` 修复了编译到支付宝和头条小程序时部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
+## v2.1.1(2021-04-09)
+1. 修复了对 `p` 标签设置 `tag-style` 可能不生效的问题
+2. 修复了 `svg` 标签中的文本无法显示的问题
+3. 修复了使用 `editable` 插件编辑表格时可能报错的问题
+4. 修复了使用 `highlight` 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
+5. 修复了使用 `editable` 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
+6. 修复了 `style` 插件连续子选择器失效的问题
+7. 修复了 `editable` 插件无法修改图片和字体大小的问题
+## v2.1.0.2(2021-03-21)
+修复了 `nvue` 端使用可能报错的问题
+## v2.1.0(2021-03-20)
+1. `A` 增加了 [container-style](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
+2. `A` 增加支持 `strike` 标签
+3. `A` `editable` 插件增加 `placeholder` 属性 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+5. `U` 外部样式支持标签名选择器 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart#setting)
+6. `F` 修复了 `nvue` 端部分情况下可能不显示的问题
+## v2.0.5(2021-03-12)
+1. `U` [linktap](https://jin-yufeng.gitee.io/mp-html/#/basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
+2. `U` [selectable](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
+3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
+4. `F` 修复了多次修改富文本数据时部分内容可能不显示的问题
+5. `F` 修复了 [腾讯视频](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
+6. `F` 修复了 [highlight](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)

+ 493 - 0
ctxx_xcx/uni_modules/mp-html/components/mp-html/mp-html.vue

@@ -0,0 +1,493 @@
+<template>
+  <view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
+    <slot v-if="!nodes[0]" />
+    <!-- #ifndef APP-PLUS-NVUE -->
+    <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
+    <!-- #endif -->
+    <!-- #ifdef APP-PLUS-NVUE -->
+    <web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+/**
+ * mp-html v2.4.0
+ * @description 富文本组件
+ * @tutorial https://github.com/jin-yufeng/mp-html
+ * @property {String} container-style 容器的样式
+ * @property {String} content 用于渲染的 html 字符串
+ * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
+ * @property {String} domain 主域名,用于拼接链接
+ * @property {String} error-img 图片出错时的占位图链接
+ * @property {Boolean} lazy-load 是否开启图片懒加载
+ * @property {string} loading-img 图片加载过程中的占位图链接
+ * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
+ * @property {Boolean} preview-img 是否允许图片被点击时自动预览
+ * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
+ * @property {Boolean | String} selectable 是否开启长按复制
+ * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
+ * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
+ * @property {Object} tag-style 标签的默认样式
+ * @property {Boolean | Number} use-anchor 是否使用锚点链接
+ * @event {Function} load dom 结构加载完毕时触发
+ * @event {Function} ready 所有图片加载完毕时触发
+ * @event {Function} imgtap 图片被点击时触发
+ * @event {Function} linktap 链接被点击时触发
+ * @event {Function} play 音视频播放时触发
+ * @event {Function} error 媒体加载出错时触发
+ */
+// #ifndef APP-PLUS-NVUE
+import node from './node/node'
+// #endif
+import Parser from './parser'
+const plugins=[]
+// #ifdef APP-PLUS-NVUE
+const dom = weex.requireModule('dom')
+// #endif
+export default {
+  name: 'mp-html',
+  data () {
+    return {
+      nodes: [],
+      // #ifdef APP-PLUS-NVUE
+      height: 3
+      // #endif
+    }
+  },
+  props: {
+    containerStyle: {
+      type: String,
+      default: ''
+    },
+    content: {
+      type: String,
+      default: ''
+    },
+    copyLink: {
+      type: [Boolean, String],
+      default: true
+    },
+    domain: String,
+    errorImg: {
+      type: String,
+      default: ''
+    },
+    lazyLoad: {
+      type: [Boolean, String],
+      default: false
+    },
+    loadingImg: {
+      type: String,
+      default: ''
+    },
+    pauseVideo: {
+      type: [Boolean, String],
+      default: true
+    },
+    previewImg: {
+      type: [Boolean, String],
+      default: true
+    },
+    scrollTable: [Boolean, String],
+    selectable: [Boolean, String],
+    setTitle: {
+      type: [Boolean, String],
+      default: true
+    },
+    showImgMenu: {
+      type: [Boolean, String],
+      default: true
+    },
+    tagStyle: Object,
+    useAnchor: [Boolean, Number]
+  },
+  // #ifdef VUE3
+  emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
+  // #endif
+  // #ifndef APP-PLUS-NVUE
+  components: {
+    node
+  },
+  // #endif
+  watch: {
+    content (content) {
+      this.setContent(content)
+    }
+  },
+  created () {
+    this.plugins = []
+    for (let i = plugins.length; i--;) {
+      this.plugins.push(new plugins[i](this))
+    }
+  },
+  mounted () {
+    if (this.content && !this.nodes.length) {
+      this.setContent(this.content)
+    }
+  },
+  beforeDestroy () {
+    this._hook('onDetached')
+  },
+  methods: {
+    /**
+     * @description 将锚点跳转的范围限定在一个 scroll-view 内
+     * @param {Object} page scroll-view 所在页面的示例
+     * @param {String} selector scroll-view 的选择器
+     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
+     */
+    in (page, selector, scrollTop) {
+      // #ifndef APP-PLUS-NVUE
+      if (page && selector && scrollTop) {
+        this._in = {
+          page,
+          selector,
+          scrollTop
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 锚点跳转
+     * @param {String} id 要跳转的锚点 id
+     * @param {Number} offset 跳转位置的偏移量
+     * @returns {Promise}
+     */
+    navigateTo (id, offset) {
+      return new Promise((resolve, reject) => {
+        if (!this.useAnchor) {
+          reject(Error('Anchor is disabled'))
+          return
+        }
+        offset = offset || parseInt(this.useAnchor) || 0
+        // #ifdef APP-PLUS-NVUE
+        if (!id) {
+          dom.scrollToElement(this.$refs.web, {
+            offset
+          })
+          resolve()
+        } else {
+          this._navigateTo = {
+            resolve,
+            reject,
+            offset
+          }
+          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
+        }
+        // #endif
+        // #ifndef APP-PLUS-NVUE
+        let deep = ' '
+        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+        deep = '>>>'
+        // #endif
+        const selector = uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this._in ? this._in.page : this)
+          // #endif
+          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
+        if (this._in) {
+          selector.select(this._in.selector).scrollOffset()
+            .select(this._in.selector).boundingClientRect()
+        } else {
+          // 获取 scroll-view 的位置和滚动距离
+          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
+        }
+        selector.exec(res => {
+          if (!res[0]) {
+            reject(Error('Label not found'))
+            return
+          }
+          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
+          if (this._in) {
+            // scroll-view 跳转
+            this._in.page[this._in.scrollTop] = scrollTop
+          } else {
+            // 页面跳转
+            uni.pageScrollTo({
+              scrollTop,
+              duration: 300
+            })
+          }
+          resolve()
+        })
+        // #endif
+      })
+    },
+
+    /**
+     * @description 获取文本内容
+     * @return {String}
+     */
+    getText (nodes) {
+      let text = '';
+      (function traversal (nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          const node = nodes[i]
+          if (node.type === 'text') {
+            text += node.text.replace(/&amp;/g, '&')
+          } else if (node.name === 'br') {
+            text += '\n'
+          } else {
+            // 块级标签前后加换行
+            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
+            if (isBlock && text && text[text.length - 1] !== '\n') {
+              text += '\n'
+            }
+            // 递归获取子节点的文本
+            if (node.children) {
+              traversal(node.children)
+            }
+            if (isBlock && text[text.length - 1] !== '\n') {
+              text += '\n'
+            } else if (node.name === 'td' || node.name === 'th') {
+              text += '\t'
+            }
+          }
+        }
+      })(nodes || this.nodes)
+      return text
+    },
+
+    /**
+     * @description 获取内容大小和位置
+     * @return {Promise}
+     */
+    getRect () {
+      return new Promise((resolve, reject) => {
+        uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this)
+          // #endif
+          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
+      })
+    },
+
+    /**
+     * @description 暂停播放媒体
+     */
+    pauseMedia () {
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].pause()
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置媒体播放速率
+     * @param {Number} rate 播放速率
+     */
+    setPlaybackRate (rate) {
+      this.playbackRate = rate
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].playbackRate(rate)
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置内容
+     * @param {String} content html 内容
+     * @param {Boolean} append 是否在尾部追加
+     */
+    setContent (content, append) {
+      if (!append || !this.imgList) {
+        this.imgList = []
+      }
+      const nodes = new Parser(this).parse(content)
+      // #ifdef APP-PLUS-NVUE
+      if (this._ready) {
+        this._set(nodes, append)
+      }
+      // #endif
+      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
+
+      // #ifndef APP-PLUS-NVUE
+      this._videos = []
+      this.$nextTick(() => {
+        this._hook('onLoad')
+        this.$emit('load')
+      })
+
+      if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
+        // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
+        let height
+        const callback = rect => {
+          // 350ms 总高度无变化就触发 ready 事件
+          if (rect.height === height) {
+            this.$emit('ready', rect)
+          } else {
+            height = rect.height
+            setTimeout(() => {
+              this.getRect().then(callback)
+            }, 350)
+          }
+        }
+        this.getRect().then(callback)
+      } else {
+        // 未设置懒加载,等待所有图片加载完毕
+        if (!this.imgList._unloadimgs) {
+          this.getRect(rect => {
+            this.$emit('ready', rect)
+          })
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 调用插件钩子函数
+     */
+    _hook (name) {
+      for (let i = plugins.length; i--;) {
+        if (this.plugins[i][name]) {
+          this.plugins[i][name]()
+        }
+      }
+    },
+
+    // #ifdef APP-PLUS-NVUE
+    /**
+     * @description 设置内容
+     */
+    _set (nodes, append) {
+      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
+    },
+
+    /**
+     * @description 接收到 web-view 消息
+     */
+    _onMessage (e) {
+      const message = e.detail.data[0]
+      switch (message.action) {
+        // web-view 初始化完毕
+        case 'onJSBridgeReady':
+          this._ready = true
+          if (this.nodes) {
+            this._set(this.nodes)
+          }
+          break
+        // 内容 dom 加载完毕
+        case 'onLoad':
+          this.height = message.height
+          this._hook('onLoad')
+          this.$emit('load')
+          break
+        // 所有图片加载完毕
+        case 'onReady':
+          this.getRect().then(res => {
+            this.$emit('ready', res)
+          }).catch(() => { })
+          break
+        // 总高度发生变化
+        case 'onHeightChange':
+          this.height = message.height
+          break
+        // 图片点击
+        case 'onImgTap':
+          this.$emit('imgtap', message.attrs)
+          if (this.previewImg) {
+            uni.previewImage({
+              current: parseInt(message.attrs.i),
+              urls: this.imgList
+            })
+          }
+          break
+        // 链接点击
+        case 'onLinkTap': {
+          const href = message.attrs.href
+          this.$emit('linktap', message.attrs)
+          if (href) {
+            // 锚点跳转
+            if (href[0] === '#') {
+              if (this.useAnchor) {
+                dom.scrollToElement(this.$refs.web, {
+                  offset: message.offset
+                })
+              }
+            } else if (href.includes('://')) {
+              // 打开外链
+              if (this.copyLink) {
+                plus.runtime.openWeb(href)
+              }
+            } else {
+              uni.navigateTo({
+                url: href,
+                fail () {
+                  uni.switchTab({
+                    url: href
+                  })
+                }
+              })
+            }
+          }
+          break
+        }
+        case 'onPlay':
+          this.$emit('play')
+          break
+        // 获取到锚点的偏移量
+        case 'getOffset':
+          if (typeof message.offset === 'number') {
+            dom.scrollToElement(this.$refs.web, {
+              offset: message.offset + this._navigateTo.offset
+            })
+            this._navigateTo.resolve()
+          } else {
+            this._navigateTo.reject(Error('Label not found'))
+          }
+          break
+        // 点击
+        case 'onClick':
+          this.$emit('tap')
+          this.$emit('click')
+          break
+        // 出错
+        case 'onError':
+          this.$emit('error', {
+            source: message.source,
+            attrs: message.attrs
+          })
+      }
+    }
+    // #endif
+  }
+}
+</script>
+
+<style>
+/* #ifndef APP-PLUS-NVUE */
+/* 根节点样式 */
+._root {
+  padding: 1px 0;
+  overflow-x: auto;
+  overflow-y: hidden;
+  -webkit-overflow-scrolling: touch;
+}
+
+/* 长按复制 */
+._select {
+  user-select: text;
+}
+/* #endif */
+</style>

+ 574 - 0
ctxx_xcx/uni_modules/mp-html/components/mp-html/node/node.vue

@@ -0,0 +1,574 @@
+<template>
+  <view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
+    <block v-for="(n, i) in childs" v-bind:key="i">
+      <!-- 图片 -->
+      <!-- 占位图 -->
+      <image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
+      <!-- 显示图片 -->
+      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
+      <img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || (APP-PLUS && VUE2) -->
+      <!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
+      <rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="'<img class=\'_img\' style=\''+n.attrs.style+'\' src=\''+n.attrs.src+'\'>'" :data-i="i" @tap.stop="imgTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || APP-PLUS -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifdef APP-PLUS && VUE3 -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- 文本 -->
+      <!-- #ifdef MP-WEIXIN -->
+      <text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
+      <text v-else-if="n.text" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <text v-else-if="n.name==='br'">\n</text>
+      <!-- 链接 -->
+      <view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
+        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
+      </view>
+      <!-- 视频 -->
+      <!-- #ifdef APP-PLUS -->
+      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
+      <!-- #endif -->
+      <!-- #ifndef APP-PLUS -->
+      <video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <!-- #ifdef H5 || APP-PLUS -->
+      <iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
+      <embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
+      <!-- #endif -->
+      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
+      <!-- 音频 -->
+      <audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
+        <node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
+        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
+          <node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
+          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
+            <view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <node :childs="tr.children" :opts="opts" />
+            </view>
+            <view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
+                <node :childs="td.children" :opts="opts" />
+              </view>
+            </view>
+          </block>
+        </view>
+      </view>
+      
+      <!-- 富文本 -->
+      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="n.f+';display:inline'" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- 继续递归 -->
+      <view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
+        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
+      </view>
+      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
+    </block>
+  </view>
+</template>
+<script module="handler" lang="wxs">
+// 行内标签列表
+var inlineTags = {
+  abbr: true,
+  b: true,
+  big: true,
+  code: true,
+  del: true,
+  em: true,
+  i: true,
+  ins: true,
+  label: true,
+  q: true,
+  small: true,
+  span: true,
+  strong: true,
+  sub: true,
+  sup: true
+}
+/**
+ * @description 判断是否为行内标签
+ */
+module.exports = {
+  isInline: function (tagName, style) {
+    return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
+  }
+}
+</script>
+<script>
+
+import node from './node'
+export default {
+  name: 'node',
+  options: {
+    // #ifdef MP-WEIXIN
+    virtualHost: true,
+    // #endif
+    // #ifdef MP-TOUTIAO
+    addGlobalClass: false
+    // #endif
+  },
+  data () {
+    return {
+      ctrl: {},
+      // #ifdef MP-WEIXIN
+      isiOS: uni.getSystemInfoSync().system.includes('iOS')
+      // #endif
+    }
+  },
+  props: {
+    name: String,
+    attrs: {
+      type: Object,
+      default () {
+        return {}
+      }
+    },
+    childs: Array,
+    opts: Array
+  },
+  components: {
+
+    // #ifndef H5 && VUE3
+    node
+    // #endif
+  },
+  mounted () {
+    this.$nextTick(() => {
+      for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
+    })
+    // #ifdef H5 || APP-PLUS
+    if (this.opts[0]) {
+      let i
+      for (i = this.childs.length; i--;) {
+        if (this.childs[i].name === 'img') break
+      }
+      if (i !== -1) {
+        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+          top: 500,
+          bottom: 500
+        })
+        this.observer.observe('._img', res => {
+          if (res.intersectionRatio) {
+            this.$set(this.ctrl, 'load', 1)
+            this.observer.disconnect()
+          }
+        })
+      }
+    }
+    // #endif
+  },
+  beforeDestroy () {
+    // #ifdef H5 || APP-PLUS
+    if (this.observer) {
+      this.observer.disconnect()
+    }
+    // #endif
+  },
+  methods:{
+    // #ifdef MP-WEIXIN
+    toJSON () { return this },
+    // #endif
+    /**
+     * @description 播放视频事件
+     * @param {Event} e
+     */
+    play (e) {
+      this.root.$emit('play')
+      // #ifndef APP-PLUS
+      if (this.root.pauseVideo) {
+        let flag = false
+        const id = e.target.id
+        for (let i = this.root._videos.length; i--;) {
+          if (this.root._videos[i].id === id) {
+            flag = true
+          } else {
+            this.root._videos[i].pause() // 自动暂停其他视频
+          }
+        }
+        // 将自己加入列表
+        if (!flag) {
+          const ctx = uni.createVideoContext(id
+            // #ifndef MP-BAIDU
+            , this
+            // #endif
+          )
+          ctx.id = id
+          if (this.root.playbackRate) {
+            ctx.playbackRate(this.root.playbackRate)
+          }
+          this.root._videos.push(ctx)
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片点击事件
+     * @param {Event} e
+     */
+    imgTap (e) {
+      const node = this.childs[e.currentTarget.dataset.i]
+      if (node.a) {
+        this.linkTap(node.a)
+        return
+      }
+      if (node.attrs.ignore) return
+      // #ifdef H5 || APP-PLUS
+      node.attrs.src = node.attrs.src || node.attrs['data-src']
+      // #endif
+      this.root.$emit('imgtap', node.attrs)
+      // 自动预览图片
+      if (this.root.previewImg) {
+        uni.previewImage({
+          // #ifdef MP-WEIXIN
+          showmenu: this.root.showImgMenu,
+          // #endif
+          // #ifdef MP-ALIPAY
+          enablesavephoto: this.root.showImgMenu,
+          enableShowPhotoDownload: this.root.showImgMenu,
+          // #endif
+          current: parseInt(node.attrs.i),
+          urls: this.root.imgList
+        })
+      }
+    },
+
+    /**
+     * @description 图片长按
+     */
+    imgLongTap (e) {
+      // #ifdef APP-PLUS
+      const attrs = this.childs[e.currentTarget.dataset.i].attrs
+      if (this.opts[3] && !attrs.ignore) {
+        uni.showActionSheet({
+          itemList: ['保存图片'],
+          success: () => {
+            const save = path => {
+              uni.saveImageToPhotosAlbum({
+                filePath: path,
+                success () {
+                  uni.showToast({
+                    title: '保存成功'
+                  })
+                }
+              })
+            }
+            if (this.root.imgList[attrs.i].startsWith('http')) {
+              uni.downloadFile({
+                url: this.root.imgList[attrs.i],
+                success: res => save(res.tempFilePath)
+              })
+            } else {
+              save(this.root.imgList[attrs.i])
+            }
+          }
+        })
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片加载完成事件
+     * @param {Event} e
+     */
+    imgLoad (e) {
+      const i = e.currentTarget.dataset.i
+      /* #ifndef H5 || (APP-PLUS && VUE2) */
+      if (!this.childs[i].w) {
+        // 设置原宽度
+        this.$set(this.ctrl, i, e.detail.width)
+      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
+        // 加载完毕,取消加载中占位图
+        this.$set(this.ctrl, i, 1)
+      }
+      this.checkReady()
+    },
+
+    /**
+     * @description 检查是否所有图片加载完毕
+     */
+    checkReady () {
+      if (!this.root.lazyLoad) {
+        this.root._unloadimgs -= 1
+        if (!this.root._unloadimgs) {
+          setTimeout(() => {
+            this.root.getRect().then(rect => {
+              this.root.$emit('ready', rect)
+            })
+          }, 350)
+        }
+      }
+    },
+
+    /**
+     * @description 链接点击事件
+     * @param {Event} e
+     */
+    linkTap (e) {
+      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
+      const attrs = node.attrs || e
+      const href = attrs.href
+      this.root.$emit('linktap', Object.assign({
+        innerText: this.root.getText(node.children || []) // 链接内的文本内容
+      }, attrs))
+      if (href) {
+        if (href[0] === '#') {
+          // 跳转锚点
+          this.root.navigateTo(href.substring(1)).catch(() => { })
+        } else if (href.split('?')[0].includes('://')) {
+          // 复制外部链接
+          if (this.root.copyLink) {
+            // #ifdef H5
+            window.open(href)
+            // #endif
+            // #ifdef MP
+            uni.setClipboardData({
+              data: href,
+              success: () =>
+                uni.showToast({
+                  title: '链接已复制'
+                })
+            })
+            // #endif
+            // #ifdef APP-PLUS
+            plus.runtime.openWeb(href)
+            // #endif
+          }
+        } else {
+          // 跳转页面
+          uni.navigateTo({
+            url: href,
+            fail () {
+              uni.switchTab({
+                url: href,
+                fail () { }
+              })
+            }
+          })
+        }
+      }
+    },
+
+    /**
+     * @description 错误事件
+     * @param {Event} e
+     */
+    mediaError (e) {
+      const i = e.currentTarget.dataset.i
+      const node = this.childs[i]
+      // 加载其他源
+      if (node.name === 'video' || node.name === 'audio') {
+        let index = (this.ctrl[i] || 0) + 1
+        if (index > node.src.length) {
+          index = 0
+        }
+        if (index < node.src.length) {
+          this.$set(this.ctrl, i, index)
+          return
+        }
+      } else if (node.name === 'img') {
+        // #ifdef H5 && VUE3
+        if (this.opts[0] && !this.ctrl.load) return
+        // #endif
+        // 显示错误占位图
+        if (this.opts[2]) {
+          this.$set(this.ctrl, i, -1)
+        }
+        this.checkReady()
+      }
+      if (this.root) {
+        this.root.$emit('error', {
+          source: node.name,
+          attrs: node.attrs,
+          // #ifndef H5 && VUE3
+          errMsg: e.detail.errMsg
+          // #endif
+        })
+      }
+    }
+  }
+}
+</script>
+<style>
+/* a 标签默认效果 */
+._a {
+  padding: 1.5px 0 1.5px 0;
+  color: #366092;
+  word-break: break-all;
+}
+
+/* a 标签点击态效果 */
+._hover {
+  text-decoration: underline;
+  opacity: 0.7;
+}
+
+/* 图片默认效果 */
+._img {
+  max-width: 100%;
+  -webkit-touch-callout: none;
+}
+
+/* 内部样式 */
+
+._block {
+  display: block;
+}
+
+._b,
+._strong {
+  font-weight: bold;
+}
+
+._code {
+  font-family: monospace;
+}
+
+._del {
+  text-decoration: line-through;
+}
+
+._em,
+._i {
+  font-style: italic;
+}
+
+._h1 {
+  font-size: 2em;
+}
+
+._h2 {
+  font-size: 1.5em;
+}
+
+._h3 {
+  font-size: 1.17em;
+}
+
+._h5 {
+  font-size: 0.83em;
+}
+
+._h6 {
+  font-size: 0.67em;
+}
+
+._h1,
+._h2,
+._h3,
+._h4,
+._h5,
+._h6 {
+  display: block;
+  font-weight: bold;
+}
+
+._image {
+  height: 1px;
+}
+
+._ins {
+  text-decoration: underline;
+}
+
+._li {
+  display: list-item;
+}
+
+._ol {
+  list-style-type: decimal;
+}
+
+._ol,
+._ul {
+  display: block;
+  padding-left: 40px;
+  margin: 1em 0;
+}
+
+._q::before {
+  content: '"';
+}
+
+._q::after {
+  content: '"';
+}
+
+._sub {
+  font-size: smaller;
+  vertical-align: sub;
+}
+
+._sup {
+  font-size: smaller;
+  vertical-align: super;
+}
+
+._thead,
+._tbody,
+._tfoot {
+  display: table-row-group;
+}
+
+._tr {
+  display: table-row;
+}
+
+._td,
+._th {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+._th {
+  font-weight: bold;
+  text-align: center;
+}
+
+._ul {
+  list-style-type: disc;
+}
+
+._ul ._ul {
+  margin: 0;
+  list-style-type: circle;
+}
+
+._ul ._ul ._ul {
+  list-style-type: square;
+}
+
+._abbr,
+._b,
+._code,
+._del,
+._em,
+._i,
+._ins,
+._label,
+._q,
+._span,
+._strong,
+._sub,
+._sup {
+  display: inline;
+}
+
+/* #ifdef APP-PLUS */
+._video {
+  width: 300px;
+  height: 225px;
+}
+/* #endif */
+</style>

+ 1333 - 0
ctxx_xcx/uni_modules/mp-html/components/mp-html/parser.js

@@ -0,0 +1,1333 @@
+/**
+ * @fileoverview html 解析器
+ */
+
+// 配置
+const config = {
+  // 信任的标签(保持标签名不变)
+  trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+
+  // 块级标签(转为 div,其他的非信任标签转为 span)
+  blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+
+  // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+  // 行内标签
+  inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup'),
+  // #endif
+
+  // 要移除的标签
+  ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
+
+  // 自闭合的标签
+  voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+
+  // html 实体
+  entities: {
+    lt: '<',
+    gt: '>',
+    quot: '"',
+    apos: "'",
+    ensp: '\u2002',
+    emsp: '\u2003',
+    nbsp: '\xA0',
+    semi: ';',
+    ndash: '–',
+    mdash: '—',
+    middot: '·',
+    lsquo: '‘',
+    rsquo: '’',
+    ldquo: '“',
+    rdquo: '”',
+    bull: '•',
+    hellip: '…',
+    larr: '←',
+    uarr: '↑',
+    rarr: '→',
+    darr: '↓'
+  },
+
+  // 默认的标签样式
+  tagStyle: {
+    // #ifndef APP-PLUS-NVUE
+    address: 'font-style:italic',
+    big: 'display:inline;font-size:1.2em',
+    caption: 'display:table-caption;text-align:center',
+    center: 'text-align:center',
+    cite: 'font-style:italic',
+    dd: 'margin-left:40px',
+    mark: 'background-color:yellow',
+    pre: 'font-family:monospace;white-space:pre',
+    s: 'text-decoration:line-through',
+    small: 'display:inline;font-size:0.8em',
+    strike: 'text-decoration:line-through',
+    u: 'text-decoration:underline'
+    // #endif
+  },
+
+  // svg 大小写对照表
+  svgDict: {
+    animatetransform: 'animateTransform',
+    lineargradient: 'linearGradient',
+    viewbox: 'viewBox',
+    attributename: 'attributeName',
+    repeatcount: 'repeatCount',
+    repeatdur: 'repeatDur'
+  }
+}
+const tagSelector={}
+const {
+  windowWidth,
+  // #ifdef MP-WEIXIN
+  system
+  // #endif
+} = uni.getSystemInfoSync()
+const blankChar = makeMap(' ,\r,\n,\t,\f')
+let idIndex = 0
+
+// #ifdef H5 || APP-PLUS
+config.ignoreTags.iframe = undefined
+config.trustTags.iframe = true
+config.ignoreTags.embed = undefined
+config.trustTags.embed = true
+// #endif
+// #ifdef APP-PLUS-NVUE
+config.ignoreTags.source = undefined
+config.ignoreTags.style = undefined
+// #endif
+
+/**
+ * @description 创建 map
+ * @param {String} str 逗号分隔
+ */
+function makeMap (str) {
+  const map = Object.create(null)
+  const list = str.split(',')
+  for (let i = list.length; i--;) {
+    map[list[i]] = true
+  }
+  return map
+}
+
+/**
+ * @description 解码 html 实体
+ * @param {String} str 要解码的字符串
+ * @param {Boolean} amp 要不要解码 &amp;
+ * @returns {String} 解码后的字符串
+ */
+function decodeEntity (str, amp) {
+  let i = str.indexOf('&')
+  while (i !== -1) {
+    const j = str.indexOf(';', i + 3)
+    let code
+    if (j === -1) break
+    if (str[i + 1] === '#') {
+      // &#123; 形式的实体
+      code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
+      if (!isNaN(code)) {
+        str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
+      }
+    } else {
+      // &nbsp; 形式的实体
+      code = str.substring(i + 1, j)
+      if (config.entities[code] || (code === 'amp' && amp)) {
+        str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
+      }
+    }
+    i = str.indexOf('&', i + 1)
+  }
+  return str
+}
+
+/**
+ * @description 合并多个块级标签,加快长内容渲染
+ * @param {Array} nodes 要合并的标签数组
+ */
+function mergeNodes (nodes) {
+  let i = nodes.length - 1
+  for (let j = i; j >= -1; j--) {
+    if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
+      if (i - j >= 5) {
+        nodes.splice(j + 1, i - j, {
+          name: 'div',
+          attrs: {},
+          children: nodes.slice(j + 1, i + 1)
+        })
+      }
+      i = j - 1
+    }
+  }
+}
+
+/**
+ * @description html 解析器
+ * @param {Object} vm 组件实例
+ */
+function Parser (vm) {
+  this.options = vm || {}
+  this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
+  this.imgList = vm.imgList || []
+  this.imgList._unloadimgs = 0
+  this.plugins = vm.plugins || []
+  this.attrs = Object.create(null)
+  this.stack = []
+  this.nodes = []
+  this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Parser.prototype.parse = function (content) {
+  // 插件处理
+  for (let i = this.plugins.length; i--;) {
+    if (this.plugins[i].onUpdate) {
+      content = this.plugins[i].onUpdate(content, config) || content
+    }
+  }
+
+  new Lexer(this).parse(content)
+  // 出栈未闭合的标签
+  while (this.stack.length) {
+    this.popNode()
+  }
+  if (this.nodes.length > 50) {
+    mergeNodes(this.nodes)
+  }
+  return this.nodes
+}
+
+/**
+ * @description 将标签暴露出来(不被 rich-text 包含)
+ */
+Parser.prototype.expose = function () {
+  // #ifndef APP-PLUS-NVUE
+  for (let i = this.stack.length; i--;) {
+    const item = this.stack[i]
+    if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
+    item.c = 1
+  }
+  // #endif
+}
+
+/**
+ * @description 处理插件
+ * @param {Object} node 要处理的标签
+ * @returns {Boolean} 是否要移除此标签
+ */
+Parser.prototype.hook = function (node) {
+  for (let i = this.plugins.length; i--;) {
+    if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
+      return false
+    }
+  }
+  return true
+}
+
+/**
+ * @description 将链接拼接上主域名
+ * @param {String} url 需要拼接的链接
+ * @returns {String} 拼接后的链接
+ */
+Parser.prototype.getUrl = function (url) {
+  const domain = this.options.domain
+  if (url[0] === '/') {
+    if (url[1] === '/') {
+      // // 开头的补充协议名
+      url = (domain ? domain.split('://')[0] : 'http') + ':' + url
+    } else if (domain) {
+      // 否则补充整个域名
+      url = domain + url
+    } /* #ifdef APP-PLUS */ else {
+      url = plus.io.convertLocalFileSystemURL(url)
+    } /* #endif */
+  } else if (!url.includes('data:') && !url.includes('://')) {
+    if (domain) {
+      url = domain + '/' + url
+    } /* #ifdef APP-PLUS */ else {
+      url = plus.io.convertLocalFileSystemURL(url)
+    } /* #endif */
+  }
+  return url
+}
+
+/**
+ * @description 解析样式表
+ * @param {Object} node 标签
+ * @returns {Object}
+ */
+Parser.prototype.parseStyle = function (node) {
+  const attrs = node.attrs
+  const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
+  const styleObj = {}
+  let tmp = ''
+
+  if (attrs.id && !this.xml) {
+    // 暴露锚点
+    if (this.options.useAnchor) {
+      this.expose()
+    } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
+      attrs.id = undefined
+    }
+  }
+
+  // 转换 width 和 height 属性
+  if (attrs.width) {
+    styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
+    attrs.width = undefined
+  }
+  if (attrs.height) {
+    styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
+    attrs.height = undefined
+  }
+
+  for (let i = 0, len = list.length; i < len; i++) {
+    const info = list[i].split(':')
+    if (info.length < 2) continue
+    const key = info.shift().trim().toLowerCase()
+    let value = info.join(':').trim()
+    if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
+      // 兼容性的 css 不压缩
+      tmp += `;${key}:${value}`
+    } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
+      // 重复的样式进行覆盖
+      if (value.includes('url')) {
+        // 填充链接
+        let j = value.indexOf('(') + 1
+        if (j) {
+          while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
+            j++
+          }
+          value = value.substr(0, j) + this.getUrl(value.substr(j))
+        }
+      } else if (value.includes('rpx')) {
+        // 转换 rpx(rich-text 内部不支持 rpx)
+        value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
+      }
+      styleObj[key] = value
+    }
+  }
+
+  node.attrs.style = tmp
+  return styleObj
+}
+
+/**
+ * @description 解析到标签名
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onTagName = function (name) {
+  this.tagName = this.xml ? name : name.toLowerCase()
+  if (this.tagName === 'svg') {
+    this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
+  }
+}
+
+/**
+ * @description 解析到属性名
+ * @param {String} name 属性名
+ * @private
+ */
+Parser.prototype.onAttrName = function (name) {
+  name = this.xml ? name : name.toLowerCase()
+  if (name.substr(0, 5) === 'data-') {
+    if (name === 'data-src' && !this.attrs.src) {
+      // data-src 自动转为 src
+      this.attrName = 'src'
+    } else if (this.tagName === 'img' || this.tagName === 'a') {
+      // a 和 img 标签保留 data- 的属性,可以在 imgtap 和 linktap 事件中使用
+      this.attrName = name
+    } else {
+      // 剩余的移除以减小大小
+      this.attrName = undefined
+    }
+  } else {
+    this.attrName = name
+    this.attrs[name] = 'T' // boolean 型属性缺省设置
+  }
+}
+
+/**
+ * @description 解析到属性值
+ * @param {String} val 属性值
+ * @private
+ */
+Parser.prototype.onAttrVal = function (val) {
+  const name = this.attrName || ''
+  if (name === 'style' || name === 'href') {
+    // 部分属性进行实体解码
+    this.attrs[name] = decodeEntity(val, true)
+  } else if (name.includes('src')) {
+    // 拼接主域名
+    this.attrs[name] = this.getUrl(decodeEntity(val, true))
+  } else if (name) {
+    this.attrs[name] = val
+  }
+}
+
+/**
+ * @description 解析到标签开始
+ * @param {Boolean} selfClose 是否有自闭合标识 />
+ * @private
+ */
+Parser.prototype.onOpenTag = function (selfClose) {
+  // 拼装 node
+  const node = Object.create(null)
+  node.name = this.tagName
+  node.attrs = this.attrs
+  // 避免因为自动 diff 使得 type 被设置为 null 导致部分内容不显示
+  if (this.options.nodes.length) {
+    node.type = 'node'
+  }
+  this.attrs = Object.create(null)
+
+  const attrs = node.attrs
+  const parent = this.stack[this.stack.length - 1]
+  const siblings = parent ? parent.children : this.nodes
+  const close = this.xml ? selfClose : config.voidTags[node.name]
+
+  // 替换标签名选择器
+  if (tagSelector[node.name]) {
+    attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
+  }
+
+  // 转换 embed 标签
+  if (node.name === 'embed') {
+    // #ifndef H5 || APP-PLUS
+    const src = attrs.src || ''
+    // 按照后缀名和 type 将 embed 转为 video 或 audio
+    if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
+      node.name = 'video'
+    } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
+      node.name = 'audio'
+    }
+    if (attrs.autostart) {
+      attrs.autoplay = 'T'
+    }
+    attrs.controls = 'T'
+    // #endif
+    // #ifdef H5 || APP-PLUS
+    this.expose()
+    // #endif
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  // 处理音视频
+  if (node.name === 'video' || node.name === 'audio') {
+    // 设置 id 以便获取 context
+    if (node.name === 'video' && !attrs.id) {
+      attrs.id = 'v' + idIndex++
+    }
+    // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
+    if (!attrs.controls && !attrs.autoplay) {
+      attrs.controls = 'T'
+    }
+    // 用数组存储所有可用的 source
+    node.src = []
+    if (attrs.src) {
+      node.src.push(attrs.src)
+      attrs.src = undefined
+    }
+    this.expose()
+  }
+  // #endif
+
+  // 处理自闭合标签
+  if (close) {
+    if (!this.hook(node) || config.ignoreTags[node.name]) {
+      // 通过 base 标签设置主域名
+      if (node.name === 'base' && !this.options.domain) {
+        this.options.domain = attrs.href
+      } /* #ifndef APP-PLUS-NVUE */ else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
+        // 设置 source 标签(仅父节点为 video 或 audio 时有效)
+        parent.src.push(attrs.src)
+      } /* #endif */
+      return
+    }
+
+    // 解析 style
+    const styleObj = this.parseStyle(node)
+
+    // 处理图片
+    if (node.name === 'img') {
+      if (attrs.src) {
+        // 标记 webp
+        if (attrs.src.includes('webp')) {
+          node.webp = 'T'
+        }
+        // data url 图片如果没有设置 original-src 默认为不可预览的小图片
+        if (attrs.src.includes('data:') && !attrs['original-src']) {
+          attrs.ignore = 'T'
+        }
+        if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
+          for (let i = this.stack.length; i--;) {
+            const item = this.stack[i]
+            if (item.name === 'a') {
+              node.a = item.attrs
+            }
+            if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
+              if (!styleObj.display || styleObj.display.includes('inline')) {
+                node.t = 'inline-block'
+              } else {
+                node.t = styleObj.display
+              }
+              styleObj.display = undefined
+            }
+            // #ifndef H5 || APP-PLUS
+            const style = item.attrs.style || ''
+            if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
+              styleObj.width = '100% !important'
+              styleObj.height = ''
+              for (let j = i + 1; j < this.stack.length; j++) {
+                this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
+              }
+            } else if (style.includes('flex') && styleObj.width === '100%') {
+              for (let j = i + 1; j < this.stack.length; j++) {
+                const style = this.stack[j].attrs.style || ''
+                if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
+                  styleObj.width = ''
+                  break
+                }
+              }
+            } else if (style.includes('inline-block')) {
+              if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
+                item.attrs.style += ';max-width:' + styleObj.width
+                styleObj.width = ''
+              } else {
+                item.attrs.style += ';max-width:100%'
+              }
+            }
+            // #endif
+            item.c = 1
+          }
+          attrs.i = this.imgList.length.toString()
+          let src = attrs['original-src'] || attrs.src
+          // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360
+          if (this.imgList.includes(src)) {
+            // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
+            let i = src.indexOf('://')
+            if (i !== -1) {
+              i += 3
+              let newSrc = src.substr(0, i)
+              for (; i < src.length; i++) {
+                if (src[i] === '/') break
+                newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
+              }
+              newSrc += src.substr(i)
+              src = newSrc
+            }
+          }
+          // #endif
+          this.imgList.push(src)
+          if (!node.t) {
+            this.imgList._unloadimgs += 1
+          }
+          // #ifdef H5 || APP-PLUS
+          if (this.options.lazyLoad) {
+            attrs['data-src'] = attrs.src
+            attrs.src = undefined
+          }
+          // #endif
+        }
+      }
+      if (styleObj.display === 'inline') {
+        styleObj.display = ''
+      }
+      // #ifndef APP-PLUS-NVUE
+      if (attrs.ignore) {
+        styleObj['max-width'] = styleObj['max-width'] || '100%'
+        attrs.style += ';-webkit-touch-callout:none'
+      }
+      // #endif
+      // 设置的宽度超出屏幕,为避免变形,高度转为自动
+      if (parseInt(styleObj.width) > windowWidth) {
+        styleObj.height = undefined
+      }
+      // 记录是否设置了宽高
+      if (!isNaN(parseInt(styleObj.width))) {
+        node.w = 'T'
+      }
+      if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
+        node.h = 'T'
+      }
+    } else if (node.name === 'svg') {
+      siblings.push(node)
+      this.stack.push(node)
+      this.popNode()
+      return
+    }
+    for (const key in styleObj) {
+      if (styleObj[key]) {
+        attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
+      }
+    }
+    attrs.style = attrs.style.substr(1) || undefined
+    // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+    if (!attrs.style) {
+      delete attrs.style
+    }
+    // #endif
+  } else {
+    if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
+      this.pre = node.pre = 1
+    }
+    node.children = []
+    this.stack.push(node)
+  }
+
+  // 加入节点树
+  siblings.push(node)
+}
+
+/**
+ * @description 解析到标签结束
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onCloseTag = function (name) {
+  // 依次出栈到匹配为止
+  name = this.xml ? name : name.toLowerCase()
+  let i
+  for (i = this.stack.length; i--;) {
+    if (this.stack[i].name === name) break
+  }
+  if (i !== -1) {
+    while (this.stack.length > i) {
+      this.popNode()
+    }
+  } else if (name === 'p' || name === 'br') {
+    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+    siblings.push({
+      name,
+      attrs: {
+        class: tagSelector[name] || '',
+        style: this.tagStyle[name] || ''
+      }
+    })
+  }
+}
+
+/**
+ * @description 处理标签出栈
+ * @private
+ */
+Parser.prototype.popNode = function () {
+  const node = this.stack.pop()
+  let attrs = node.attrs
+  const children = node.children
+  const parent = this.stack[this.stack.length - 1]
+  const siblings = parent ? parent.children : this.nodes
+
+  if (!this.hook(node) || config.ignoreTags[node.name]) {
+    // 获取标题
+    if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
+      uni.setNavigationBarTitle({
+        title: children[0].text
+      })
+    }
+    siblings.pop()
+    return
+  }
+
+  if (node.pre && this.pre !== 2) {
+    // 是否合并空白符标识
+    this.pre = node.pre = undefined
+    for (let i = this.stack.length; i--;) {
+      if (this.stack[i].pre) {
+        this.pre = 1
+      }
+    }
+  }
+
+  const styleObj = {}
+
+  // 转换 svg
+  if (node.name === 'svg') {
+    if (this.xml > 1) {
+      // 多层 svg 嵌套
+      this.xml--
+      return
+    }
+    // #ifdef APP-PLUS-NVUE
+    (function traversal (node) {
+      if (node.name) {
+        // 调整 svg 的大小写
+        node.name = config.svgDict[node.name] || node.name
+        for (const item in node.attrs) {
+          if (config.svgDict[item]) {
+            node.attrs[config.svgDict[item]] = node.attrs[item]
+            node.attrs[item] = undefined
+          }
+        }
+        for (let i = 0; i < (node.children || []).length; i++) {
+          traversal(node.children[i])
+        }
+      }
+    })(node)
+    // #endif
+    // #ifndef APP-PLUS-NVUE
+    let src = ''
+    const style = attrs.style
+    attrs.style = ''
+    attrs.xmlns = 'http://www.w3.org/2000/svg';
+    (function traversal (node) {
+      if (node.type === 'text') {
+        src += node.text
+        return
+      }
+      const name = config.svgDict[node.name] || node.name
+      src += '<' + name
+      for (const item in node.attrs) {
+        const val = node.attrs[item]
+        if (val) {
+          src += ` ${config.svgDict[item] || item}="${val}"`
+        }
+      }
+      if (!node.children) {
+        src += '/>'
+      } else {
+        src += '>'
+        for (let i = 0; i < node.children.length; i++) {
+          traversal(node.children[i])
+        }
+        src += '</' + name + '>'
+      }
+    })(node)
+    node.name = 'img'
+    node.attrs = {
+      src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+      style,
+      ignore: 'T'
+    }
+    node.children = undefined
+    // #endif
+    this.xml = false
+    return
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  // 转换 align 属性
+  if (attrs.align) {
+    if (node.name === 'table') {
+      if (attrs.align === 'center') {
+        styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
+      } else {
+        styleObj.float = attrs.align
+      }
+    } else {
+      styleObj['text-align'] = attrs.align
+    }
+    attrs.align = undefined
+  }
+
+  // 转换 dir 属性
+  if (attrs.dir) {
+    styleObj.direction = attrs.dir
+    attrs.dir = undefined
+  }
+
+  // 转换 font 标签的属性
+  if (node.name === 'font') {
+    if (attrs.color) {
+      styleObj.color = attrs.color
+      attrs.color = undefined
+    }
+    if (attrs.face) {
+      styleObj['font-family'] = attrs.face
+      attrs.face = undefined
+    }
+    if (attrs.size) {
+      let size = parseInt(attrs.size)
+      if (!isNaN(size)) {
+        if (size < 1) {
+          size = 1
+        } else if (size > 7) {
+          size = 7
+        }
+        styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
+      }
+      attrs.size = undefined
+    }
+  }
+  // #endif
+
+  // 一些编辑器的自带 class
+  if ((attrs.class || '').includes('align-center')) {
+    styleObj['text-align'] = 'center'
+  }
+
+  Object.assign(styleObj, this.parseStyle(node))
+
+  if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
+    styleObj['max-width'] = '100%'
+    styleObj['box-sizing'] = 'border-box'
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  if (config.blockTags[node.name]) {
+    node.name = 'div'
+  } else if (!config.trustTags[node.name] && !this.xml) {
+    // 未知标签转为 span,避免无法显示
+    node.name = 'span'
+  }
+
+  if (node.name === 'a' || node.name === 'ad'
+    // #ifdef H5 || APP-PLUS
+    || node.name === 'iframe' // eslint-disable-line
+    // #endif
+  ) {
+    this.expose()
+  } else if (node.name === 'video') {
+    if ((styleObj.height || '').includes('auto')) {
+      styleObj.height = undefined
+    }
+    /* #ifdef APP-PLUS */
+    let str = '<video style="width:100%;height:100%"'
+    for (const item in attrs) {
+      if (attrs[item]) {
+        str += ' ' + item + '="' + attrs[item] + '"'
+      }
+    }
+    if (this.options.pauseVideo) {
+      str += ' onplay="this.dispatchEvent(new CustomEvent(\'vplay\',{bubbles:!0}));for(var e=document.getElementsByTagName(\'video\'),t=0;t<e.length;t++)e[t]!=this&&e[t].pause()"'
+    }
+    str += '>'
+    for (let i = 0; i < node.src.length; i++) {
+      str += '<source src="' + node.src[i] + '">'
+    }
+    str += '</video>'
+    node.html = str
+    /* #endif */
+  } else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
+    // 列表处理
+    const types = {
+      a: 'lower-alpha',
+      A: 'upper-alpha',
+      i: 'lower-roman',
+      I: 'upper-roman'
+    }
+    if (types[attrs.type]) {
+      attrs.style += ';list-style-type:' + types[attrs.type]
+      attrs.type = undefined
+    }
+    for (let i = children.length; i--;) {
+      if (children[i].name === 'li') {
+        children[i].c = 1
+      }
+    }
+  } else if (node.name === 'table') {
+    // 表格处理
+    // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
+    let padding = parseFloat(attrs.cellpadding)
+    let spacing = parseFloat(attrs.cellspacing)
+    const border = parseFloat(attrs.border)
+    const bordercolor = styleObj['border-color']
+    const borderstyle = styleObj['border-style']
+    if (node.c) {
+      // padding 和 spacing 默认 2
+      if (isNaN(padding)) {
+        padding = 2
+      }
+      if (isNaN(spacing)) {
+        spacing = 2
+      }
+    }
+    if (border) {
+      attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
+    }
+    if (node.flag && node.c) {
+      // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
+      styleObj.display = 'grid'
+      if (spacing) {
+        styleObj['grid-gap'] = spacing + 'px'
+        styleObj.padding = spacing + 'px'
+      } else if (border) {
+        // 无间隔的情况下避免边框重叠
+        attrs.style += ';border-left:0;border-top:0'
+      }
+
+      const width = [] // 表格的列宽
+      const trList = [] // tr 列表
+      const cells = [] // 保存新的单元格
+      const map = {}; // 被合并单元格占用的格子
+
+      (function traversal (nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          if (nodes[i].name === 'tr') {
+            trList.push(nodes[i])
+          } else {
+            traversal(nodes[i].children || [])
+          }
+        }
+      })(children)
+
+      for (let row = 1; row <= trList.length; row++) {
+        let col = 1
+        for (let j = 0; j < trList[row - 1].children.length; j++) {
+          const td = trList[row - 1].children[j]
+          if (td.name === 'td' || td.name === 'th') {
+            // 这个格子被上面的单元格占用,则列号++
+            while (map[row + '.' + col]) {
+              col++
+            }
+            let style = td.attrs.style || ''
+            let start = style.indexOf('width') ? style.indexOf(';width') : 0
+            // 提取出 td 的宽度
+            if (start !== -1) {
+              let end = style.indexOf(';', start + 6)
+              if (end === -1) {
+                end = style.length
+              }
+              if (!td.attrs.colspan) {
+                width[col] = style.substring(start ? start + 7 : 6, end)
+              }
+              style = style.substr(0, start) + style.substr(end)
+            }
+            // 设置竖直对齐
+            style += ';display:flex'
+            start = style.indexOf('vertical-align')
+            if (start !== -1) {
+              const val = style.substr(start + 15, 10)
+              if (val.includes('middle')) {
+                style += ';align-items:center'
+              } else if (val.includes('bottom')) {
+                style += ';align-items:flex-end'
+              }
+            } else {
+              style += ';align-items:center'
+            }
+            // 设置水平对齐
+            start = style.indexOf('text-align')
+            if (start !== -1) {
+              const val = style.substr(start + 11, 10)
+              if (val.includes('center')) {
+                style += ';justify-content: center'
+              } else if (val.includes('right')) {
+                style += ';justify-content: right'
+              }
+            }
+            style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
+            // 处理列合并
+            if (td.attrs.colspan) {
+              style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
+              if (!td.attrs.rowspan) {
+                style += `;grid-row-start:${row};grid-row-end:${row + 1}`
+              }
+              col += parseInt(td.attrs.colspan) - 1
+            }
+            // 处理行合并
+            if (td.attrs.rowspan) {
+              style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
+              if (!td.attrs.colspan) {
+                style += `;grid-column-start:${col};grid-column-end:${col + 1}`
+              }
+              // 记录下方单元格被占用
+              for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
+                for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
+                  map[(row + rowspan) + '.' + (col - colspan)] = 1
+                }
+              }
+            }
+            if (style) {
+              td.attrs.style = style
+            }
+            cells.push(td)
+            col++
+          }
+        }
+        if (row === 1) {
+          let temp = ''
+          for (let i = 1; i < col; i++) {
+            temp += (width[i] ? width[i] : 'auto') + ' '
+          }
+          styleObj['grid-template-columns'] = temp
+        }
+      }
+      node.children = cells
+    } else {
+      // 没有使用合并单元格的表格通过 table 布局实现
+      if (node.c) {
+        styleObj.display = 'table'
+      }
+      if (!isNaN(spacing)) {
+        styleObj['border-spacing'] = spacing + 'px'
+      }
+      if (border || padding) {
+        // 遍历
+        (function traversal (nodes) {
+          for (let i = 0; i < nodes.length; i++) {
+            const td = nodes[i]
+            if (td.name === 'th' || td.name === 'td') {
+              if (border) {
+                td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
+              }
+              if (padding) {
+                td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
+              }
+            } else if (td.children) {
+              traversal(td.children)
+            }
+          }
+        })(children)
+      }
+    }
+    // 给表格添加一个单独的横向滚动层
+    if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
+      const table = Object.assign({}, node)
+      node.name = 'div'
+      node.attrs = {
+        style: 'overflow:auto'
+      }
+      node.children = [table]
+      attrs = table.attrs
+    }
+  } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
+    for (let i = this.stack.length; i--;) {
+      if (this.stack[i].name === 'table') {
+        this.stack[i].flag = 1 // 指示含有合并单元格
+        break
+      }
+    }
+  } else if (node.name === 'ruby') {
+    // 转换 ruby
+    node.name = 'span'
+    for (let i = 0; i < children.length - 1; i++) {
+      if (children[i].type === 'text' && children[i + 1].name === 'rt') {
+        children[i] = {
+          name: 'div',
+          attrs: {
+            style: 'display:inline-block;text-align:center'
+          },
+          children: [{
+            name: 'div',
+            attrs: {
+              style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
+            },
+            children: children[i + 1].children
+          }, children[i]]
+        }
+        children.splice(i + 1, 1)
+      }
+    }
+  } else if (node.c) {
+    (function traversal (node) {
+      node.c = 2
+      for (let i = node.children.length; i--;) {
+        const child = node.children[i]
+        // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+        if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
+          traversal(child)
+        }
+        // #endif
+        if (!child.c || child.name === 'table') {
+          node.c = 1
+        }
+      }
+    })(node)
+  }
+
+  if ((styleObj.display || '').includes('flex') && !node.c) {
+    for (let i = children.length; i--;) {
+      const item = children[i]
+      if (item.f) {
+        item.attrs.style = (item.attrs.style || '') + item.f
+        item.f = undefined
+      }
+    }
+  }
+  // flex 布局时部分样式需要提取到 rich-text 外层
+  const flex = parent && ((parent.attrs.style || '').includes('flex') || (parent.attrs.style || '').includes('grid'))
+    // #ifdef MP-WEIXIN
+    // 检查基础库版本 virtualHost 是否可用
+    && !(node.c && wx.getNFCAdapter) // eslint-disable-line
+    // #endif
+    // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
+    && !node.c // eslint-disable-line
+  // #endif
+  if (flex) {
+    node.f = ';max-width:100%'
+  }
+
+  if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
+    mergeNodes(children)
+  }
+  // #endif
+
+  for (const key in styleObj) {
+    if (styleObj[key]) {
+      const val = `;${key}:${styleObj[key].replace(' !important', '')}`
+      /* #ifndef APP-PLUS-NVUE */
+      if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || key.includes('grid') || styleObj[key][0] === '-' || (key.includes('width') && val.includes('%')))) {
+        node.f += val
+        if (key === 'width') {
+          attrs.style += ';width:100%'
+        }
+      } else /* #endif */ {
+        attrs.style += val
+      }
+    }
+  }
+  attrs.style = attrs.style.substr(1) || undefined
+  // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+  for (const key in attrs) {
+    if (!attrs[key]) {
+      delete attrs[key]
+    }
+  }
+  // #endif
+}
+
+/**
+ * @description 解析到文本
+ * @param {String} text 文本内容
+ */
+Parser.prototype.onText = function (text) {
+  if (!this.pre) {
+    // 合并空白符
+    let trim = ''
+    let flag
+    for (let i = 0, len = text.length; i < len; i++) {
+      if (!blankChar[text[i]]) {
+        trim += text[i]
+      } else {
+        if (trim[trim.length - 1] !== ' ') {
+          trim += ' '
+        }
+        if (text[i] === '\n' && !flag) {
+          flag = true
+        }
+      }
+    }
+    // 去除含有换行符的空串
+    if (trim === ' ') {
+      if (flag) return
+      // #ifdef VUE3
+      else {
+        const parent = this.stack[this.stack.length - 1]
+        if (parent && parent.name[0] === 't') return
+      }
+      // #endif
+    }
+    text = trim
+  }
+  const node = Object.create(null)
+  node.type = 'text'
+  // #ifdef (MP-BAIDU || MP-ALIPAY || MP-TOUTIAO) && VUE3
+  node.attrs = {}
+  // #endif
+  node.text = decodeEntity(text)
+  if (this.hook(node)) {
+    // #ifdef MP-WEIXIN
+    if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
+      this.expose()
+    }
+    // #endif
+    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+    siblings.push(node)
+  }
+}
+
+/**
+ * @description html 词法分析器
+ * @param {Object} handler 高层处理器
+ */
+function Lexer (handler) {
+  this.handler = handler
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Lexer.prototype.parse = function (content) {
+  this.content = content || ''
+  this.i = 0 // 标记解析位置
+  this.start = 0 // 标记一个单词的开始位置
+  this.state = this.text // 当前状态
+  for (let len = this.content.length; this.i !== -1 && this.i < len;) {
+    this.state()
+  }
+}
+
+/**
+ * @description 检查标签是否闭合
+ * @param {String} method 如果闭合要进行的操作
+ * @returns {Boolean} 是否闭合
+ * @private
+ */
+Lexer.prototype.checkClose = function (method) {
+  const selfClose = this.content[this.i] === '/'
+  if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
+    if (method) {
+      this.handler[method](this.content.substring(this.start, this.i))
+    }
+    this.i += selfClose ? 2 : 1
+    this.start = this.i
+    this.handler.onOpenTag(selfClose)
+    if (this.handler.tagName === 'script') {
+      this.i = this.content.indexOf('</', this.i)
+      if (this.i !== -1) {
+        this.i += 2
+        this.start = this.i
+      }
+      this.state = this.endTag
+    } else {
+      this.state = this.text
+    }
+    return true
+  }
+  return false
+}
+
+/**
+ * @description 文本状态
+ * @private
+ */
+Lexer.prototype.text = function () {
+  this.i = this.content.indexOf('<', this.i) // 查找最近的标签
+  if (this.i === -1) {
+    // 没有标签了
+    if (this.start < this.content.length) {
+      this.handler.onText(this.content.substring(this.start, this.content.length))
+    }
+    return
+  }
+  const c = this.content[this.i + 1]
+  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+    // 标签开头
+    if (this.start !== this.i) {
+      this.handler.onText(this.content.substring(this.start, this.i))
+    }
+    this.start = ++this.i
+    this.state = this.tagName
+  } else if (c === '/' || c === '!' || c === '?') {
+    if (this.start !== this.i) {
+      this.handler.onText(this.content.substring(this.start, this.i))
+    }
+    const next = this.content[this.i + 2]
+    if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+      // 标签结尾
+      this.i += 2
+      this.start = this.i
+      this.state = this.endTag
+      return
+    }
+    // 处理注释
+    let end = '-->'
+    if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
+      end = '>'
+    }
+    this.i = this.content.indexOf(end, this.i)
+    if (this.i !== -1) {
+      this.i += end.length
+      this.start = this.i
+    }
+  } else {
+    this.i++
+  }
+}
+
+/**
+ * @description 标签名状态
+ * @private
+ */
+Lexer.prototype.tagName = function () {
+  if (blankChar[this.content[this.i]]) {
+    // 解析到标签名
+    this.handler.onTagName(this.content.substring(this.start, this.i))
+    while (blankChar[this.content[++this.i]]);
+    if (this.i < this.content.length && !this.checkClose()) {
+      this.start = this.i
+      this.state = this.attrName
+    }
+  } else if (!this.checkClose('onTagName')) {
+    this.i++
+  }
+}
+
+/**
+ * @description 属性名状态
+ * @private
+ */
+Lexer.prototype.attrName = function () {
+  let c = this.content[this.i]
+  if (blankChar[c] || c === '=') {
+    // 解析到属性名
+    this.handler.onAttrName(this.content.substring(this.start, this.i))
+    let needVal = c === '='
+    const len = this.content.length
+    while (++this.i < len) {
+      c = this.content[this.i]
+      if (!blankChar[c]) {
+        if (this.checkClose()) return
+        if (needVal) {
+          // 等号后遇到第一个非空字符
+          this.start = this.i
+          this.state = this.attrVal
+          return
+        }
+        if (this.content[this.i] === '=') {
+          needVal = true
+        } else {
+          this.start = this.i
+          this.state = this.attrName
+          return
+        }
+      }
+    }
+  } else if (!this.checkClose('onAttrName')) {
+    this.i++
+  }
+}
+
+/**
+ * @description 属性值状态
+ * @private
+ */
+Lexer.prototype.attrVal = function () {
+  const c = this.content[this.i]
+  const len = this.content.length
+  if (c === '"' || c === "'") {
+    // 有冒号的属性
+    this.start = ++this.i
+    this.i = this.content.indexOf(c, this.i)
+    if (this.i === -1) return
+    this.handler.onAttrVal(this.content.substring(this.start, this.i))
+  } else {
+    // 没有冒号的属性
+    for (; this.i < len; this.i++) {
+      if (blankChar[this.content[this.i]]) {
+        this.handler.onAttrVal(this.content.substring(this.start, this.i))
+        break
+      } else if (this.checkClose('onAttrVal')) return
+    }
+  }
+  while (blankChar[this.content[++this.i]]);
+  if (this.i < len && !this.checkClose()) {
+    this.start = this.i
+    this.state = this.attrName
+  }
+}
+
+/**
+ * @description 结束标签状态
+ * @returns {String} 结束的标签名
+ * @private
+ */
+Lexer.prototype.endTag = function () {
+  const c = this.content[this.i]
+  if (blankChar[c] || c === '>' || c === '/') {
+    this.handler.onCloseTag(this.content.substring(this.start, this.i))
+    if (c !== '>') {
+      this.i = this.content.indexOf('>', this.i)
+      if (this.i === -1) return
+    }
+    this.start = ++this.i
+    this.state = this.text
+  } else {
+    this.i++
+  }
+}
+
+export default Parser

+ 76 - 0
ctxx_xcx/uni_modules/mp-html/package.json

@@ -0,0 +1,76 @@
+{
+    "id": "mp-html",
+    "displayName": "mp-html 富文本组件【全端支持,支持编辑、latex等扩展】",
+    "version": "v2.4.0",
+    "description": "一个强大的富文本组件,高效轻量,功能丰富",
+    "keywords": [
+        "富文本",
+        "编辑器",
+        "html",
+        "rich-text",
+        "editor"
+    ],
+    "repository": "https://github.com/jin-yufeng/mp-html",
+    "dcloudext": {
+        "sale": {
+            "regular": {
+                "price": "0.00"
+            },
+            "sourcecode": {
+                "price": "0.00"
+            }
+        },
+        "contact": {
+            "qq": ""
+        },
+        "declaration": {
+            "ads": "无",
+            "data": "无",
+            "permissions": "无"
+        },
+        "npmurl": "https://www.npmjs.com/package/mp-html",
+        "type": "component-vue"
+    },
+    "uni_modules": {
+        "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": "u",
+                    "Edge": "y",
+                    "Firefox": "y",
+                    "Safari": "y"
+                },
+                "小程序": {
+                    "微信": "y",
+                    "阿里": "y",
+                    "百度": "y",
+                    "字节跳动": "y",
+                    "QQ": "y"
+                },
+                "快应用": {
+                    "华为": "y",
+                    "联盟": "y"
+                },
+                "Vue": {
+                    "vue2": "y",
+                    "vue3": "y"
+                }
+            }
+        }
+    }
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
ctxx_xcx/uni_modules/mp-html/static/app-plus/mp-html/js/handler.js


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov