作者 lihongjuan

1

要显示太多修改。

为保证性能只显示 31 of 31+ 个文件。

  1 +<script>
  2 +export default {
  3 + onLaunch: function() {},
  4 + onShow: function() {},
  5 + onHide: function() {},
  6 + post: function(url, data) {
  7 + var promise = new Promise((resolve, reject) => {
  8 + //init
  9 + let that = this,
  10 + token = uni.getStorageSync('token'),
  11 + header = {
  12 + 'token': token || ''
  13 + },
  14 + postData;
  15 + //网络请求
  16 + uni.request({
  17 + url: this.globalData.baseUrl + url,
  18 + data: data,
  19 + method: 'POST',
  20 + header: header,
  21 + success: function(res) {
  22 + //返回取得的数据
  23 + if (res.data.code == '1') {
  24 + resolve(res.data.data);
  25 + } else {
  26 + uni.showToast({
  27 + title: res.data.msg,
  28 + icon: 'none'
  29 + });
  30 + reject(res.data);
  31 + }
  32 + },
  33 + fail: function(e) {
  34 + reject('网络出错');
  35 + uni.hideNavigationBarLoading();
  36 + }
  37 + });
  38 + });
  39 + return promise;
  40 + },
  41 + globalData: {
  42 + userInfo: null,
  43 + baseUrl: 'https://cardxcx.w.broing.cn'
  44 + },
  45 +
  46 +
  47 +
  48 +
  49 +
  50 + // 上传图片
  51 + upload(file) {
  52 + var promise = new Promise((resolve, reject) => {
  53 + let url = 'https://cardxcx.w.broing.cn/api/common/upload';
  54 + let head = {
  55 + 'token': uni.getStorageSync('token'),
  56 + };
  57 + // let typename = {
  58 + // filetype: filetype //其他参数
  59 + // };
  60 + uni.uploadFile({
  61 + url: url, //仅为示例,非真实的接口地址
  62 + filePath: file,
  63 + name: 'file',
  64 + header: head,
  65 + // formData: typename,
  66 + success: function(res) {
  67 + let temdata = JSON.parse(res.data);
  68 + let urlobj = {
  69 + url: temdata.data.url,
  70 + };
  71 + resolve(urlobj);
  72 + uni.hideNavigationBarLoading();
  73 + uni.hideLoading();
  74 + },
  75 + fail: function(res) {
  76 + reject('网络出错');
  77 + uni.hideNavigationBarLoading();
  78 + uni.hideLoading();
  79 + },
  80 + complete: () => {
  81 + uni.hideNavigationBarLoading();
  82 + uni.hideLoading();
  83 + }
  84 + });
  85 + });
  86 + return promise;
  87 + }
  88 +};
  89 +</script>
  90 +
  91 +<style >
  92 + /*每个页面公共css */
  93 +
  94 + image {
  95 + width: 100%;
  96 + height: 100%;
  97 + display: block;
  98 + }
  99 + /* 布局 */
  100 + .layer_star {
  101 + display: flex;
  102 + display: -webkit-flex;
  103 + flex-direction: row;
  104 + justify-content: flex-start;
  105 + align-items: center
  106 + }
  107 +
  108 + .layer_nostar {
  109 + display: flex;
  110 + display: -webkit-flex;
  111 + justify-content: flex-start;
  112 + }
  113 +
  114 + .layer_center {
  115 + display: flex;
  116 + display: -webkit-flex;
  117 + justify-content: center;
  118 + align-items: center
  119 + }
  120 +
  121 + .layer_nocenter {
  122 + display: flex;
  123 + display: -webkit-flex;
  124 + justify-content: center;
  125 + }
  126 +
  127 + .layer_end {
  128 + display: flex;
  129 + display: -webkit-flex;
  130 + justify-content: flex-end;
  131 + align-items: center
  132 + }
  133 +
  134 + .layer_noend {
  135 + display: flex;
  136 + display: -webkit-flex;
  137 + justify-content: flex-end;
  138 + }
  139 +
  140 + .layer_between {
  141 + display: flex;
  142 + display: -webkit-flex;
  143 + justify-content: space-between;
  144 + align-items: center
  145 + }
  146 +
  147 + .layer_nobetween {
  148 + display: flex;
  149 + display: -webkit-flex;
  150 + justify-content: space-between;
  151 + }
  152 +
  153 + .flex_star {
  154 + display: flex;
  155 + display: -webkit-flex;
  156 + flex-direction: column;
  157 + align-items: flex-start
  158 + }
  159 + .flex_column_center{
  160 + display: flex;
  161 + display: -webkit-flex;
  162 + flex-direction: column;
  163 + justify-content: flex-start;
  164 + align-items: center
  165 + }
  166 + .flex_column_nojustify{
  167 + display: flex;
  168 + display: -webkit-flex;
  169 + flex-direction: column;
  170 + align-items: center;
  171 + justify-content: center;
  172 + }
  173 + .flex_star_between {
  174 + display: flex;
  175 + display: -webkit-flex;
  176 + flex-direction: column;
  177 + justify-content: space-between;
  178 + align-items: flex-start
  179 + }
  180 +
  181 + .flex_center {
  182 + display: flex;
  183 + display: -webkit-flex;
  184 + flex-direction: column;
  185 + align-items: center;
  186 + justify-content: center;
  187 + }
  188 + .flex_warp {
  189 + display: flex;
  190 + display: -webkit-flex;
  191 + flex-wrap: wrap;
  192 + align-items: center;
  193 + justify-content: center;
  194 + }
  195 + .flex_wrap_between{
  196 + display: flex;
  197 + display: -webkit-flex;
  198 + flex-wrap: wrap;
  199 + justify-content: space-between;
  200 + }
  201 + .flex_wrap_no{
  202 + display: flex;
  203 + display: -webkit-flex;
  204 + flex-wrap: wrap;
  205 + }
  206 + /* 模态框 */
  207 +
  208 + .tx_mask {
  209 + z-index: 99;
  210 + width: 100%;
  211 + height: 100vh;
  212 + position: fixed;
  213 + top: 0;
  214 + left: 0;
  215 + background-color: rgba(0, 0, 0, 0.5);
  216 + }
  217 + .mask_content{
  218 + background-color: rgba(255,255,255,1);
  219 + width:686upx;
  220 + /* height:298upx; */
  221 + border-radius:16upx;
  222 + position: fixed;
  223 + top: 50%;
  224 + left: 50%;
  225 + transform: translate(-50%,-50%);
  226 + z-index: 100;
  227 + }
  228 + /* 购买弹窗 */
  229 + .mask_content_bottom{
  230 + background-color: #fff;
  231 + position: fixed;
  232 + left: 0;
  233 + bottom: 0;
  234 + z-index: 100;
  235 + width: 100%;
  236 + }
  237 + .over_hide{
  238 + height: 100vh;
  239 + overflow: hidden;
  240 + }
  241 +
  242 +</style>
  1 +<template>
  2 + <!--增加audio标签支持-->
  3 + <audio
  4 + :id="node.attr.id"
  5 + :class="node.classStr"
  6 + :style="node.styleStr"
  7 + :src="node.attr.src"
  8 + :loop="node.attr.loop"
  9 + :poster="node.attr.poster"
  10 + :name="node.attr.name"
  11 + :author="node.attr.author"
  12 + controls></audio>
  13 +</template>
  14 +
  15 +<script>
  16 +export default {
  17 + name: 'wxParseAudio',
  18 + props: {
  19 + node: {
  20 + type: Object,
  21 + default() {
  22 + return {};
  23 + },
  24 + },
  25 + },
  26 +};
  27 +</script>
  1 +<template>
  2 + <image
  3 + :mode="node.attr.mode"
  4 + :lazy-load="node.attr.lazyLoad"
  5 + :class="node.classStr"
  6 + :style="newStyleStr || node.styleStr"
  7 + :data-src="node.attr.src"
  8 + :src="node.attr.src"
  9 + @tap="wxParseImgTap"
  10 + @load="wxParseImgLoad"
  11 + />
  12 +</template>
  13 +
  14 +<script>
  15 +export default {
  16 + name: 'wxParseImg',
  17 + data() {
  18 + return {
  19 + newStyleStr: '',
  20 + preview: true,
  21 + };
  22 + },
  23 + props: {
  24 + node: {
  25 + type: Object,
  26 + default() {
  27 + return {};
  28 + },
  29 + },
  30 + },
  31 + methods: {
  32 + wxParseImgTap(e) {
  33 + if (!this.preview) return;
  34 + const { src } = e.currentTarget.dataset;
  35 + if (!src) return;
  36 + let parent = this.$parent;
  37 + while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
  38 + parent = parent.$parent;
  39 + }
  40 + parent.preview(src, e);
  41 + },
  42 + // 图片视觉宽高计算函数区
  43 + wxParseImgLoad(e) {
  44 + const { src } = e.currentTarget.dataset;
  45 + if (!src) return;
  46 + const { width, height } = e.mp.detail;
  47 + const recal = this.wxAutoImageCal(width, height);
  48 + const { imageheight, imageWidth } = recal;
  49 + const { padding, mode } = this.node.attr;
  50 + const { styleStr } = this.node;
  51 + const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
  52 + this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;
  53 + },
  54 + // 计算视觉优先的图片宽高
  55 + wxAutoImageCal(originalWidth, originalHeight) {
  56 + // 获取图片的原始长宽
  57 + const { padding } = this.node.attr;
  58 + const windowWidth = this.node.$screen.width - (2 * padding);
  59 + const results = {};
  60 +
  61 + if (originalWidth < 60 || originalHeight < 60) {
  62 + const { src } = this.node.attr;
  63 + let parent = this.$parent;
  64 + while(!parent.preview || typeof parent.preview !== 'function') {
  65 + parent = parent.$parent;
  66 + }
  67 + parent.removeImageUrl(src);
  68 + this.preview = false;
  69 + }
  70 +
  71 + // 判断按照那种方式进行缩放
  72 + if (originalWidth > windowWidth) {
  73 + // 在图片width大于手机屏幕width时候
  74 + results.imageWidth = windowWidth;
  75 + results.imageheight = windowWidth * (originalHeight / originalWidth);
  76 + } else {
  77 + // 否则展示原来的数据
  78 + results.imageWidth = originalWidth;
  79 + results.imageheight = originalHeight;
  80 + }
  81 +
  82 + return results;
  83 + },
  84 + },
  85 +};
  86 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--table类型-->
  47 + <block v-else-if="node.tag == 'table'">
  48 + <view :class="node.classStr" class="table" :style="node.styleStr">
  49 + <block v-for="(node, index) of node.nodes" :key="index">
  50 + <wx-parse-template :node="node" />
  51 + </block>
  52 + </view>
  53 + </block>
  54 +
  55 + <!--br类型-->
  56 + <block v-else-if="node.tag == 'br'">
  57 + <text>\n</text>
  58 + </block>
  59 +
  60 + <!--其他标签-->
  61 + <block v-else>
  62 + <view :class="node.classStr" :style="node.styleStr">
  63 + <block v-for="(node, index) of node.nodes" :key="index">
  64 + <wx-parse-template :node="node" />
  65 + </block>
  66 + </view>
  67 + </block>
  68 +
  69 + </block>
  70 +
  71 + <!--判断是否是文本节点-->
  72 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  73 + </view>
  74 +</template>
  75 +
  76 +<script>
  77 + import wxParseTemplate from './wxParseTemplate1';
  78 + import wxParseImg from './wxParseImg';
  79 + import wxParseVideo from './wxParseVideo';
  80 + import wxParseAudio from './wxParseAudio';
  81 +
  82 + export default {
  83 + name: 'wxParseTemplate0',
  84 + props: {
  85 + node: {},
  86 + },
  87 + components: {
  88 + wxParseTemplate,
  89 + wxParseImg,
  90 + wxParseVideo,
  91 + wxParseAudio,
  92 + },
  93 + methods: {
  94 + wxParseATap(e) {
  95 + const {
  96 + href
  97 + } = e.currentTarget.dataset;// TODO currentTarget才有dataset
  98 + if (!href) return;
  99 + let parent = this.$parent;
  100 + while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
  101 + parent = parent.$parent;
  102 + }
  103 + parent.navigate(href, e);
  104 + },
  105 + },
  106 + };
  107 +</script>
  1 +<template>
  2 + <view :class="(node.tag == 'li' ? node.classStr : (node.node==='text'?'text':''))">
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <!-- <view :class="node.classStr" :style="node.styleStr"> -->
  16 + <view :style="node.styleStr">
  17 + <block v-for="(node, index) of node.nodes" :key="index">
  18 + <wx-parse-template :node="node" />
  19 + </block>
  20 + </view>
  21 + </block>
  22 +
  23 + <!--video类型-->
  24 + <block v-else-if="node.tag == 'video'">
  25 + <wx-parse-video :node="node" />
  26 + </block>
  27 +
  28 + <!--audio类型-->
  29 + <block v-else-if="node.tag == 'audio'">
  30 + <wx-parse-audio :node="node" />
  31 + </block>
  32 +
  33 + <!--img类型-->
  34 + <block v-else-if="node.tag == 'img'">
  35 + <wx-parse-img :node="node" />
  36 + </block>
  37 +
  38 + <!--a类型-->
  39 + <block v-else-if="node.tag == 'a'">
  40 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  41 + <block v-for="(node, index) of node.nodes" :key="index">
  42 + <wx-parse-template :node="node" />
  43 + </block>
  44 + </view>
  45 + </block>
  46 +
  47 + <!--br类型-->
  48 + <block v-else-if="node.tag == 'br'">
  49 + <text>\n</text>
  50 + </block>
  51 +
  52 + <!--其他标签-->
  53 + <block v-else>
  54 + <view :class="node.classStr" :style="node.styleStr">
  55 + <block v-for="(node, index) of node.nodes" :key="index">
  56 + <wx-parse-template :node="node" />
  57 + </block>
  58 + </view>
  59 + </block>
  60 +
  61 + </block>
  62 +
  63 + <!--判断是否是文本节点-->
  64 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  65 + </view>
  66 +</template>
  67 +
  68 +<script>
  69 + import wxParseTemplate from './wxParseTemplate2';
  70 + import wxParseImg from './wxParseImg';
  71 + import wxParseVideo from './wxParseVideo';
  72 + import wxParseAudio from './wxParseAudio';
  73 +
  74 + export default {
  75 + name: 'wxParseTemplate1',
  76 + props: {
  77 + node: {},
  78 + },
  79 + components: {
  80 + wxParseTemplate,
  81 + wxParseImg,
  82 + wxParseVideo,
  83 + wxParseAudio,
  84 + },
  85 + methods: {
  86 + wxParseATap(e) {
  87 + const {
  88 + href
  89 + } = e.currentTarget.dataset;
  90 + if (!href) return;
  91 + let parent = this.$parent;
  92 + while(!parent.preview || typeof parent.preview !== 'function') {
  93 + parent = parent.$parent;
  94 + }
  95 + parent.navigate(href, e);
  96 + },
  97 + },
  98 + };
  99 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 + </block>
  60 +
  61 + <!--判断是否是文本节点-->
  62 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  63 + </view>
  64 +</template>
  65 +
  66 +<script>
  67 + import wxParseTemplate from './wxParseTemplate11';
  68 + import wxParseImg from './wxParseImg';
  69 + import wxParseVideo from './wxParseVideo';
  70 + import wxParseAudio from './wxParseAudio';
  71 +
  72 + export default {
  73 + name: 'wxParseTemplate10',
  74 + props: {
  75 + node: {},
  76 + },
  77 + components: {
  78 + wxParseTemplate,
  79 + wxParseImg,
  80 + wxParseVideo,
  81 + wxParseAudio,
  82 + },
  83 + methods: {
  84 + wxParseATap(e) {
  85 + const {
  86 + href
  87 + } = e.currentTarget.dataset;
  88 + if (!href) return;
  89 + let parent = this.$parent;
  90 + while(!parent.preview || typeof parent.preview !== 'function') {
  91 + parent = parent.$parent;
  92 + }
  93 + parent.navigate(href, e);
  94 + },
  95 + },
  96 + };
  97 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <!--button类型-->
  6 + <block v-if="node.tag == 'button'">
  7 + <button type="default" size="mini">
  8 + </button>
  9 + </block>
  10 +
  11 + <!--li类型-->
  12 + <block v-else-if="node.tag == 'li'">
  13 + <view :class="node.classStr" :style="node.styleStr">
  14 + {{node.text}}
  15 + </view>
  16 + </block>
  17 +
  18 + <!--video类型-->
  19 + <block v-else-if="node.tag == 'video'">
  20 + <wx-parse-video :node="node" />
  21 + </block>
  22 +
  23 + <!--audio类型-->
  24 + <block v-else-if="node.tag == 'audio'">
  25 + <wx-parse-audio :node="node" />
  26 + </block>
  27 +
  28 + <!--img类型-->
  29 + <block v-else-if="node.tag == 'img'">
  30 + <wx-parse-img :node="node" />
  31 + </block>
  32 +
  33 + <!--a类型-->
  34 + <block v-else-if="node.tag == 'a'">
  35 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  36 + {{node.text}}
  37 + </view>
  38 + </block>
  39 +
  40 + <!--br类型-->
  41 + <block v-else-if="node.tag == 'br'">
  42 + <text>\n</text>
  43 + </block>
  44 +
  45 + <!--其他标签-->
  46 + <block v-else>
  47 + <view :class="node.classStr" :style="node.styleStr">
  48 + {{node.text}}
  49 + </view>
  50 + </block>
  51 + </block>
  52 +
  53 + <!--判断是否是文本节点-->
  54 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55 + </view>
  56 +</template>
  57 +
  58 +<script>
  59 + import wxParseImg from './wxParseImg';
  60 + import wxParseVideo from './wxParseVideo';
  61 + import wxParseAudio from './wxParseAudio';
  62 +
  63 + export default {
  64 + name: 'wxParseTemplate11',
  65 + props: {
  66 + node: {},
  67 + },
  68 + components: {
  69 + wxParseImg,
  70 + wxParseVideo,
  71 + wxParseAudio,
  72 + },
  73 + methods: {
  74 + wxParseATap(e) {
  75 + const {
  76 + href
  77 + } = e.currentTarget.dataset;
  78 + if (!href) return;
  79 + let parent = this.$parent;
  80 + while(!parent.preview || typeof parent.preview !== 'function') {
  81 + parent = parent.$parent;
  82 + }
  83 + parent.navigate(href, e);
  84 + },
  85 + },
  86 + };
  87 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate3';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate2',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate4';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate3',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate5';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate4',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate6';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate5',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate7';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate6',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate8';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate7',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate9';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate8',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <view>
  3 + <!--判断是否是标签节点-->
  4 + <block v-if="node.node == 'element'">
  5 + <block v-if="node.tag == 'button'">
  6 + <button type="default" size="mini">
  7 + <block v-for="(node, index) of node.nodes" :key="index">
  8 + <wx-parse-template :node="node" />
  9 + </block>
  10 + </button>
  11 + </block>
  12 +
  13 + <!--li类型-->
  14 + <block v-else-if="node.tag == 'li'">
  15 + <view :class="node.classStr" :style="node.styleStr">
  16 + <block v-for="(node, index) of node.nodes" :key="index">
  17 + <wx-parse-template :node="node" />
  18 + </block>
  19 + </view>
  20 + </block>
  21 +
  22 + <!--video类型-->
  23 + <block v-else-if="node.tag == 'video'">
  24 + <wx-parse-video :node="node" />
  25 + </block>
  26 +
  27 + <!--audio类型-->
  28 + <block v-else-if="node.tag == 'audio'">
  29 + <wx-parse-audio :node="node" />
  30 + </block>
  31 +
  32 + <!--img类型-->
  33 + <block v-else-if="node.tag == 'img'">
  34 + <wx-parse-img :node="node" />
  35 + </block>
  36 +
  37 + <!--a类型-->
  38 + <block v-else-if="node.tag == 'a'">
  39 + <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  40 + <block v-for="(node, index) of node.nodes" :key="index">
  41 + <wx-parse-template :node="node" />
  42 + </block>
  43 + </view>
  44 + </block>
  45 +
  46 + <!--br类型-->
  47 + <block v-else-if="node.tag == 'br'">
  48 + <text>\n</text>
  49 + </block>
  50 +
  51 + <!--其他标签-->
  52 + <block v-else>
  53 + <view :class="node.classStr" :style="node.styleStr">
  54 + <block v-for="(node, index) of node.nodes" :key="index">
  55 + <wx-parse-template :node="node" />
  56 + </block>
  57 + </view>
  58 + </block>
  59 +
  60 + </block>
  61 +
  62 + <!--判断是否是文本节点-->
  63 + <block v-else-if="node.node == 'text'">{{node.text}}</block>
  64 + </view>
  65 +</template>
  66 +
  67 +<script>
  68 + import wxParseTemplate from './wxParseTemplate10';
  69 + import wxParseImg from './wxParseImg';
  70 + import wxParseVideo from './wxParseVideo';
  71 + import wxParseAudio from './wxParseAudio';
  72 +
  73 + export default {
  74 + name: 'wxParseTemplate9',
  75 + props: {
  76 + node: {},
  77 + },
  78 + components: {
  79 + wxParseTemplate,
  80 + wxParseImg,
  81 + wxParseVideo,
  82 + wxParseAudio,
  83 + },
  84 + methods: {
  85 + wxParseATap(e) {
  86 + const {
  87 + href
  88 + } = e.currentTarget.dataset;
  89 + if (!href) return;
  90 + let parent = this.$parent;
  91 + while(!parent.preview || typeof parent.preview !== 'function') {
  92 + parent = parent.$parent;
  93 + }
  94 + parent.navigate(href, e);
  95 + },
  96 + },
  97 + };
  98 +</script>
  1 +<template>
  2 + <!--增加video标签支持,并循环添加-->
  3 + <view :class="node.classStr" :style="node.styleStr">
  4 + <video :class="node.classStr" class="video-video" :src="node.attr.src"></video>
  5 + </view>
  6 +</template>
  7 +
  8 +<script>
  9 +export default {
  10 + name: 'wxParseVideo',
  11 + props: {
  12 + node: {},
  13 + },
  14 +};
  15 +</script>
  1 +/**
  2 + * html2Json 改造来自: https://github.com/Jxck/html2json
  3 + *
  4 + *
  5 + * author: Di (微信小程序开发工程师)
  6 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7 + * 垂直微信小程序开发交流社区
  8 + *
  9 + * github地址: https://github.com/icindy/wxParse
  10 + *
  11 + * for: 微信小程序富文本解析
  12 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13 + */
  14 +
  15 +import wxDiscode from './wxDiscode';
  16 +import HTMLParser from './htmlparser';
  17 +
  18 +function makeMap(str) {
  19 + const obj = {};
  20 + const items = str.split(',');
  21 + for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  22 + return obj;
  23 +}
  24 +
  25 +// Block Elements - HTML 5
  26 +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');
  27 +
  28 +// Inline Elements - HTML 5
  29 +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');
  30 +
  31 +// Elements that you can, intentionally, leave open
  32 +// (and which close themselves)
  33 +const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  34 +
  35 +function removeDOCTYPE(html) {
  36 + const isDocument = /<body.*>([^]*)<\/body>/.test(html);
  37 + return isDocument ? RegExp.$1 : html;
  38 +}
  39 +
  40 +function trimHtml(html) {
  41 + return html
  42 + .replace(/<!--.*?-->/gi, '')
  43 + .replace(/\/\*.*?\*\//gi, '')
  44 + .replace(/[ ]+</gi, '<')
  45 + .replace(/<script[^]*<\/script>/gi, '')
  46 + .replace(/<style[^]*<\/style>/gi, '');
  47 +}
  48 +
  49 +function getScreenInfo() {
  50 + const screen = {};
  51 + wx.getSystemInfo({
  52 + success: (res) => {
  53 + screen.width = res.windowWidth;
  54 + screen.height = res.windowHeight;
  55 + },
  56 + });
  57 + return screen;
  58 +}
  59 +
  60 +function html2json(html, customHandler, imageProp, host) {
  61 + // 处理字符串
  62 + html = removeDOCTYPE(html);
  63 + html = trimHtml(html);
  64 + html = wxDiscode.strDiscode(html);
  65 + // 生成node节点
  66 + const bufArray = [];
  67 + const results = {
  68 + nodes: [],
  69 + imageUrls: [],
  70 + };
  71 +
  72 + const screen = getScreenInfo();
  73 + function Node(tag) {
  74 + this.node = 'element';
  75 + this.tag = tag;
  76 +
  77 + this.$screen = screen;
  78 + }
  79 +
  80 + HTMLParser(html, {
  81 + start(tag, attrs, unary) {
  82 + // node for this element
  83 + const node = new Node(tag);
  84 +
  85 + if (bufArray.length !== 0) {
  86 + const parent = bufArray[0];
  87 + if (parent.nodes === undefined) {
  88 + parent.nodes = [];
  89 + }
  90 + }
  91 +
  92 + if (block[tag]) {
  93 + node.tagType = 'block';
  94 + } else if (inline[tag]) {
  95 + node.tagType = 'inline';
  96 + } else if (closeSelf[tag]) {
  97 + node.tagType = 'closeSelf';
  98 + }
  99 +
  100 + node.attr = attrs.reduce((pre, attr) => {
  101 + const { name } = attr;
  102 + let { value } = attr;
  103 + if (name === 'class') {
  104 + node.classStr = value;
  105 + }
  106 + // has multi attibutes
  107 + // make it array of attribute
  108 + if (name === 'style') {
  109 + node.styleStr = value;
  110 + }
  111 + if (value.match(/ /)) {
  112 + value = value.split(' ');
  113 + }
  114 +
  115 + // if attr already exists
  116 + // merge it
  117 + if (pre[name]) {
  118 + if (Array.isArray(pre[name])) {
  119 + // already array, push to last
  120 + pre[name].push(value);
  121 + } else {
  122 + // single value, make it array
  123 + pre[name] = [pre[name], value];
  124 + }
  125 + } else {
  126 + // not exist, put it
  127 + pre[name] = value;
  128 + }
  129 +
  130 + return pre;
  131 + }, {});
  132 +
  133 + // 优化样式相关属性
  134 + if (node.classStr) {
  135 + node.classStr += ` ${node.tag}`;
  136 + } else {
  137 + node.classStr = node.tag;
  138 + }
  139 + if (node.tagType === 'inline') {
  140 + node.classStr += ' inline';
  141 + }
  142 +
  143 + // 对img添加额外数据
  144 + if (node.tag === 'img') {
  145 + let imgUrl = node.attr.src;
  146 + imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
  147 + Object.assign(node.attr, imageProp, {
  148 + src: imgUrl || '',
  149 + });
  150 + if (imgUrl) {
  151 + results.imageUrls.push(imgUrl);
  152 + }
  153 + }
  154 +
  155 + // 处理a标签属性
  156 + if (node.tag === 'a') {
  157 + node.attr.href = node.attr.href || '';
  158 + }
  159 +
  160 + // 处理font标签样式属性
  161 + if (node.tag === 'font') {
  162 + const fontSize = [
  163 + 'x-small',
  164 + 'small',
  165 + 'medium',
  166 + 'large',
  167 + 'x-large',
  168 + 'xx-large',
  169 + '-webkit-xxx-large',
  170 + ];
  171 + const styleAttrs = {
  172 + color: 'color',
  173 + face: 'font-family',
  174 + size: 'font-size',
  175 + };
  176 + if (!node.styleStr) node.styleStr = '';
  177 + Object.keys(styleAttrs).forEach((key) => {
  178 + if (node.attr[key]) {
  179 + const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
  180 + node.styleStr += `${styleAttrs[key]}: ${value};`;
  181 + }
  182 + });
  183 + }
  184 +
  185 + // 临时记录source资源
  186 + if (node.tag === 'source') {
  187 + results.source = node.attr.src;
  188 + }
  189 +
  190 + if (customHandler.start) {
  191 + customHandler.start(node, results);
  192 + }
  193 +
  194 + if (unary) {
  195 + // if this tag doesn't have end tag
  196 + // like <img src="hoge.png"/>
  197 + // add to parents
  198 + const parent = bufArray[0] || results;
  199 + if (parent.nodes === undefined) {
  200 + parent.nodes = [];
  201 + }
  202 + parent.nodes.push(node);
  203 + } else {
  204 + bufArray.unshift(node);
  205 + }
  206 + },
  207 + end(tag) {
  208 + // merge into parent tag
  209 + const node = bufArray.shift();
  210 + if (node.tag !== tag) {
  211 + console.error('invalid state: mismatch end tag');
  212 + }
  213 +
  214 + // 当有缓存source资源时于于video补上src资源
  215 + if (node.tag === 'video' && results.source) {
  216 + node.attr.src = results.source;
  217 + delete results.source;
  218 + }
  219 +
  220 + if (customHandler.end) {
  221 + customHandler.end(node, results);
  222 + }
  223 +
  224 + if (bufArray.length === 0) {
  225 + results.nodes.push(node);
  226 + } else {
  227 + const parent = bufArray[0];
  228 + if (!parent.nodes) {
  229 + parent.nodes = [];
  230 + }
  231 + parent.nodes.push(node);
  232 + }
  233 + },
  234 + chars(text) {
  235 + if (!text.trim()) return;
  236 +
  237 + const node = {
  238 + node: 'text',
  239 + text,
  240 + };
  241 +
  242 + if (customHandler.chars) {
  243 + customHandler.chars(node, results);
  244 + }
  245 +
  246 + if (bufArray.length === 0) {
  247 + results.nodes.push(node);
  248 + } else {
  249 + const parent = bufArray[0];
  250 + if (parent.nodes === undefined) {
  251 + parent.nodes = [];
  252 + }
  253 + parent.nodes.push(node);
  254 + }
  255 + },
  256 + });
  257 +
  258 + return results;
  259 +}
  260 +
  261 +export default html2json;
  1 +/**
  2 + *
  3 + * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
  4 + *
  5 + * author: Di (微信小程序开发工程师)
  6 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7 + * 垂直微信小程序开发交流社区
  8 + *
  9 + * github地址: https://github.com/icindy/wxParse
  10 + *
  11 + * for: 微信小程序富文本解析
  12 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13 + */
  14 +// Regular Expressions for parsing tags and attributes
  15 +
  16 +const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  17 +const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
  18 +const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  19 +
  20 +function makeMap(str) {
  21 + const obj = {};
  22 + const items = str.split(',');
  23 + for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  24 + return obj;
  25 +}
  26 +
  27 +// Empty Elements - HTML 5
  28 +const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
  29 +
  30 +// Block Elements - HTML 5
  31 +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');
  32 +
  33 +// Inline Elements - HTML 5
  34 +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');
  35 +
  36 +// Elements that you can, intentionally, leave open
  37 +// (and which close themselves)
  38 +const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  39 +
  40 +// Attributes that have their values filled in disabled="disabled"
  41 +const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
  42 +
  43 +function HTMLParser(html, handler) {
  44 + let index;
  45 + let chars;
  46 + let match;
  47 + let last = html;
  48 + const stack = [];
  49 +
  50 + stack.last = () => stack[stack.length - 1];
  51 +
  52 + function parseEndTag(tag, tagName) {
  53 + // If no tag name is provided, clean shop
  54 + let pos;
  55 + if (!tagName) {
  56 + pos = 0;
  57 + } else {
  58 + // Find the closest opened tag of the same type
  59 + tagName = tagName.toLowerCase();
  60 + for (pos = stack.length - 1; pos >= 0; pos -= 1) {
  61 + if (stack[pos] === tagName) break;
  62 + }
  63 + }
  64 + if (pos >= 0) {
  65 + // Close all the open elements, up the stack
  66 + for (let i = stack.length - 1; i >= pos; i -= 1) {
  67 + if (handler.end) handler.end(stack[i]);
  68 + }
  69 +
  70 + // Remove the open elements from the stack
  71 + stack.length = pos;
  72 + }
  73 + }
  74 +
  75 + function parseStartTag(tag, tagName, rest, unary) {
  76 + tagName = tagName.toLowerCase();
  77 +
  78 + if (block[tagName]) {
  79 + while (stack.last() && inline[stack.last()]) {
  80 + parseEndTag('', stack.last());
  81 + }
  82 + }
  83 +
  84 + if (closeSelf[tagName] && stack.last() === tagName) {
  85 + parseEndTag('', tagName);
  86 + }
  87 +
  88 + unary = empty[tagName] || !!unary;
  89 +
  90 + if (!unary) stack.push(tagName);
  91 +
  92 + if (handler.start) {
  93 + const attrs = [];
  94 +
  95 + rest.replace(attr, function genAttr(matches, name) {
  96 + const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
  97 +
  98 + attrs.push({
  99 + name,
  100 + value,
  101 + escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
  102 + });
  103 + });
  104 +
  105 + if (handler.start) {
  106 + handler.start(tagName, attrs, unary);
  107 + }
  108 + }
  109 + }
  110 +
  111 + while (html) {
  112 + chars = true;
  113 +
  114 + if (html.indexOf('</') === 0) {
  115 + match = html.match(endTag);
  116 +
  117 + if (match) {
  118 + html = html.substring(match[0].length);
  119 + match[0].replace(endTag, parseEndTag);
  120 + chars = false;
  121 + }
  122 +
  123 + // start tag
  124 + } else if (html.indexOf('<') === 0) {
  125 + match = html.match(startTag);
  126 +
  127 + if (match) {
  128 + html = html.substring(match[0].length);
  129 + match[0].replace(startTag, parseStartTag);
  130 + chars = false;
  131 + }
  132 + }
  133 +
  134 + if (chars) {
  135 + index = html.indexOf('<');
  136 + let text = '';
  137 + while (index === 0) {
  138 + text += '<';
  139 + html = html.substring(1);
  140 + index = html.indexOf('<');
  141 + }
  142 + text += index < 0 ? html : html.substring(0, index);
  143 + html = index < 0 ? '' : html.substring(index);
  144 +
  145 + if (handler.chars) handler.chars(text);
  146 + }
  147 +
  148 + if (html === last) throw new Error(`Parse Error: ${html}`);
  149 + last = html;
  150 + }
  151 +
  152 + // Clean up any remaining tags
  153 + parseEndTag();
  154 +}
  155 +
  156 +export default HTMLParser;
  1 +// HTML 支持的数学符号
  2 +function strNumDiscode(str) {
  3 + str = str.replace(/&forall;/g, '∀');
  4 + str = str.replace(/&part;/g, '∂');
  5 + str = str.replace(/&exist;/g, '∃');
  6 + str = str.replace(/&empty;/g, '∅');
  7 + str = str.replace(/&nabla;/g, '∇');
  8 + str = str.replace(/&isin;/g, '∈');
  9 + str = str.replace(/&notin;/g, '∉');
  10 + str = str.replace(/&ni;/g, '∋');
  11 + str = str.replace(/&prod;/g, '∏');
  12 + str = str.replace(/&sum;/g, '∑');
  13 + str = str.replace(/&minus;/g, '−');
  14 + str = str.replace(/&lowast;/g, '∗');
  15 + str = str.replace(/&radic;/g, '√');
  16 + str = str.replace(/&prop;/g, '∝');
  17 + str = str.replace(/&infin;/g, '∞');
  18 + str = str.replace(/&ang;/g, '∠');
  19 + str = str.replace(/&and;/g, '∧');
  20 + str = str.replace(/&or;/g, '∨');
  21 + str = str.replace(/&cap;/g, '∩');
  22 + str = str.replace(/&cup;/g, '∪');
  23 + str = str.replace(/&int;/g, '∫');
  24 + str = str.replace(/&there4;/g, '∴');
  25 + str = str.replace(/&sim;/g, '∼');
  26 + str = str.replace(/&cong;/g, '≅');
  27 + str = str.replace(/&asymp;/g, '≈');
  28 + str = str.replace(/&ne;/g, '≠');
  29 + str = str.replace(/&le;/g, '≤');
  30 + str = str.replace(/&ge;/g, '≥');
  31 + str = str.replace(/&sub;/g, '⊂');
  32 + str = str.replace(/&sup;/g, '⊃');
  33 + str = str.replace(/&nsub;/g, '⊄');
  34 + str = str.replace(/&sube;/g, '⊆');
  35 + str = str.replace(/&supe;/g, '⊇');
  36 + str = str.replace(/&oplus;/g, '⊕');
  37 + str = str.replace(/&otimes;/g, '⊗');
  38 + str = str.replace(/&perp;/g, '⊥');
  39 + str = str.replace(/&sdot;/g, '⋅');
  40 + return str;
  41 +}
  42 +
  43 +// HTML 支持的希腊字母
  44 +function strGreeceDiscode(str) {
  45 + str = str.replace(/&Alpha;/g, 'Α');
  46 + str = str.replace(/&Beta;/g, 'Β');
  47 + str = str.replace(/&Gamma;/g, 'Γ');
  48 + str = str.replace(/&Delta;/g, 'Δ');
  49 + str = str.replace(/&Epsilon;/g, 'Ε');
  50 + str = str.replace(/&Zeta;/g, 'Ζ');
  51 + str = str.replace(/&Eta;/g, 'Η');
  52 + str = str.replace(/&Theta;/g, 'Θ');
  53 + str = str.replace(/&Iota;/g, 'Ι');
  54 + str = str.replace(/&Kappa;/g, 'Κ');
  55 + str = str.replace(/&Lambda;/g, 'Λ');
  56 + str = str.replace(/&Mu;/g, 'Μ');
  57 + str = str.replace(/&Nu;/g, 'Ν');
  58 + str = str.replace(/&Xi;/g, 'Ν');
  59 + str = str.replace(/&Omicron;/g, 'Ο');
  60 + str = str.replace(/&Pi;/g, 'Π');
  61 + str = str.replace(/&Rho;/g, 'Ρ');
  62 + str = str.replace(/&Sigma;/g, 'Σ');
  63 + str = str.replace(/&Tau;/g, 'Τ');
  64 + str = str.replace(/&Upsilon;/g, 'Υ');
  65 + str = str.replace(/&Phi;/g, 'Φ');
  66 + str = str.replace(/&Chi;/g, 'Χ');
  67 + str = str.replace(/&Psi;/g, 'Ψ');
  68 + str = str.replace(/&Omega;/g, 'Ω');
  69 +
  70 + str = str.replace(/&alpha;/g, 'α');
  71 + str = str.replace(/&beta;/g, 'β');
  72 + str = str.replace(/&gamma;/g, 'γ');
  73 + str = str.replace(/&delta;/g, 'δ');
  74 + str = str.replace(/&epsilon;/g, 'ε');
  75 + str = str.replace(/&zeta;/g, 'ζ');
  76 + str = str.replace(/&eta;/g, 'η');
  77 + str = str.replace(/&theta;/g, 'θ');
  78 + str = str.replace(/&iota;/g, 'ι');
  79 + str = str.replace(/&kappa;/g, 'κ');
  80 + str = str.replace(/&lambda;/g, 'λ');
  81 + str = str.replace(/&mu;/g, 'μ');
  82 + str = str.replace(/&nu;/g, 'ν');
  83 + str = str.replace(/&xi;/g, 'ξ');
  84 + str = str.replace(/&omicron;/g, 'ο');
  85 + str = str.replace(/&pi;/g, 'π');
  86 + str = str.replace(/&rho;/g, 'ρ');
  87 + str = str.replace(/&sigmaf;/g, 'ς');
  88 + str = str.replace(/&sigma;/g, 'σ');
  89 + str = str.replace(/&tau;/g, 'τ');
  90 + str = str.replace(/&upsilon;/g, 'υ');
  91 + str = str.replace(/&phi;/g, 'φ');
  92 + str = str.replace(/&chi;/g, 'χ');
  93 + str = str.replace(/&psi;/g, 'ψ');
  94 + str = str.replace(/&omega;/g, 'ω');
  95 + str = str.replace(/&thetasym;/g, 'ϑ');
  96 + str = str.replace(/&upsih;/g, 'ϒ');
  97 + str = str.replace(/&piv;/g, 'ϖ');
  98 + str = str.replace(/&middot;/g, '·');
  99 + return str;
  100 +}
  101 +
  102 +function strcharacterDiscode(str) {
  103 + // 加入常用解析
  104 + str = str.replace(/&nbsp;/g, ' ');
  105 + str = str.replace(/&ensp;/g, ' ');
  106 + str = str.replace(/&emsp;/g, ' ');
  107 + str = str.replace(/&quot;/g, "'");
  108 + str = str.replace(/&amp;/g, '&');
  109 + str = str.replace(/&lt;/g, '<');
  110 + str = str.replace(/&gt;/g, '>');
  111 + str = str.replace(/&#8226;/g, '•');
  112 +
  113 + return str;
  114 +}
  115 +
  116 +// HTML 支持的其他实体
  117 +function strOtherDiscode(str) {
  118 + str = str.replace(/&OElig;/g, 'Œ');
  119 + str = str.replace(/&oelig;/g, 'œ');
  120 + str = str.replace(/&Scaron;/g, 'Š');
  121 + str = str.replace(/&scaron;/g, 'š');
  122 + str = str.replace(/&Yuml;/g, 'Ÿ');
  123 + str = str.replace(/&fnof;/g, 'ƒ');
  124 + str = str.replace(/&circ;/g, 'ˆ');
  125 + str = str.replace(/&tilde;/g, '˜');
  126 + str = str.replace(/&ensp;/g, '');
  127 + str = str.replace(/&emsp;/g, '');
  128 + str = str.replace(/&thinsp;/g, '');
  129 + str = str.replace(/&zwnj;/g, '');
  130 + str = str.replace(/&zwj;/g, '');
  131 + str = str.replace(/&lrm;/g, '');
  132 + str = str.replace(/&rlm;/g, '');
  133 + str = str.replace(/&ndash;/g, '–');
  134 + str = str.replace(/&mdash;/g, '—');
  135 + str = str.replace(/&lsquo;/g, '‘');
  136 + str = str.replace(/&rsquo;/g, '’');
  137 + str = str.replace(/&sbquo;/g, '‚');
  138 + str = str.replace(/&ldquo;/g, '“');
  139 + str = str.replace(/&rdquo;/g, '”');
  140 + str = str.replace(/&bdquo;/g, '„');
  141 + str = str.replace(/&dagger;/g, '†');
  142 + str = str.replace(/&Dagger;/g, '‡');
  143 + str = str.replace(/&bull;/g, '•');
  144 + str = str.replace(/&hellip;/g, '…');
  145 + str = str.replace(/&permil;/g, '‰');
  146 + str = str.replace(/&prime;/g, '′');
  147 + str = str.replace(/&Prime;/g, '″');
  148 + str = str.replace(/&lsaquo;/g, '‹');
  149 + str = str.replace(/&rsaquo;/g, '›');
  150 + str = str.replace(/&oline;/g, '‾');
  151 + str = str.replace(/&euro;/g, '€');
  152 + str = str.replace(/&trade;/g, '™');
  153 +
  154 + str = str.replace(/&larr;/g, '←');
  155 + str = str.replace(/&uarr;/g, '↑');
  156 + str = str.replace(/&rarr;/g, '→');
  157 + str = str.replace(/&darr;/g, '↓');
  158 + str = str.replace(/&harr;/g, '↔');
  159 + str = str.replace(/&crarr;/g, '↵');
  160 + str = str.replace(/&lceil;/g, '⌈');
  161 + str = str.replace(/&rceil;/g, '⌉');
  162 +
  163 + str = str.replace(/&lfloor;/g, '⌊');
  164 + str = str.replace(/&rfloor;/g, '⌋');
  165 + str = str.replace(/&loz;/g, '◊');
  166 + str = str.replace(/&spades;/g, '♠');
  167 + str = str.replace(/&clubs;/g, '♣');
  168 + str = str.replace(/&hearts;/g, '♥');
  169 +
  170 + str = str.replace(/&diams;/g, '♦');
  171 + str = str.replace(/&#39;/g, "'");
  172 + return str;
  173 +}
  174 +
  175 +function strDiscode(str) {
  176 + str = strNumDiscode(str);
  177 + str = strGreeceDiscode(str);
  178 + str = strcharacterDiscode(str);
  179 + str = strOtherDiscode(str);
  180 + return str;
  181 +}
  182 +
  183 +function urlToHttpUrl(url, domain) {
  184 + if (/^\/\//.test(url)) {
  185 + return `https:${url}`;
  186 + } else if (/^\//.test(url)) {
  187 + return `https://${domain}${url}`;
  188 + }
  189 + return url;
  190 +}
  191 +
  192 +export default {
  193 + strDiscode,
  194 + urlToHttpUrl,
  195 +};
  1 +## uParse 适用于 uni-app/mpvue 的富文本解析组件
  2 +
  3 +> 支持 Html、Markdown 解析,Fork自: [mpvue-wxParse](https://github.com/F-loat/mpvue-wxParse)
  4 +
  5 +
  6 +## 属性
  7 +
  8 +| 名称 | 类型 | 默认值 | 描述 |
  9 +| -----------------|--------------- | ------------- | ---------------- |
  10 +| loading | Boolean | false | 数据加载状态 |
  11 +| className | String | — | 自定义 class 名称 |
  12 +| content | String | — | 渲染内容 |
  13 +| noData | String | 数据不能为空 | 空数据时的渲染展示 |
  14 +| startHandler | Function | 见源码 | 自定义 parser 函数 |
  15 +| endHandler | Function | null | 自定义 parser 函数 |
  16 +| charsHandler | Function | null | 自定义 parser 函数 |
  17 +| imageProp | Object | 见下文 | 图片相关参数 |
  18 +
  19 +### 自定义 parser 函数具体介绍
  20 +
  21 +* 传入的参数为当前节点 `node` 对象及解析结果 `results` 对象,例如 `startHandler(node, results)`
  22 +* 无需返回值,通过对传入的参数直接操作来完成需要的改动
  23 +* 自定义函数会在原解析函数处理之后执行
  24 +
  25 +### imageProp 对象具体属性
  26 +
  27 +| 名称 | 类型 | 默认值 | 描述 |
  28 +| -----------------|--------------- | ------------- | ------------------ |
  29 +| mode | String | 'aspectFit' | 图片裁剪、缩放的模式 |
  30 +| padding | Number | 0 | 图片内边距 |
  31 +| lazyLoad | Boolean | false | 图片懒加载 |
  32 +| domain | String | '' | 图片服务域名 |
  33 +
  34 +## 事件
  35 +
  36 +| 名称 | 参数 | 描述 |
  37 +| -----------------|----------------- | ---------------- |
  38 +| preview | 图片地址,原始事件 | 预览图片时触发 |
  39 +| navigate | 链接地址,原始事件 | 点击链接时触发 |
  40 +
  41 +## 基本使用方法
  42 +
  43 +
  44 +``` vue
  45 +<template>
  46 + <div>
  47 + <u-parse :content="article" @preview="preview" @navigate="navigate" />
  48 + </div>
  49 +</template>
  50 +
  51 +<script>
  52 +import uParse from '@/components/u-parse/u-parse.vue'
  53 +
  54 +export default {
  55 + components: {
  56 + uParse
  57 + },
  58 + data () {
  59 + return {
  60 + article: '<div>我是HTML代码</div>'
  61 + }
  62 + },
  63 + methods: {
  64 + preview(src, e) {
  65 + // do something
  66 + },
  67 + navigate(href, e) {
  68 + // do something
  69 + }
  70 + }
  71 +}
  72 +</script>
  73 +
  74 +<style>
  75 +@import url("@/components/u-parse/u-parse.css");
  76 +</style>
  77 +```
  78 +
  79 +
  80 +## 渲染 Markdown
  81 +
  82 +> 先将 markdown 转换为 html 即可
  83 +
  84 +```
  85 +npm install marked
  86 +```
  87 +
  88 +``` js
  89 +import marked from 'marked'
  90 +import uParse from '@/components/u-parse/u-parse.vue'
  91 +
  92 +export default {
  93 + components: {
  94 + uParse
  95 + },
  96 + data () {
  97 + return {
  98 + article: marked(`#hello, markdown!`)
  99 + }
  100 + }
  101 +}
  102 +```
  1 +/**
  2 + * author: Di (微信小程序开发工程师)
  3 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  4 + * 垂直微信小程序开发交流社区
  5 + *
  6 + * github地址: https://github.com/icindy/wxParse
  7 + *
  8 + * for: 微信小程序富文本解析
  9 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  10 + */
  11 +
  12 +.wxParse {
  13 + width: 100%;
  14 + font-family: Helvetica, sans-serif;
  15 + font-size: 30upx;
  16 + color: #666;
  17 + line-height: 1.8;
  18 +}
  19 +
  20 +.wxParse view {
  21 + word-break: hyphenate;
  22 +}
  23 +
  24 +.wxParse .inline {
  25 + display: inline;
  26 + margin: 0;
  27 + padding: 0;
  28 +}
  29 +
  30 +.wxParse .div {
  31 + margin: 0;
  32 + padding: 0;
  33 +}
  34 +
  35 +.wxParse .h1 .text {
  36 + font-size: 2em;
  37 + margin: 0.67em 0;
  38 +}
  39 +.wxParse .h2 .text {
  40 + font-size: 1.5em;
  41 + margin: 0.83em 0;
  42 +}
  43 +.wxParse .h3 .text {
  44 + font-size: 1.17em;
  45 + margin: 1em 0;
  46 +}
  47 +.wxParse .h4 .text {
  48 + margin: 1.33em 0;
  49 +}
  50 +.wxParse .h5 .text {
  51 + font-size: 0.83em;
  52 + margin: 1.67em 0;
  53 +}
  54 +.wxParse .h6 .text {
  55 + font-size: 0.67em;
  56 + margin: 2.33em 0;
  57 +}
  58 +
  59 +.wxParse .h1 .text,
  60 +.wxParse .h2 .text,
  61 +.wxParse .h3 .text,
  62 +.wxParse .h4 .text,
  63 +.wxParse .h5 .text,
  64 +.wxParse .h6 .text,
  65 +.wxParse .b,
  66 +.wxParse .strong {
  67 + font-weight: bolder;
  68 +}
  69 +
  70 +
  71 +.wxParse .p {
  72 + margin: 1em 0;
  73 +}
  74 +
  75 +.wxParse .i,
  76 +.wxParse .cite,
  77 +.wxParse .em,
  78 +.wxParse .var,
  79 +.wxParse .address {
  80 + font-style: italic;
  81 +}
  82 +
  83 +.wxParse .pre,
  84 +.wxParse .tt,
  85 +.wxParse .code,
  86 +.wxParse .kbd,
  87 +.wxParse .samp {
  88 + font-family: monospace;
  89 +}
  90 +.wxParse .pre {
  91 + overflow: auto;
  92 + background: #f5f5f5;
  93 + padding: 16upx;
  94 + white-space: pre;
  95 + margin: 1em 0upx;
  96 +}
  97 +.wxParse .code {
  98 + display: inline;
  99 + background: #f5f5f5;
  100 +}
  101 +
  102 +.wxParse .big {
  103 + font-size: 1.17em;
  104 +}
  105 +
  106 +.wxParse .small,
  107 +.wxParse .sub,
  108 +.wxParse .sup {
  109 + font-size: 0.83em;
  110 +}
  111 +
  112 +.wxParse .sub {
  113 + vertical-align: sub;
  114 +}
  115 +.wxParse .sup {
  116 + vertical-align: super;
  117 +}
  118 +
  119 +.wxParse .s,
  120 +.wxParse .strike,
  121 +.wxParse .del {
  122 + text-decoration: line-through;
  123 +}
  124 +
  125 +.wxParse .strong,
  126 +.wxParse .s {
  127 + display: inline;
  128 +}
  129 +
  130 +.wxParse .a {
  131 + color: deepskyblue;
  132 +}
  133 +
  134 +.wxParse .video {
  135 + text-align: center;
  136 + margin: 22upx 0;
  137 +}
  138 +
  139 +.wxParse .video-video {
  140 + width: 100%;
  141 +}
  142 +
  143 +.wxParse .img {
  144 + display: inline-block;
  145 + width: 0;
  146 + height: 0;
  147 + max-width: 100%;
  148 + overflow: hidden;
  149 +}
  150 +
  151 +.wxParse .blockquote {
  152 + margin: 10upx 0;
  153 + padding: 22upx 0 22upx 22upx;
  154 + font-family: Courier, Calibri, "宋体";
  155 + background: #f5f5f5;
  156 + border-left: 6upx solid #dbdbdb;
  157 +}
  158 +.wxParse .blockquote .p {
  159 + margin: 0;
  160 +}
  161 +
  162 +.wxParse .ul, .wxParse .ol {
  163 + display: block;
  164 + margin: 1em 0;
  165 + padding-left: 33upx;
  166 +}
  167 +.wxParse .ol {
  168 + list-style-type: disc;
  169 +}
  170 +.wxParse .ol {
  171 + list-style-type: decimal;
  172 +}
  173 +.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
  174 + display: list-item;
  175 + align-items: baseline;
  176 + text-align: match-parent;
  177 +}
  178 +
  179 +.wxParse .ol>.li,.wxParse .ul>.li {
  180 + display: list-item;
  181 + align-items: baseline;
  182 + text-align: match-parent;
  183 +}
  184 +.wxParse .ul .ul, .wxParse .ol .ul {
  185 + list-style-type: circle;
  186 +}
  187 +.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
  188 + list-style-type: square;
  189 +}
  190 +
  191 +.wxParse .u {
  192 + text-decoration: underline;
  193 +}
  194 +.wxParse .hide {
  195 + display: none;
  196 +}
  197 +.wxParse .del {
  198 + display: inline;
  199 +}
  200 +.wxParse .figure {
  201 + overflow: hidden;
  202 +}
  203 +
  204 +.wxParse .table {
  205 + width: 100%;
  206 +}
  207 +.wxParse .thead, .wxParse .tfoot, .wxParse .tr {
  208 + display: flex;
  209 + flex-direction: row;
  210 +}
  211 +.wxParse .tr {
  212 + width:100%;
  213 + display: flex;
  214 + border-right: 2upx solid #e0e0e0;
  215 + border-bottom: 2upx solid #e0e0e0;
  216 +}
  217 +.wxParse .th,
  218 +.wxParse .td {
  219 + display: flex;
  220 + width: 1276upx;
  221 + overflow: auto;
  222 + flex: 1;
  223 + padding: 11upx;
  224 + border-left: 2upx solid #e0e0e0;
  225 +}
  226 +.wxParse .td:last {
  227 + border-top: 2upx solid #e0e0e0;
  228 +}
  229 +.wxParse .th {
  230 + background: #f0f0f0;
  231 + border-top: 2upx solid #e0e0e0;
  232 +}
  1 +<!--**
  2 + * forked from:https://github.com/F-loat/mpvue-wxParse
  3 + *
  4 + * github地址: https://github.com/dcloudio/uParse
  5 + *
  6 + * for: uni-app框架下 富文本解析
  7 + */-->
  8 +
  9 +<template>
  10 +<!--基础元素-->
  11 +<div class="wxParse" :class="className" v-if="!loading">
  12 + <block v-for="(node,index) of nodes" :key="index">
  13 + <wxParseTemplate :node="node" />
  14 + </block>
  15 +</div>
  16 +</template>
  17 +
  18 +<script>
  19 +import HtmlToJson from './libs/html2json';
  20 +import wxParseTemplate from './components/wxParseTemplate0';
  21 +
  22 +export default {
  23 + name: 'wxParse',
  24 + props: {
  25 + loading: {
  26 + type: Boolean,
  27 + default: false,
  28 + },
  29 + className: {
  30 + type: String,
  31 + default: '',
  32 + },
  33 + content: {
  34 + type: String,
  35 + default: '',
  36 + },
  37 + noData: {
  38 + type: String,
  39 + default: '<div style="color: red;">数据不能为空</div>',
  40 + },
  41 + startHandler: {
  42 + type: Function,
  43 + default() {
  44 + return (node) => {
  45 + node.attr.class = null;
  46 + node.attr.style = null;
  47 + };
  48 + },
  49 + },
  50 + endHandler: {
  51 + type: Function,
  52 + default: null,
  53 + },
  54 + charsHandler: {
  55 + type: Function,
  56 + default: null,
  57 + },
  58 + imageProp: {
  59 + type: Object,
  60 + default() {
  61 + return {
  62 + mode: 'aspectFit',
  63 + padding: 0,
  64 + lazyLoad: false,
  65 + domain: '',
  66 + };
  67 + },
  68 + },
  69 + },
  70 + components: {
  71 + wxParseTemplate,
  72 + },
  73 + data() {
  74 + return {
  75 + imageUrls: [],
  76 + };
  77 + },
  78 + computed: {
  79 + nodes() {
  80 + const {
  81 + content,
  82 + noData,
  83 + imageProp,
  84 + startHandler,
  85 + endHandler,
  86 + charsHandler,
  87 + } = this;
  88 + const parseData = content || noData;
  89 + const customHandler = {
  90 + start: startHandler,
  91 + end: endHandler,
  92 + chars: charsHandler,
  93 + };
  94 + const results = HtmlToJson(parseData, customHandler, imageProp, this);
  95 + this.imageUrls = results.imageUrls;
  96 + console.log(results)
  97 + return results.nodes;
  98 + },
  99 + },
  100 + methods: {
  101 + navigate(href, $event) {
  102 + this.$emit('navigate', href, $event);
  103 + },
  104 + preview(src, $event) {
  105 + if (!this.imageUrls.length) return;
  106 + wx.previewImage({
  107 + current: src,
  108 + urls: this.imageUrls,
  109 + });
  110 + this.$emit('preview', src, $event);
  111 + },
  112 + removeImageUrl(src) {
  113 + const { imageUrls } = this;
  114 + imageUrls.splice(imageUrls.indexOf(src), 1);
  115 + },
  116 + },
  117 +};
  118 +</script>
  1 +import Vue from 'vue'
  2 +import App from './App'
  3 +
  4 +Vue.config.productionTip = false
  5 +
  6 +App.mpType = 'app'
  7 +
  8 +const app = new Vue({
  9 + ...App
  10 +})
  11 +app.$mount()
  1 +{
  2 + "name" : "card",
  3 + "appid" : "__UNI__C5AC020",
  4 + "description" : "",
  5 + "versionName" : "1.0.0",
  6 + "versionCode" : "100",
  7 + "transformPx" : false,
  8 + /* 5+App特有相关 */
  9 + "app-plus" : {
  10 + "usingComponents" : true,
  11 + "nvueCompiler" : "uni-app",
  12 + "splashscreen" : {
  13 + "alwaysShowBeforeRender" : true,
  14 + "waiting" : true,
  15 + "autoclose" : true,
  16 + "delay" : 0
  17 + },
  18 + /* 模块配置 */
  19 + "modules" : {},
  20 + /* 应用发布信息 */
  21 + "distribute" : {
  22 + /* android打包配置 */
  23 + "android" : {
  24 + "permissions" : [
  25 + "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
  26 + "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
  27 + "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
  28 + "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
  29 + "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
  30 + "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
  31 + "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
  32 + "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
  33 + "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
  34 + "<uses-permission android:name=\"android.permission.CAMERA\"/>",
  35 + "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
  36 + "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
  37 + "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
  38 + "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
  39 + "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
  40 + "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
  41 + "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
  42 + "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
  43 + "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
  44 + "<uses-feature android:name=\"android.hardware.camera\"/>",
  45 + "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
  46 + "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
  47 + ]
  48 + },
  49 + /* ios打包配置 */
  50 + "ios" : {},
  51 + /* SDK配置 */
  52 + "sdkConfigs" : {}
  53 + }
  54 + },
  55 + /* 快应用特有相关 */
  56 + "quickapp" : {},
  57 + /* 小程序特有相关 */
  58 + "mp-weixin" : {
  59 + "appid" : "wx5282e7febc772e8c",
  60 + "setting" : {
  61 + "urlCheck" : false
  62 + },
  63 + "usingComponents" : true
  64 + },
  65 + "mp-alipay" : {
  66 + "usingComponents" : true
  67 + },
  68 + "mp-baidu" : {
  69 + "usingComponents" : true
  70 + },
  71 + "mp-toutiao" : {
  72 + "usingComponents" : true
  73 + }
  74 +}
  1 +{
  2 + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
  3 + // 首页
  4 + {
  5 + "path": "pages/index/index",
  6 + "style": {
  7 + "navigationBarTitleText": "轴承名片网",
  8 + "navigationBarBackgroundColor": "#fff",
  9 + "navigationBarTextStyle": "black"
  10 + }
  11 + },
  12 + // 名片列表
  13 + {
  14 + "path": "pages/index/cardList",
  15 + "style": {
  16 + "navigationBarTitleText": "名片列表",
  17 + "navigationBarBackgroundColor": "#fff",
  18 + "navigationBarTextStyle": "black"
  19 + }
  20 + },
  21 + // 搜索结果
  22 + {
  23 + "path": "pages/index/search",
  24 + "style": {
  25 + "navigationBarTitleText": "搜索",
  26 + "navigationBarBackgroundColor": "#fff",
  27 + "navigationBarTextStyle": "black"
  28 + }
  29 + },
  30 + // 名片详情
  31 + {
  32 + "path": "pages/index/cardDetail",
  33 + "style": {
  34 + "navigationBarTitleText": "轴承名片网",
  35 + "navigationBarBackgroundColor": "#fff",
  36 + "navigationBarTextStyle": "black"
  37 + }
  38 + },
  39 + // 我的名片
  40 + {
  41 + "path": "pages/card/card",
  42 + "style": {
  43 + "navigationBarTitleText": "轴承名片网",
  44 + "navigationBarBackgroundColor": "#fff",
  45 + "navigationBarTextStyle": "black"
  46 + }
  47 + },
  48 + // 添加名片
  49 + {
  50 + "path": "pages/card/addCard",
  51 + "style": {
  52 + "navigationBarTitleText": "发布名片",
  53 + "navigationBarBackgroundColor": "#fff",
  54 + "navigationBarTextStyle": "black"
  55 + }
  56 + },
  57 + // 编辑名片
  58 + {
  59 + "path": "pages/card/editorCard",
  60 + "style": {
  61 + "navigationBarTitleText": "编辑名片",
  62 + "navigationBarBackgroundColor": "#fff",
  63 + "navigationBarTextStyle": "black"
  64 + }
  65 + },
  66 + // 我的收藏
  67 + {
  68 + "path": "pages/collect/collect",
  69 + "style": {
  70 + "navigationBarTitleText": "名片收藏",
  71 + "navigationBarBackgroundColor": "#fff",
  72 + "navigationBarTextStyle": "black"
  73 + }
  74 + },
  75 + // 会员中心
  76 + {
  77 + "path": "pages/vip/vip",
  78 + "style": {
  79 + "navigationBarTitleText": "会员中心",
  80 + "navigationBarBackgroundColor": "#fff",
  81 + "navigationBarTextStyle": "black"
  82 + }
  83 + },
  84 + // 我的会员
  85 + {
  86 + "path": "pages/vip/myVip",
  87 + "style": {
  88 + "navigationBarTitleText": "我的会员",
  89 + "navigationBarBackgroundColor": "#fff",
  90 + "navigationBarTextStyle": "black"
  91 + }
  92 + },
  93 + // 我的充值
  94 + {
  95 + "path": "pages/vip/recharge",
  96 + "style": {
  97 + "navigationBarTitleText": "我的充值",
  98 + "navigationBarBackgroundColor": "#fff",
  99 + "navigationBarTextStyle": "black"
  100 + }
  101 + },
  102 + // 联系客服
  103 + {
  104 + "path": "pages/vip/contactService",
  105 + "style": {
  106 + "navigationBarTitleText": "联系客服",
  107 + "navigationBarBackgroundColor": "#fff",
  108 + "navigationBarTextStyle": "black"
  109 + }
  110 + },
  111 + // 关于我们
  112 + {
  113 + "path": "pages/vip/aboutUs",
  114 + "style": {
  115 + "navigationBarTitleText": "关于我们",
  116 + "navigationBarBackgroundColor": "#fff",
  117 + "navigationBarTextStyle": "black"
  118 + }
  119 + },
  120 + // 授权登录
  121 + {
  122 + "path": "pages/start/start",
  123 + "style": {
  124 + "navigationBarTitleText": "",
  125 + "navigationBarBackgroundColor": "#fff",
  126 + "navigationBarTextStyle": "black"
  127 + }
  128 + }
  129 + ],
  130 + "globalStyle": {
  131 + "navigationBarTextStyle": "black",
  132 + "navigationBarTitleText": "uni-app",
  133 + "navigationBarBackgroundColor": "#F8F8F8",
  134 + "backgroundColor": "#F8F8F8"
  135 + },
  136 + "tabBar": {
  137 + "color": "#8C9198",
  138 + "selectedColor": "#0083FB",
  139 + "borderStyle": "black",
  140 + "backgroundColor": "#ffffff",
  141 + "list": [{
  142 + "pagePath": "pages/index/index",
  143 + "iconPath": "static/noindex1.png",
  144 + "selectedIconPath": "static/index1.png",
  145 + "text": "首页"
  146 + }, {
  147 + "pagePath": "pages/card/card",
  148 + "iconPath": "static/nocard1.png",
  149 + "selectedIconPath": "static/card1.png",
  150 + "text": "我的名片"
  151 + },{
  152 + "pagePath": "pages/collect/collect",
  153 + "iconPath": "static/nocollect1.png",
  154 + "selectedIconPath": "static/collect1.png",
  155 + "text": "我的收藏"
  156 + }, {
  157 + "pagePath": "pages/vip/vip",
  158 + "iconPath": "static/novip1.png",
  159 + "selectedIconPath": "static/vip1.png",
  160 + "text": "会员中心"
  161 + }]
  162 + }
  163 +}
  1 +<template>
  2 + <view class="add_card" :class="{ over_hide: isHide }">
  3 + <!-- 名片信息 -->
  4 + <view class="add_card_top">
  5 + <!-- 正反面 -->
  6 + <view class="add_card_single">
  7 + <view class="card_front flex_center" @click="uploadPositive()">
  8 + <view class="show_img" v-if="front_image"><image :src="front_image" mode="aspectFill"></image></view>
  9 + <view class="flex_center" v-else>
  10 + <view class="card_upload"><image src="../../static/add.png" mode=""></image></view>
  11 + <view class="card_tips">上传名片正面图片</view>
  12 + </view>
  13 + </view>
  14 + <view class="card_front flex_center" @click="uploadSide()">
  15 + <view class="show_img" v-if="reverse_image"><image :src="reverse_image" mode="aspectFill"></image></view>
  16 + <view class="flex_center" v-else>
  17 + <view class="card_upload"><image src="../../static/add.png" mode=""></image></view>
  18 + <view class="card_tips">上传名片背面图片</view>
  19 + </view>
  20 + </view>
  21 + <view class="upload_tips">建议名片尺寸为360*210像素 </view>
  22 + <view class="msg_single layer_between">
  23 + <view class="single_l">公司名称:</view>
  24 + <input class="single_r" type="text" v-model="company_name" placeholder="请输入公司名称" />
  25 + </view>
  26 + </view>
  27 + <!-- 公司简介 -->
  28 +
  29 + <view class="add_card_single">
  30 + <view class="msg_single">
  31 + <view class="single_l">公司简介:</view>
  32 + <textarea v-model="brief" placeholder="请输入公司简介" maxlength="2000"/>
  33 + <view class="layer_nostar flex_wrap_no">
  34 + <view class="wx_code" v-for="(item, index) in brief_images" :key="index">
  35 + <image :src="item" mode=""></image>
  36 + <image @click="deleteCompany(index)" class="cancle_icon" src="../../static/del_icon@2x.png" mode=""></image>
  37 + </view>
  38 + <view class="wx_code" @click="uploadCompay()"><image src="../../static/add_wx.png" mode=""></image></view>
  39 + </view>
  40 + </view>
  41 + </view>
  42 + <!-- 经营范围 -->
  43 + <view class="add_card_single">
  44 + <view class="msg_single">
  45 + <view class="single_l">经营范围:</view>
  46 + <textarea v-model="scope" placeholder="请输入经营范围" maxlength="2000"/>
  47 + <view class="layer_nostar flex_wrap_no">
  48 + <view class="wx_code" v-for="(item, index) in scope_images" :key="index">
  49 + <image :src="item" mode=""></image>
  50 + <image @click="deleteScope(index)" class="cancle_icon" src="../../static/del_icon@2x.png" mode=""></image>
  51 + </view>
  52 + <view class="wx_code" @click="uploadBusiness()"><image src="../../static/add_wx.png" mode=""></image></view>
  53 + </view>
  54 + </view>
  55 + </view>
  56 + <!-- 各种联系方式 -->
  57 + <view class="add_card_single">
  58 + <view class="msg_single layer_between">
  59 + <view class="single_l">联系人:</view>
  60 + <input class="single_r" type="text" v-model="name" placeholder="请输入联系人" />
  61 + </view>
  62 + </view>
  63 + <view class="add_card_single">
  64 + <view class="msg_single layer_between">
  65 + <view class="single_l">地址:</view>
  66 + <input class="single_r" type="text" v-model="site" placeholder="请输入地址" />
  67 + </view>
  68 + </view>
  69 + <view class="add_card_single">
  70 + <view class="msg_single layer_between">
  71 + <view class="single_l">电话:</view>
  72 + <input class="single_r" type="text" v-model="phone" placeholder="请输入电话" />
  73 + </view>
  74 + </view>
  75 + <view class="add_card_single">
  76 + <view class="msg_single layer_between">
  77 + <view class="single_l">传真:</view>
  78 + <input class="single_r" type="text" v-model="fax" placeholder="请输入传真" />
  79 + </view>
  80 + </view>
  81 + <view class="add_card_single">
  82 + <view class="msg_single layer_between">
  83 + <view class="single_l">手机号:</view>
  84 + <input class="single_r" maxlength="11" type="text" v-model="mobile" placeholder="请输入手机号" />
  85 + </view>
  86 + </view>
  87 + <view class="add_card_single">
  88 + <view class="msg_single layer_between">
  89 + <view class="single_l">QQ:</view>
  90 + <input class="single_r" type="text" v-model="qq" placeholder="请输入QQ号" />
  91 + </view>
  92 + </view>
  93 + <view class="add_card_single">
  94 + <view class="msg_single layer_between">
  95 + <view class="single_l">微信:</view>
  96 + <input class="single_r" type="text" v-model="wechat" placeholder="请输入微信" />
  97 + </view>
  98 + </view>
  99 + <view class="add_card_single">
  100 + <view class="msg_single">
  101 + <view class="single_l">微信二维码:</view>
  102 + <view class="layer_nostar" @click="uploadCode()">
  103 + <view class="wx_img" v-if="weichat_image"><image :src="weichat_image" mode=""></image></view>
  104 + <view class="wx_code" v-else><image src="../../static/add_wx.png" mode=""></image></view>
  105 + </view>
  106 + </view>
  107 + </view>
  108 + </view>
  109 + <!-- 名片分类 -->
  110 +
  111 + <view class="add_card_classify">
  112 + <view class="classify_title">
  113 + 名片分类:
  114 + <text>(可选择{{ category_num }}个名片分类)</text>
  115 + </view>
  116 + <view class="classify_tips">想要增加更多分类,请提交名片升级成VIP后到会员中心增加</view>
  117 + <!-- 轴承列表 -->
  118 + <view class="bearing_classify layer_nostar">
  119 + <!-- 左侧类目 -->
  120 + <view class="bearing_l">
  121 + <view class="bear_l_box flex_column_center">
  122 + <view
  123 + class="bear_l_single flex_warp"
  124 + :class="{ bear_l_active: isLeft == item.id }"
  125 + v-for="(item, index) in leftList"
  126 + :key="index"
  127 + @click="changeLeft(item, index)"
  128 + >
  129 + <view class="bear_l_child">{{ item.name }}</view>
  130 + </view>
  131 + </view>
  132 + </view>
  133 + <!-- 右侧具体分类 -->
  134 + <view class="bearing_r">
  135 + <view class="bear_r_box">
  136 + <view class="bear_r_single" :class="{ bear_r_active: item.isChoice }" v-for="(item, index) in rightList" :key="index" @click="changeRight(item, index)">
  137 + {{ item.name }}
  138 + </view>
  139 + </view>
  140 + </view>
  141 + </view>
  142 + </view>
  143 + <!-- 提交名片 -->
  144 + <view class="submit_btn" @click="submitCard()">提交名片</view>
  145 + <!-- 提交弹窗 -->
  146 + <view class="tx_mask" v-if="isHide" @click="closeDialog()"></view>
  147 + <view class="mask_content" v-if="isHide">
  148 + <view class="mask_top">成为VIP会员,其他用户可以搜索到您的名片</view>
  149 + <view class="mask_bottom" @click="getNow()">立即获取</view>
  150 + </view>
  151 + </view>
  152 +</template>
  153 +
  154 +<script>
  155 +import App from '../../App.vue';
  156 +export default {
  157 + data() {
  158 + return {
  159 + front_image: '', //正面图片
  160 + reverse_image: '', //反面图片
  161 + company_name: '', //公司名称
  162 + brief: '', //公司简介
  163 + brief_images: [], //公司简介图片
  164 + scope: '', //经营范围
  165 + scope_images: [], //经营范围图片
  166 + name: '', //联系人
  167 + phone: '', //电话
  168 + site: '', //地址
  169 + mobile: '', //手机号
  170 + fax: '', //传真
  171 + qq: '', // QQ
  172 + wechat: '', //微信
  173 + weichat_image: '', //微信二维码
  174 + category_ids: [], //分类ID
  175 + category_num: '', //可选分类个数
  176 + // 轴承列表
  177 + // 左侧
  178 + leftList: [],
  179 + isLeft: 0,
  180 + // 右侧
  181 + rightList: [],
  182 + isRight: 0,
  183 + // 弹窗
  184 + isHide: false,
  185 + // 是否为vip 1:是 2:否
  186 + isVip: '',
  187 + // 防连点
  188 + isClick:false,
  189 + imgBrief: [], //公司简介上传数量
  190 + imgScope: []
  191 + };
  192 + },
  193 + methods: {
  194 + // 上传正面图片
  195 + uploadPositive() {
  196 + let t = this;
  197 + uni.chooseImage({
  198 + count: 1, //默认9
  199 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  200 + sourceType: ['album'], //从相册选择
  201 + success: chooseImageRes => {
  202 + const tempFilePaths = chooseImageRes.tempFilePaths;
  203 + App.upload(tempFilePaths[0]).then(res => {
  204 + this.front_image = res.url;
  205 + });
  206 + }
  207 + });
  208 + },
  209 + // 上传反面图片
  210 + uploadSide() {
  211 + let t = this;
  212 + uni.chooseImage({
  213 + count: 1, //默认9
  214 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  215 + sourceType: ['album'], //从相册选择
  216 + success: chooseImageRes => {
  217 + const tempFilePaths = chooseImageRes.tempFilePaths;
  218 + App.upload(tempFilePaths[0]).then(res => {
  219 + this.reverse_image = res.url;
  220 + });
  221 + }
  222 + });
  223 + },
  224 + // 上传公司简介图片
  225 + uploadCompay() {
  226 + let t = this;
  227 + uni.chooseImage({
  228 + count: 3, //默认9
  229 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  230 + sourceType: ['album'], //从相册选择
  231 + success: chooseImageRes => {
  232 + const tempFilePaths = chooseImageRes.tempFilePaths;
  233 + t.imgBrief = [...t.imgBrief,...tempFilePaths]
  234 + if(t.imgBrief.length>3){
  235 + uni.showToast({
  236 + title: '图片总数超过3张',
  237 + icon: 'none'
  238 + });
  239 + return false;
  240 + }
  241 + tempFilePaths.forEach(el => {
  242 + App.upload(el).then(res => {
  243 + t.brief_images.push(res.url);
  244 + });
  245 + });
  246 + }
  247 + });
  248 + },
  249 + // 上传经营范围图片
  250 + uploadBusiness() {
  251 + let t = this;
  252 + uni.chooseImage({
  253 + count: 3, //默认9
  254 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  255 + sourceType: ['album'], //从相册选择
  256 + success: chooseImageRes => {
  257 + const tempFilePaths = chooseImageRes.tempFilePaths;
  258 + t.imgScope = [...t.imgScope, ...tempFilePaths];
  259 + if (t.imgScope.length > 3) {
  260 + uni.showToast({
  261 + title: '图片总数超过3张',
  262 + icon: 'none'
  263 + });
  264 + return false;
  265 + }
  266 + tempFilePaths.forEach(el => {
  267 + App.upload(el).then(res => {
  268 + t.scope_images.push(res.url);
  269 + });
  270 + });
  271 + }
  272 + });
  273 + },
  274 + // 删除公司简介图片
  275 + deleteCompany(index){
  276 + this.imgBrief.splice(index, 1);
  277 + this.brief_images.splice(index,1)
  278 + },
  279 + // 删除经营范围图片
  280 + deleteScope(index){
  281 + this.imgBrief.splice(index, 1);
  282 + this.scope_images.splice(index,1)
  283 + },
  284 + // 上传二维码
  285 + uploadCode() {
  286 + let t = this;
  287 + uni.chooseImage({
  288 + count: 1, //默认9
  289 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  290 + sourceType: ['album'], //从相册选择
  291 + success: chooseImageRes => {
  292 + const tempFilePaths = chooseImageRes.tempFilePaths;
  293 + App.upload(tempFilePaths[0]).then(res => {
  294 + t.weichat_image = res.url;
  295 + });
  296 + }
  297 + });
  298 + },
  299 + // 首页分类数据 左侧一级分类
  300 + getType() {
  301 + let t = this;
  302 + t.leftList = [];
  303 + t.rightList = [];
  304 + let url = '/api/category/get_category_one';
  305 + App.post(url).then(res => {
  306 + t.leftList = res;
  307 + t.rightList = res[0].children;
  308 + t.isLeft = res[0].id;
  309 + t.rightList.forEach(el => {
  310 + el.isChoice = false;
  311 + });
  312 + });
  313 + },
  314 + // 左侧列表选中
  315 + changeLeft(item, index) {
  316 + this.isLeft = item.id;
  317 + this.rightList = item.children;
  318 + },
  319 + // 右侧列表选中
  320 + changeRight(item, index) {
  321 + let arr = [];
  322 + item.isChoice = !item.isChoice;
  323 + this.leftList.forEach(lel=>{
  324 + // 找出已选择的二级分类
  325 + lel.children.forEach(rel=>{
  326 + if(rel.isChoice == true){
  327 + arr.push(rel);
  328 + }
  329 + })
  330 + })
  331 + // 根据后台返回的可选择类型数量选择
  332 + if (arr.length > this.category_num) {
  333 + // 删除超出可选数量的最后一位
  334 + let end = arr.pop();
  335 + end.isChoice = false;
  336 + uni.showToast({
  337 + title:"已超出可选分类数量",
  338 + icon:"none"
  339 + })
  340 + return false
  341 + }
  342 + arr.forEach(el => {
  343 + this.category_ids.push(el.id);
  344 + });
  345 + // 去重
  346 + this.category_ids = [...new Set(this.category_ids)];
  347 + // 回显选中的分类
  348 + this.$forceUpdate();
  349 + },
  350 + // 提交名片
  351 + submitCard() {
  352 + if(!this.isClick){
  353 + let t = this;
  354 + t.isClick = true
  355 + let url = '/api/goods/publish_card';
  356 + let params = {
  357 + front_image: t.front_image,
  358 + reverse_image: t.reverse_image,
  359 + company_name: t.company_name,
  360 + brief: t.brief,
  361 + brief_images: t.brief_images.toString(),
  362 + scope: t.scope,
  363 + scope_images: t.scope_images.toString(),
  364 + name: t.name,
  365 + phone: t.phone,
  366 + site: t.site,
  367 + mobile: t.mobile,
  368 + fax: t.fax,
  369 + qq: t.qq,
  370 + wechat: t.wechat,
  371 + wechat_image: t.weichat_image,
  372 + category_ids: t.category_ids.toString()
  373 + };
  374 + if (t.front_image) {
  375 + if (t.company_name) {
  376 + if (t.brief) {
  377 + if (t.scope) {
  378 + if (t.name) {
  379 + App.post(url, params).then(res => {
  380 + uni.showToast({
  381 + title: '发布成功',
  382 + icon: 'success',
  383 + duration: 1000
  384 + });
  385 + setTimeout(function() {
  386 + if(t.isVip == 2){
  387 + t.isHide = true;
  388 + }else{
  389 + uni.navigateBack({
  390 + delta: 1
  391 + });
  392 + }
  393 + t.isClick = false
  394 + }, 1000);
  395 + });
  396 + } else {
  397 + uni.showToast({
  398 + title: '请输入联系人姓名',
  399 + icon: 'none'
  400 + });
  401 + t.isClick = false
  402 + }
  403 + } else {
  404 + uni.showToast({
  405 + title: '请输入经营范围',
  406 + icon: 'none'
  407 + });
  408 + t.isClick = false
  409 + }
  410 + } else {
  411 + uni.showToast({
  412 + title: '请输入公司简介',
  413 + icon: 'none'
  414 + });
  415 + t.isClick = false
  416 + }
  417 + } else {
  418 + uni.showToast({
  419 + title: '请填写公司名称',
  420 + icon: 'none'
  421 + });
  422 + t.isClick = false
  423 + }
  424 + } else {
  425 + uni.showToast({
  426 + title: '请上传正面图片',
  427 + icon: 'none'
  428 + });
  429 + t.isClick = false
  430 + }
  431 + }
  432 +
  433 + },
  434 + // 关闭弹窗
  435 + closeDialog() {
  436 + uni.navigateBack({
  437 + delta: 1
  438 + });
  439 + },
  440 + // 立即获取vip
  441 + getNow() {
  442 + uni.redirectTo({
  443 + url: '/pages/vip/myVip'
  444 + });
  445 + }
  446 + },
  447 + onLoad() {
  448 + this.category_num = uni.getStorageSync('category_num');
  449 + this.isVip = uni.getStorageSync("is_vip");
  450 + this.getType();
  451 +
  452 + }
  453 +};
  454 +</script>
  455 +
  456 +<style>
  457 +@import url('../../style/addCard');
  458 +</style>
  1 +<template>
  2 + <view class="card_wrap">
  3 + <!-- 无名片 -->
  4 + <view class="layer_center no_card" v-if="!isHave">
  5 + <view class="no_card_pic">
  6 + <image src="../../static/no_card.png" mode=""></image>
  7 + </view>
  8 + <view class="add_card">
  9 + <view class="add_card_btn" @click="addCard()">
  10 + 发布我的名片
  11 + </view>
  12 + </view>
  13 + </view>
  14 + <!-- 有名片 -->
  15 + <view class="content" v-else>
  16 + <view class="detail_top">
  17 + <!-- 公司名称 -->
  18 + <view class="company_name">{{cardDetail.company_name}}</view>
  19 + <!-- 名片正反面 -->
  20 + <view>
  21 + <image class="card_pic" :src="cardDetail.front_image" mode=""></image>
  22 + <view class="card_tips">名片正面</view>
  23 + </view>
  24 + <view>
  25 + <image class="card_pic" :src="cardDetail.reverse_image" mode=""></image>
  26 + <view class="card_tips">名片反面</view>
  27 + </view>
  28 + </view>
  29 + <!-- 公司简介 -->
  30 + <view class="company_intro">
  31 + <view class="company_title_wrap"><view class="company_title">公司简介</view></view>
  32 + <view class="company_detail">
  33 + <view class="company_detail_box">
  34 + <view class="">
  35 + {{cardDetail.brief}}
  36 + </view>
  37 + <view class="company_pic_wrap flex_wrap_no">
  38 + <view class="company_pic_single" @click="showImg(item)" v-for="(item, index) in cardDetail.brief_images" :key="index"><image :src="item" mode=""></image></view>
  39 + </view>
  40 + </view>
  41 + </view>
  42 + </view>
  43 + <!-- 经营范围 -->
  44 + <view class="company_intro">
  45 + <view class="company_title_wrap"><view class="company_title">经营范围</view></view>
  46 + <view class="company_detail">
  47 + <view class="company_detail_box">
  48 + <view class="">
  49 + {{cardDetail.scope}}
  50 + </view>
  51 + <view class="company_pic_wrap flex_wrap_no">
  52 + <view class="company_pic_single" @click="showImg(item)" v-for="(item, index) in cardDetail.scope_images" :key="index"><image :src="item" mode=""></image></view>
  53 + </view>
  54 + <!-- 刷新名片 -->
  55 + <view class="refresh_card flex_column_nojustify" @click="refreshCard()">
  56 + <image class="refresh_icon" src="../../static/refresh.png" mode=""></image>
  57 + <view class="refresh_tips">刷新名片</view>
  58 + </view>
  59 + </view>
  60 + </view>
  61 + </view>
  62 + <!-- 联系方式 -->
  63 + <view class="company_intro">
  64 + <view class="company_title_wrap"><view class="company_title">联系方式</view></view>
  65 + <!-- 地址 -->
  66 + <view class="contact_code">
  67 + <view class="layer_nobetween">
  68 + <!-- 二维码 -->
  69 + <view class="qr_code" @click="showImg(cardDetail.wechat_image)"><image :src="cardDetail.wechat_image" mode=""></image></view>
  70 + <!-- 姓名 地址 -->
  71 + <view class="contact_r flex_star_between">
  72 + <view class="">联系人:{{cardDetail.name}}</view>
  73 + <view class="" @click="callPhone()" v-if="cardDetail.phone">电话:{{cardDetail.phone}}</view>
  74 + <view class="" v-if="cardDetail.site">地址:{{cardDetail.site}}</view>
  75 + </view>
  76 + </view>
  77 + </view>
  78 + <!-- 各种联系方式 -->
  79 + <view class="contact_single layer_between" v-if="cardDetail.fax">
  80 + <view class="layer_between">
  81 + <image class="contact_icon" src="../../static/phone.png" mode=""></image>
  82 + 传真
  83 + </view>
  84 + <view class="" @click="copyEmail()">{{cardDetail.fax}}</view>
  85 + </view>
  86 + <view class="contact_single layer_between" v-if="cardDetail.mobile">
  87 + <view class="layer_between">
  88 + <image class="contact_icon" src="../../static/tel.png" mode=""></image>
  89 + 手机号
  90 + </view>
  91 + <view class="" @click="callTel()">{{cardDetail.mobile}}</view>
  92 + </view>
  93 + <view class="contact_single layer_between" v-if="cardDetail.qq">
  94 + <view class="layer_between">
  95 + <image class="contact_icon" src="../../static/qq.png" mode=""></image>
  96 + QQ
  97 + </view>
  98 + <view class="" @click="copyQQ()">{{cardDetail.qq}}</view>
  99 + </view>
  100 + <view class="contact_single no_bottom layer_between" v-if="cardDetail.wechat">
  101 + <view class="layer_between">
  102 + <image class="contact_icon" src="../../static/weixin.png" mode=""></image>
  103 + 微信
  104 + </view>
  105 + <view class="" @click="copyWx()">{{cardDetail.wechat}}</view>
  106 + </view>
  107 + </view>
  108 + <!-- 图片放大 -->
  109 + <view class="tx_mask" v-if="isShowImg" @click="closDialog()"></view>
  110 + <view class="mask_content" v-if="isShowImg" @click="closDialog()" @longpress="saveImg()">
  111 + <image :src="img" mode="widthFix"></image>
  112 + </view>
  113 + <!-- 编辑名片 -->
  114 + <view class="layer_between editor_btn">
  115 + <view class="refresh_time">
  116 + 上次刷新时间:{{cardDetail.refresh_time}}
  117 + </view>
  118 + <view class="editor_card" @click="toEditor()">编辑我的名片</view>
  119 + </view>
  120 + </view>
  121 + </view>
  122 +</template>
  123 +
  124 +<script>
  125 + import App from "../../App.vue";
  126 + export default {
  127 + data() {
  128 + return {
  129 + // 是否有名片
  130 + isHave:false,
  131 + // 我的名片详情
  132 + cardDetail:"",
  133 + token:"",
  134 + // 图片放大
  135 + isShowImg:false,
  136 + img:"",
  137 + }
  138 + },
  139 + methods: {
  140 + // 图片放大
  141 + showImg(img){
  142 + console.log(111)
  143 + this.isShowImg = true
  144 + this.img = img
  145 + },
  146 + closDialog(){
  147 + this.isShowImg = false
  148 + },
  149 + saveImg(){
  150 + let t = this ;
  151 + uni.downloadFile({
  152 + url: t.img,
  153 + success: function(res) {
  154 + uni.saveImageToPhotosAlbum({
  155 + filePath: res.tempFilePath,
  156 + success: function() {
  157 + uni.showToast({
  158 + title: '保存成功',
  159 + icon: 'none',
  160 + duration: 1500
  161 + });
  162 + t.isShowImg = false
  163 + },
  164 + fail: function(err) {
  165 + if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || err.errMsg ===
  166 + "saveImageToPhotosAlbum:fail:auth denied") {
  167 + uni.showToast({
  168 + title: '需要您授权保存相册',
  169 + icon:none,
  170 + duration: 1500,
  171 + success: modalSuccess => {
  172 + uni.openSetting({
  173 + success(settingdata) {
  174 + if (settingdata.authSetting['scope.writePhotosAlbum']) {
  175 + uni.showToast({
  176 + title: '获取权限成功',
  177 + icon: 'none',
  178 + duration: 1500
  179 + });
  180 + } else {
  181 + uni.showToast({
  182 + title: '获取权限失败',
  183 + icon: 'none',
  184 + duration: 1500
  185 + });
  186 + }
  187 + },
  188 + fail(failData) {
  189 + console.log("failData", failData)
  190 + },
  191 + complete(finishData) {
  192 + console.log("finishData", finishData)
  193 + }
  194 + })
  195 + }
  196 + })
  197 + }
  198 + },
  199 + });
  200 + }
  201 + });
  202 + },
  203 + // 刷新名片
  204 + refreshCard(){
  205 + let url = "/api/goods/refresh";
  206 + App.post(url)
  207 + .then(res=>{
  208 + this.getMyCard()
  209 + })
  210 + },
  211 + // 发布我的名片
  212 + addCard() {
  213 + if(this.token){
  214 + uni.navigateTo({
  215 + url:"/pages/card/addCard"
  216 + })
  217 + }else{
  218 + uni.navigateTo({
  219 + url:"/pages/start/start"
  220 + })
  221 + }
  222 + },
  223 + // 获取我的名片详情
  224 + getMyCard(){
  225 + let url = "/api/goods/my_goods";
  226 + App.post(url)
  227 + .then(res=>{
  228 + this.cardDetail = res;
  229 + if(this.cardDetail){
  230 + this.isHave = true
  231 + }
  232 + })
  233 + },
  234 + // 去编辑页
  235 + toEditor(){
  236 + uni.navigateTo({
  237 + url:"/pages/card/editorCard"
  238 + })
  239 + },
  240 + // 拨打电话
  241 + callPhone(){
  242 + uni.makePhoneCall({
  243 + phoneNumber:this.cardDetail.mobile
  244 + })
  245 + },
  246 + // 拨打手机号
  247 + callTel(){
  248 + uni.makePhoneCall({
  249 + phoneNumber:this.cardDetail.mobile
  250 + })
  251 + },
  252 + // 复制传真号
  253 + copyEmail(){
  254 + uni.setClipboardData({
  255 + data: this.cardDetail.fax,
  256 + success: function () {
  257 + uni.showToast({
  258 + title:"复制成功",
  259 + icon:'success'
  260 + })
  261 + }
  262 + });
  263 + },
  264 + // 复制qq号
  265 + copyQQ(){
  266 + uni.setClipboardData({
  267 + data: this.cardDetail.qq,
  268 + success: function () {
  269 + uni.showToast({
  270 + title:"复制成功",
  271 + icon:'success'
  272 + })
  273 + }
  274 + });
  275 + },
  276 + // 复制微信号
  277 + copyWx(){
  278 + uni.setClipboardData({
  279 + data: this.cardDetail.wechat,
  280 + success: function () {
  281 + uni.showToast({
  282 + title:"复制成功",
  283 + icon:'success'
  284 + })
  285 + }
  286 + });
  287 + },
  288 + },
  289 + onShow() {
  290 + this.token = uni.getStorageSync("token");
  291 + // 获取我的名片详情
  292 + if(this.token){
  293 + this.getMyCard();
  294 + }
  295 + },
  296 + onLoad() {
  297 +
  298 + },
  299 + onShareAppMessage: function (res) {
  300 + var that = this;
  301 +
  302 +
  303 + // 来自页面内转发按钮
  304 + return {
  305 + title: '分享',
  306 + path: "/pages/card/card"
  307 +
  308 + }
  309 +
  310 + }
  311 + }
  312 +</script>
  313 +
  314 +<style>
  315 + @import url("../../style/card");
  316 + @import url('../../style/cardDetail');
  317 +</style>
  1 +<template>
  2 + <view class="add_card" :class="{ over_hide: isHide }">
  3 + <!-- 名片信息 -->
  4 + <view class="add_card_top">
  5 + <!-- 正反面 -->
  6 + <view class="add_card_single">
  7 + <view class="card_front flex_center" @click="uploadPositive()">
  8 + <view class="show_img" v-if="front_image"><image :src="front_image" mode="aspectFill"></image></view>
  9 + <view class="flex_center" v-else>
  10 + <view class="card_upload"><image src="../../static/add.png" mode=""></image></view>
  11 + <view class="card_tips">上传名片正面图片</view>
  12 + </view>
  13 + </view>
  14 + <view class="card_front flex_center" @click="uploadSide()">
  15 + <view class="show_img" v-if="reverse_image"><image :src="reverse_image" mode="aspectFill"></image></view>
  16 + <view class="flex_center" v-else>
  17 + <view class="card_upload"><image src="../../static/add.png" mode=""></image></view>
  18 + <view class="card_tips">上传名片背面图片</view>
  19 + </view>
  20 + </view>
  21 + <view class="upload_tips">建议名片尺寸为360*210像素 </view>
  22 + <view class="msg_single layer_between">
  23 + <view class="single_l">公司名称:</view>
  24 + <input class="single_r" type="text" v-model="company_name" placeholder="请输入公司名称" />
  25 + </view>
  26 + </view>
  27 + <!-- 公司简介 -->
  28 + <view class="add_card_single">
  29 + <view class="msg_single">
  30 + <view class="single_l">公司简介:</view>
  31 + <textarea v-model="brief" placeholder="请输入公司简介" />
  32 + <view class="layer_nostar flex_wrap_no">
  33 + <view class="wx_code" v-for="(item, index) in brief_images" :key="index">
  34 + <image :src="item" mode=""></image>
  35 + <image @click="deleteCompany(index)" class="cancle_icon" src="../../static/del_icon@2x.png" mode=""></image>
  36 + </view>
  37 + <view class="wx_code" @click="uploadCompay()"><image src="../../static/add_wx.png" mode=""></image></view>
  38 + </view>
  39 + </view>
  40 + </view>
  41 + <!-- 经营范围 -->
  42 + <view class="add_card_single">
  43 + <view class="msg_single">
  44 + <view class="single_l">经营范围:</view>
  45 + <textarea v-model="scope" placeholder="请输入经营范围" />
  46 + <view class="layer_nostar flex_wrap_no">
  47 + <view class="wx_code" v-for="(item, index) in scope_images" :key="index">
  48 + <image :src="item" mode=""></image>
  49 + <image @click="deleteScope(index)" class="cancle_icon" src="../../static/del_icon@2x.png" mode=""></image>
  50 + </view>
  51 + <view class="wx_code" @click="uploadBusiness()"><image src="../../static/add_wx.png" mode=""></image></view>
  52 + </view>
  53 + </view>
  54 + </view>
  55 + <!-- 各种联系方式 -->
  56 + <view class="add_card_single">
  57 + <view class="msg_single layer_between">
  58 + <view class="single_l">联系人:</view>
  59 + <input class="single_r" type="text" v-model="name" placeholder="请输入联系人" />
  60 + </view>
  61 + </view>
  62 + <view class="add_card_single">
  63 + <view class="msg_single layer_between">
  64 + <view class="single_l">地址:</view>
  65 + <input class="single_r" type="text" v-model="site" placeholder="请输入地址" />
  66 + </view>
  67 + </view>
  68 + <view class="add_card_single">
  69 + <view class="msg_single layer_between">
  70 + <view class="single_l">电话:</view>
  71 + <input class="single_r" type="text" v-model="phone" placeholder="请输入电话" />
  72 + </view>
  73 + </view>
  74 + <view class="add_card_single">
  75 + <view class="msg_single layer_between">
  76 + <view class="single_l">传真:</view>
  77 + <input class="single_r" type="text" v-model="fax" placeholder="请输入传真" />
  78 + </view>
  79 + </view>
  80 + <view class="add_card_single">
  81 + <view class="msg_single layer_between">
  82 + <view class="single_l">手机号:</view>
  83 + <input class="single_r" maxlength="11" type="text" v-model="mobile" placeholder="请输入手机号" />
  84 + </view>
  85 + </view>
  86 + <view class="add_card_single">
  87 + <view class="msg_single layer_between">
  88 + <view class="single_l">QQ:</view>
  89 + <input class="single_r" type="text" v-model="qq" placeholder="请输入QQ号" />
  90 + </view>
  91 + </view>
  92 + <view class="add_card_single">
  93 + <view class="msg_single layer_between">
  94 + <view class="single_l">微信:</view>
  95 + <input class="single_r" type="text" v-model="wechat" placeholder="请输入微信" />
  96 + </view>
  97 + </view>
  98 + <view class="add_card_single">
  99 + <view class="msg_single">
  100 + <view class="single_l">微信二维码:</view>
  101 + <view class="layer_nostar" @click="uploadCode()">
  102 + <view class="wx_img" v-if="weichat_image"><image :src="weichat_image" mode=""></image></view>
  103 + <view class="wx_code" v-else><image src="../../static/add_wx.png" mode=""></image></view>
  104 + </view>
  105 + </view>
  106 + </view>
  107 + </view>
  108 + <!-- 名片分类 -->
  109 + <view class="add_card_classify">
  110 + <view class="classify_title">
  111 + 名片分类:
  112 + <text>(可选择{{ category_num }}个名片分类)</text>
  113 + </view>
  114 + <view class="classify_tips">想要增加更多分类,请提交名片升级成VIP后到会员中心增加</view>
  115 + <!-- 轴承列表 -->
  116 + <view class="bearing_classify layer_nostar">
  117 + <!-- 左侧类目 -->
  118 + <view class="bearing_l">
  119 + <view class="bear_l_box flex_column_center">
  120 + <view
  121 + class="bear_l_single flex_warp"
  122 + :class="{ bear_l_active: isLeft == item.id }"
  123 + v-for="(item, index) in leftList"
  124 + :key="index"
  125 + @click="changeLeft(item, index)"
  126 + >
  127 + <view class="bear_l_child">{{ item.name }}</view>
  128 + </view>
  129 + </view>
  130 + </view>
  131 + <!-- 右侧具体分类 -->
  132 + <view class="bearing_r">
  133 + <view class="bear_r_box">
  134 + <view class="bear_r_single" :class="{ bear_r_active: item.isChoice }" v-for="(item, index) in rightList" :key="index" @click="changeRight(item, index)">
  135 + {{ item.name }}
  136 + </view>
  137 + </view>
  138 + </view>
  139 + </view>
  140 + </view>
  141 + <!-- 提交名片 -->
  142 + <view class="submit_btn" @click="submitCard()">提交名片</view>
  143 + <!-- 提交弹窗 -->
  144 + <view class="tx_mask" v-if="isHide" @click="closeDialog()"></view>
  145 + <view class="mask_content" v-if="isHide">
  146 + <view class="mask_top">成为VIP会员,其他用户可以搜索到您的名片</view>
  147 + <view class="mask_bottom" @click="getNow()">立即获取</view>
  148 + </view>
  149 + </view>
  150 +</template>
  151 +
  152 +<script>
  153 +import App from '../../App.vue';
  154 +export default {
  155 + data() {
  156 + return {
  157 + front_image: '', //正面图片
  158 + reverse_image: '', //反面图片
  159 + company_name: '', //公司名称
  160 + brief: '', //公司简介
  161 + brief_images: [], //公司简介图片
  162 + scope: '', //经营范围
  163 + scope_images: [], //经营范围图片
  164 + name: '', //联系人
  165 + phone: '', //电话
  166 + site: '', //地址
  167 + mobile: '', //手机号
  168 + fax: '', //传真
  169 + qq: '', // QQ
  170 + wechat: '', //微信
  171 + weichat_image: '', //微信二维码
  172 + category_ids: [], //分类ID
  173 + category_num: '', //可选分类个数
  174 + // 轴承列表
  175 + // 左侧
  176 + leftList: [],
  177 + isLeft: 0,
  178 + // 右侧
  179 + rightList: [],
  180 + isRight: 0,
  181 + // 弹窗
  182 + isHide: false,
  183 + // 是否为vip 1:是 2:否
  184 + isVip: '',
  185 + file: '',
  186 + // 防连点
  187 + isClick: false,
  188 + imgBrief: [], //公司简介上传数量
  189 + imgScope: []
  190 + };
  191 + },
  192 + methods: {
  193 + // 上传正面图片
  194 + uploadPositive() {
  195 + let t = this;
  196 + uni.chooseImage({
  197 + count: 1, //默认9
  198 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  199 + sourceType: ['album'], //从相册选择
  200 + success: chooseImageRes => {
  201 + const tempFilePaths = chooseImageRes.tempFilePaths;
  202 + App.upload(tempFilePaths[0]).then(res => {
  203 + this.front_image = res.url;
  204 + });
  205 + }
  206 + });
  207 + },
  208 + // 上传反面图片
  209 + uploadSide() {
  210 + let t = this;
  211 + uni.chooseImage({
  212 + count: 1, //默认9
  213 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  214 + sourceType: ['album'], //从相册选择
  215 + success: chooseImageRes => {
  216 + const tempFilePaths = chooseImageRes.tempFilePaths;
  217 + t.file = tempFilePaths;
  218 + App.upload(tempFilePaths[0]).then(res => {
  219 + this.reverse_image = res.url;
  220 + });
  221 + }
  222 + });
  223 + },
  224 + // 上传公司简介图片
  225 + uploadCompay() {
  226 + let t = this;
  227 + uni.chooseImage({
  228 + count: 3, //默认9
  229 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  230 + sourceType: ['album'], //从相册选择
  231 + success: chooseImageRes => {
  232 + const tempFilePaths = chooseImageRes.tempFilePaths;
  233 + t.imgBrief = [...t.imgBrief,...tempFilePaths]
  234 + if(t.imgBrief.length>3){
  235 + uni.showToast({
  236 + title: '图片总数超过3张',
  237 + icon: 'none'
  238 + });
  239 + tempFilePaths.forEach(el=>{
  240 + t.imgBrief.forEach((ele,i)=>{
  241 + if(el == ele){
  242 + t.imgBrief.splice(i,1)
  243 + }
  244 + })
  245 + })
  246 + return false;
  247 + }
  248 + tempFilePaths.forEach(el => {
  249 + App.upload(el).then(res => {
  250 + t.brief_images.push(res.url);
  251 + });
  252 + });
  253 + }
  254 + });
  255 + },
  256 +
  257 + // 上传经营范围图片
  258 + uploadBusiness() {
  259 + let t = this;
  260 + uni.chooseImage({
  261 + count: 3, //默认9
  262 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  263 + sourceType: ['album'], //从相册选择
  264 + success: chooseImageRes => {
  265 + const tempFilePaths = chooseImageRes.tempFilePaths;
  266 + t.imgScope = [...t.imgScope, ...tempFilePaths];
  267 + if (t.imgScope.length > 3) {
  268 + uni.showToast({
  269 + title: '图片总数超过3张',
  270 + icon: 'none'
  271 + });
  272 + tempFilePaths.forEach(el=>{
  273 + t.imgScope.forEach((ele,i)=>{
  274 + if(el == ele){
  275 + t.imgScope.splice(i,1)
  276 + }
  277 + })
  278 + })
  279 + return false;
  280 + }
  281 +
  282 + tempFilePaths.forEach(el => {
  283 + App.upload(el).then(res => {
  284 + t.scope_images.push(res.url);
  285 + });
  286 + });
  287 + }
  288 + });
  289 + },
  290 + // 删除公司简介图片
  291 + deleteCompany(index) {
  292 +
  293 + this.imgBrief.splice(index, 1);
  294 + this.brief_images.splice(index, 1);
  295 + console.log(this.imgBrief,this.brief_images)
  296 + },
  297 + // 删除经营范围图片
  298 + deleteScope(index) {
  299 + this.imgScope.splice(index, 1);
  300 + this.scope_images.splice(index, 1);
  301 + },
  302 + // 上传二维码
  303 + uploadCode() {
  304 + let t = this;
  305 + uni.chooseImage({
  306 + count: 1, //默认9
  307 + sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  308 + sourceType: ['album'], //从相册选择
  309 + success: chooseImageRes => {
  310 + const tempFilePaths = chooseImageRes.tempFilePaths;
  311 + App.upload(tempFilePaths[0]).then(res => {
  312 + this.weichat_image = res.url;
  313 + });
  314 + }
  315 + });
  316 + },
  317 + // 首页分类数据 左侧一级分类
  318 + getType() {
  319 + let t = this;
  320 + t.leftList = [];
  321 + t.rightList = [];
  322 + let url = '/api/category/get_category_one';
  323 + App.post(url).then(res => {
  324 + t.leftList = res;
  325 + t.rightList.forEach(el => {
  326 + el.isChoice = false;
  327 + });
  328 + res.forEach(el => {
  329 + // 找出已选择的二级分类
  330 + el.children.forEach(ele => {
  331 + t.category_ids.forEach(eleId => {
  332 + // 根据后台返回的分类id找到对应的分类
  333 + if (eleId == ele.id) {
  334 + ele.isChoice = true;
  335 + // 一级分类
  336 + t.isLeft = el.id;
  337 + // 二级分类
  338 + t.rightList = el.children;
  339 + }
  340 + });
  341 + });
  342 + });
  343 + });
  344 + },
  345 + // 左侧列表选中
  346 + changeLeft(item, index) {
  347 + this.isLeft = item.id;
  348 + this.rightList = item.children;
  349 + },
  350 + // 右侧列表选中
  351 + changeRight(item, index) {
  352 + this.category_ids = [];
  353 + let arr = [];
  354 + item.isChoice = !item.isChoice;
  355 + this.leftList.forEach(lel => {
  356 + // 找出已选择的二级分类
  357 + lel.children.forEach(rel => {
  358 + if (rel.isChoice == true) {
  359 + arr.push(rel);
  360 + }
  361 + });
  362 + });
  363 + // 根据后台返回的可选择类型数量选择
  364 + if (arr.length > this.category_num) {
  365 + // 删除超出可选数量的最后一位
  366 + let end = arr.pop();
  367 + end.isChoice = false;
  368 + uni.showToast({
  369 + title: '已超出可选分类数量',
  370 + icon: 'none'
  371 + });
  372 + return false;
  373 + }
  374 + arr.forEach(el => {
  375 + this.category_ids.push(el.id);
  376 + });
  377 + // 去重
  378 + this.category_ids = [...new Set(this.category_ids)];
  379 + // 回显选中的分类
  380 + this.$forceUpdate();
  381 + },
  382 + // 提交名片
  383 + submitCard() {
  384 + if (!this.isClick) {
  385 + let t = this;
  386 +
  387 + t.isClick = true;
  388 + let url = '/api/goods/publish_card';
  389 + let briefArr = '';
  390 + if (t.brief_images) {
  391 + briefArr = t.brief_images.toString();
  392 + }
  393 + let scopeArr = '';
  394 + if (t.scope_images) {
  395 + scopeArr = t.scope_images.toString();
  396 + }
  397 + let cateArr = '';
  398 + if (t.category_ids) {
  399 + cateArr = t.category_ids.toString();
  400 + }
  401 + let params = {
  402 + front_image: t.front_image,
  403 + reverse_image: t.reverse_image,
  404 + company_name: t.company_name,
  405 + brief: t.brief,
  406 + brief_images: briefArr,
  407 + scope: t.scope,
  408 + scope_images: scopeArr,
  409 + name: t.name,
  410 + phone: t.phone,
  411 + site: t.site,
  412 + mobile: t.mobile,
  413 + fax: t.fax,
  414 + qq: t.qq,
  415 + wechat: t.wechat,
  416 + wechat_image: t.weichat_image,
  417 + category_ids: cateArr
  418 + };
  419 + if (t.front_image) {
  420 + if (t.company_name) {
  421 + if (t.brief) {
  422 + if (t.scope) {
  423 + if (t.name) {
  424 + App.post(url, params).then(res => {
  425 + uni.showToast({
  426 + title: '编辑成功',
  427 + icon: 'success',
  428 + duration: 1000
  429 + });
  430 + setTimeout(function() {
  431 + if (t.isVip == 2) {
  432 + t.isHide = true;
  433 + } else {
  434 + uni.navigateBack({
  435 + delta: 1
  436 + });
  437 + }
  438 + t.isClick = false;
  439 + }, 1000);
  440 + });
  441 + } else {
  442 + uni.showToast({
  443 + title: '请输入联系人姓名',
  444 + icon: 'none'
  445 + });
  446 + t.isClick = false;
  447 + }
  448 + } else {
  449 + uni.showToast({
  450 + title: '请输入经营范围',
  451 + icon: 'none'
  452 + });
  453 + t.isClick = false;
  454 + }
  455 + } else {
  456 + uni.showToast({
  457 + title: '请输入公司简介',
  458 + icon: 'none'
  459 + });
  460 + t.isClick = false;
  461 + }
  462 + } else {
  463 + uni.showToast({
  464 + title: '请填写公司名称',
  465 + icon: 'none'
  466 + });
  467 + t.isClick = false;
  468 + }
  469 + } else {
  470 + uni.showToast({
  471 + title: '请上传正面图片',
  472 + icon: 'none'
  473 + });
  474 + t.isClick = false;
  475 + }
  476 + }
  477 + },
  478 + // 关闭弹窗
  479 + closeDialog() {
  480 + uni.navigateBack({
  481 + delta: 1
  482 + });
  483 + },
  484 + // 立即获取vip
  485 + getNow() {
  486 + uni.redirectTo({
  487 + url: '/pages/vip/myVip'
  488 + });
  489 + },
  490 + // 获取我的名片详情
  491 + getMyCard() {
  492 + let t = this;
  493 + let url = '/api/goods/my_goods';
  494 + App.post(url).then(res => {
  495 + t.getType();
  496 + t.front_image = res.front_image;
  497 + t.reverse_image = res.reverse_image;
  498 + t.company_name = res.company_name;
  499 + t.brief = res.brief;
  500 + if (res.brief_images) {
  501 + t.imgBrief = res.brief_images;
  502 + t.brief_images = res.brief_images;
  503 + }
  504 + t.scope = res.scope;
  505 + if (res.scope_images) {
  506 + t.imgScope = res.scope_images;
  507 + t.scope_images = res.scope_images;
  508 + }
  509 + t.name = res.name;
  510 + t.phone = res.phone;
  511 + t.site = res.site;
  512 + t.mobile = res.mobile;
  513 + t.fax = res.fax;
  514 + t.qq = res.qq;
  515 + t.wechat = res.wechat;
  516 + t.weichat_image = res.wechat_image;
  517 + res.category_ids.forEach(el => {
  518 + if (el) {
  519 + t.category_ids.push(el);
  520 + }
  521 + });
  522 + });
  523 + }
  524 + },
  525 + onLoad() {
  526 +
  527 + // 获取我的名片详情
  528 + this.getMyCard();
  529 + },
  530 + onShow() {
  531 + this.category_num = uni.getStorageSync('category_num');
  532 +
  533 + }
  534 +};
  535 +</script>
  536 +
  537 +<style>
  538 +@import url('../../style/addCard');
  539 +</style>
  1 +<template>
  2 + <view class="content">
  3 + <!-- 轴承列表 -->
  4 + <view class="bearing_classify layer_nostar">
  5 + <!-- 左侧类目 -->
  6 + <view class="bearing_l">
  7 + <view class="bear_l_box flex_column_center">
  8 + <view class="bear_l_single flex_warp" :class="{ bear_l_active: isLeft == item.id }" v-for="(item, index) in leftList" :key="index" @click="changeLeft(item,index)">
  9 + <view class="bear_l_child">{{ item.name }}</view>
  10 + </view>
  11 + </view>
  12 + </view>
  13 + <!-- 右侧具体分类 -->
  14 + <view class="bearing_r">
  15 + <view class="bear_r_box">
  16 + <view class="bear_r_single" :class="{bear_r_active:isRight == item.id}" v-for="(item, index) in rightList" :key="index" @click="changeRight(item,index)">{{ item.name }}</view>
  17 + </view>
  18 + </view>
  19 + </view>
  20 + <!-- 收藏名片 -->
  21 + <view class="hot_search">
  22 + <!-- 名片列表 -->
  23 + <view class="hot_card_wrap flex_wrap_between" v-if="cardList.length>0">
  24 + <view class="card_single" v-for="(item,index) in cardList" :key="index" @click="toDetail(item)">
  25 + <image :src="item.front_image" mode=""></image>
  26 + </view>
  27 + </view>
  28 + <!-- 暂无名片 -->
  29 + <view class="hot_card_wrap" v-else>暂无收藏</view>
  30 + <!-- 分页 -->
  31 + <view class="card_pagation layer_between">
  32 + <view class="prev_page" :class="{next_page:pageNum>1}" @click="prevPage()">上一页</view>
  33 + <view class="layer_between jump_page">
  34 + 跳转到
  35 + <input type="text" @confirm="jumpPage()" v-model="pageNum" />
  36 +
  37 + </view>
  38 + <view class="next_page" :class="{prev:pageNum >= totalPage}" @click="nextPage()">下一页</view>
  39 + <view class="total_page">共{{totalPage}}页</view>
  40 + </view>
  41 + </view>
  42 + </view>
  43 +</template>
  44 +
  45 +<script>
  46 + import App from "../../App.vue";
  47 +export default {
  48 + data() {
  49 + return {
  50 + // 搜索
  51 + keyword:"",
  52 + // 轮播图
  53 + swiperList:[],
  54 + // 轴承列表
  55 + // 左侧
  56 + leftList: [],
  57 + isLeft: 0,
  58 + // 右侧
  59 + rightList: [],
  60 + isRight: "",
  61 + // 名片列表
  62 + cardList:[],
  63 + // 分页
  64 + pageNum:1,
  65 + // 总页数
  66 + totalPage:"",
  67 + };
  68 + },
  69 +
  70 + methods: {
  71 + // 轮播图
  72 + getSwiper(){
  73 + let t = this;
  74 + let url = "/api/slide/get_slide";
  75 + App.post(url)
  76 + .then(res=>{
  77 + this.swiperList = res.data;
  78 + })
  79 + },
  80 + // 首页分类数据 左侧一级分类
  81 + getType(){
  82 + let t = this;
  83 + t.leftList = [];
  84 + t.rightList = [];
  85 + let url = "/api/collect/get_category_one";
  86 + App.post(url)
  87 + .then(res=>{
  88 + t.leftList = res;
  89 + t.rightList = res[0].children;
  90 + t.isLeft = res[0].id;
  91 + })
  92 + },
  93 + // 左侧列表选中
  94 + changeLeft(item,index) {
  95 + this.isLeft = item.id;
  96 + this.rightList = item.children;
  97 +
  98 + },
  99 + // 右侧列表选中
  100 + changeRight(item,index){
  101 + this.isRight = item.id;
  102 + this.getCardList();
  103 + },
  104 + // 获取收藏列表
  105 + getCardList(){
  106 + let t = this;
  107 + let url = "/api/collect/collect_list";
  108 + let params = {
  109 + category_id:t.isRight,
  110 + page:t.pageNum
  111 + };
  112 + App.post(url,params)
  113 + .then(res=>{
  114 + t.totalPage = res.page_sum;
  115 + t.cardList = res.list;
  116 + })
  117 + },
  118 + // 名片详情
  119 + toDetail(item){
  120 + uni.navigateTo({
  121 + url:"/pages/index/cardDetail?id="+item.id
  122 + })
  123 + },
  124 + // 搜索 去名片列表
  125 + toSearch(){
  126 + uni.navigateTo({
  127 + url:"/pages/index/search?keyword="+this.keyword
  128 + })
  129 + },
  130 + // 上一页
  131 + prevPage(){
  132 + if(this.pageNum <=1 )
  133 + return false;
  134 + this.pageNum --;
  135 + this.getCardList()
  136 + },
  137 + // 下一页
  138 + nextPage(){
  139 + if(this.pageNum == this.totalPage){
  140 + return false
  141 + }
  142 + this.pageNum ++;
  143 + this.getCardList()
  144 + },
  145 + // 跳转到某一页
  146 + jumpPage(){
  147 + if(this.pageNum>this.totalPage)
  148 + this.pageNum = this.totalPage;
  149 + this.getCardList()
  150 + },
  151 + },
  152 + onLoad() {
  153 +
  154 + },
  155 + onShow() {
  156 + // 首页分类数据
  157 + this.getType();
  158 + // 名片列表数据
  159 + this.getCardList();
  160 + },
  161 +
  162 +};
  163 +</script>
  164 +
  165 +<style>
  166 +@import url('../../style/index');
  167 +.hot_card_wrap{
  168 + border-top: none;
  169 + text-align: center;
  170 +}
  171 +.bearing_classify{
  172 + border-top: 1upx solid #eee;
  173 +}
  174 +</style>
  1 +<template>
  2 + <view class="content">
  3 + <view class="detail_top">
  4 + <!-- 公司名称 -->
  5 + <view class="company_name">{{ cardDetail.company_name }}</view>
  6 + <!-- 名片正反面 -->
  7 + <view>
  8 + <image class="card_pic" :src="cardDetail.front_image" mode=""></image>
  9 + <view class="card_tips">名片正面</view>
  10 + </view>
  11 + <view>
  12 + <image class="card_pic" :src="cardDetail.reverse_image" mode=""></image>
  13 + <view class="card_tips">名片反面</view>
  14 + </view>
  15 + </view>
  16 + <!-- 公司简介 -->
  17 + <view class="company_intro">
  18 + <view class="company_title_wrap"><view class="company_title">公司简介</view></view>
  19 + <view class="company_detail">
  20 + <view class="company_detail_box">
  21 + <view class="">{{ cardDetail.brief }}</view>
  22 + <view class="company_pic_wrap flex_wrap_no">
  23 + <view class="company_pic_single" @click="showImg(item)" v-for="(item, index) in cardDetail.brief_images" :key="index"><image :src="item" mode=""></image></view>
  24 + </view>
  25 + </view>
  26 + </view>
  27 + </view>
  28 + <!-- 经营范围 -->
  29 + <view class="company_intro">
  30 + <view class="company_title_wrap"><view class="company_title">经营范围</view></view>
  31 + <view class="company_detail">
  32 + <view class="company_detail_box">
  33 + <view class="">{{ cardDetail.scope }}</view>
  34 + <view class="company_pic_wrap flex_wrap_no">
  35 + <view class="company_pic_single" @click="showImg(item)" v-for="(item, index) in cardDetail.scope_images" :key="index"><image :src="item" mode=""></image></view>
  36 + </view>
  37 + </view>
  38 + </view>
  39 + </view>
  40 + <!-- 联系方式 -->
  41 + <view class="company_intro">
  42 + <view class="company_title_wrap"><view class="company_title">联系方式</view></view>
  43 + <!-- 地址 -->
  44 + <view class="contact_code">
  45 + <view class="layer_nobetween">
  46 + <!-- 二维码 -->
  47 + <view class="qr_code" @click="showImg(cardDetail.wechat_image)"><image :src="cardDetail.wechat_image" mode=""></image></view>
  48 + <!-- 姓名 地址 -->
  49 + <view class="contact_r flex_star_between">
  50 + <view class="">联系人:{{ cardDetail.name }}</view>
  51 + <view class="" v-if="cardDetail.phone">电话:{{ cardDetail.phone }}</view>
  52 + <view class="" v-if="cardDetail.site">地址:{{ cardDetail.site }}</view>
  53 + </view>
  54 + </view>
  55 + </view>
  56 + <!-- 各种联系方式 -->
  57 + <view class="contact_single layer_between" v-if="cardDetail.fax">
  58 + <view class="layer_between">
  59 + <image class="contact_icon" src="../../static/phone.png" mode=""></image>
  60 + 传真
  61 + </view>
  62 + <view class="" @click="copyFax()">{{ cardDetail.fax }}</view>
  63 + </view>
  64 + <view class="contact_single layer_between" v-if="cardDetail.mobile">
  65 + <view class="layer_between">
  66 + <image class="contact_icon" src="../../static/tel.png" mode=""></image>
  67 + 手机号
  68 + </view>
  69 + <view class="" @click="callUp()">{{ cardDetail.mobile }}</view>
  70 + </view>
  71 + <view class="contact_single layer_between" v-if="cardDetail.qq">
  72 + <view class="layer_between">
  73 + <image class="contact_icon" src="../../static/qq.png" mode=""></image>
  74 + QQ
  75 + </view>
  76 + <view class="" @click="copyQQ()">{{ cardDetail.qq }}</view>
  77 + </view>
  78 + <view class="contact_single no_bottom layer_between" v-if="cardDetail.wechat">
  79 + <view class="layer_between">
  80 + <image class="contact_icon" src="../../static/weixin.png" mode=""></image>
  81 + 微信
  82 + </view>
  83 + <view class="" @click="copyWx()">{{ cardDetail.wechat }}</view>
  84 + </view>
  85 + </view>
  86 + <!-- 图片放大 -->
  87 + <view class="tx_mask" v-if="isShowImg" @click="closDialog()"></view>
  88 + <view class="mask_content" v-if="isShowImg" @click="closDialog()" @longpress="saveImg()">
  89 + <image :src="img" mode="widthFix"></image>
  90 + </view>
  91 + <!-- 收藏按钮 -->
  92 + <view class="collect_btn" @click="collectCard()">{{cardDetail.is_collect == 1?"取消收藏":"收藏名片"}}</view>
  93 + </view>
  94 +</template>
  95 +
  96 +<script>
  97 +import App from '../../App.vue';
  98 +export default {
  99 + data() {
  100 + return {
  101 + id: '',
  102 + imgList: [],
  103 + cardDetail: '',
  104 + token: '',
  105 + // 图片放大
  106 + isShowImg:false,
  107 + img:"",
  108 + };
  109 + },
  110 + methods: {
  111 + // 图片放大
  112 + showImg(img){
  113 +
  114 + this.isShowImg = true
  115 + this.img = img;
  116 +
  117 + },
  118 + saveImg(){
  119 + let t = this ;
  120 + uni.downloadFile({
  121 + url: t.img,
  122 + success: function(res) {
  123 + uni.saveImageToPhotosAlbum({
  124 + filePath: res.tempFilePath,
  125 + success: function() {
  126 + uni.showToast({
  127 + title: '保存成功',
  128 + icon: 'none',
  129 + duration: 1500
  130 + });
  131 + t.isShowImg = false
  132 + },
  133 + fail: function(err) {
  134 + if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || err.errMsg ===
  135 + "saveImageToPhotosAlbum:fail:auth denied") {
  136 + uni.showToast({
  137 + title: '需要您授权保存相册',
  138 + icon:none,
  139 + duration: 1500,
  140 + success: modalSuccess => {
  141 + uni.openSetting({
  142 + success(settingdata) {
  143 + if (settingdata.authSetting['scope.writePhotosAlbum']) {
  144 + uni.showToast({
  145 + title: '获取权限成功',
  146 + icon: 'none',
  147 + duration: 1500
  148 + });
  149 + } else {
  150 + uni.showToast({
  151 + title: '获取权限失败',
  152 + icon: 'none',
  153 + duration: 1500
  154 + });
  155 + }
  156 + },
  157 + fail(failData) {
  158 + console.log("failData", failData)
  159 + },
  160 + complete(finishData) {
  161 + console.log("finishData", finishData)
  162 + }
  163 + })
  164 + }
  165 + })
  166 + }
  167 + },
  168 + });
  169 + }
  170 + });
  171 + },
  172 + closDialog(){
  173 + this.isShowImg = false
  174 + },
  175 + // 名片详情
  176 + getCarDetail() {
  177 + let t = this;
  178 + let url = '/api/goods/goods_detail';
  179 + let params = {
  180 + goods_id: this.id
  181 + };
  182 + App.post(url, params).then(res => {
  183 + this.cardDetail = res;
  184 + });
  185 + },
  186 + // 复制传真
  187 + copyFax() {
  188 + uni.setClipboardData({
  189 + data: this.cardDetail.fax,
  190 + success: function() {
  191 + uni.showToast({
  192 + title: '复制成功',
  193 + icon: 'success'
  194 + });
  195 + }
  196 + });
  197 + },
  198 + // 复制qq
  199 + copyQQ() {
  200 + uni.setClipboardData({
  201 + data: this.cardDetail.qq,
  202 + success: function() {
  203 + uni.showToast({
  204 + title: '复制成功',
  205 + icon: 'success'
  206 + });
  207 + }
  208 + });
  209 + },
  210 + // 复制微信
  211 + copyWx() {
  212 + uni.setClipboardData({
  213 + data: this.cardDetail.wechat,
  214 + success: function() {
  215 + uni.showToast({
  216 + title: '复制成功',
  217 + icon: 'success'
  218 + });
  219 + }
  220 + });
  221 + },
  222 + // 拨打电话
  223 + callUp() {
  224 + uni.makePhoneCall({
  225 + phoneNumber: this.cardDetail.mobile
  226 + });
  227 + },
  228 + // 收藏名片
  229 + collectCard() {
  230 + if (this.token) {
  231 + let url = '/api/collect/collect';
  232 + let params = {
  233 + goods_id:this.id
  234 + };
  235 + App.post(url,params)
  236 + .then(res=>{
  237 + uni.showToast({
  238 + title:'操作成功',
  239 + icon:'success',
  240 + duration:1500
  241 + })
  242 + setTimeout(function(){
  243 + uni.navigateBack({
  244 + delta:1
  245 + })
  246 + },1500)
  247 +
  248 + })
  249 + } else {
  250 + uni.navigateTo({
  251 + url: '/pages/start/start'
  252 + });
  253 + }
  254 + }
  255 + },
  256 + onLoad(option) {
  257 + this.token = uni.getStorageSync('token');
  258 + this.id = option.id;
  259 + // 获取名片详情
  260 + this.getCarDetail();
  261 + },
  262 +
  263 + onShareAppMessage: function (res) {
  264 + var that = this;
  265 +
  266 +
  267 + // 来自页面内转发按钮
  268 + return {
  269 + title: '分享',
  270 + path: "/pages/index/cardDetail?id="+that.id
  271 +
  272 + }
  273 +
  274 + }
  275 +
  276 +};
  277 +</script>
  278 +
  279 +<style>
  280 +@import url('../../style/cardDetail');
  281 +</style>
  1 +<template>
  2 + <view class="content">
  3 + <!-- 顶部搜索 -->
  4 + <view class="search_wrap layer_between">
  5 + <view class="search_input">
  6 + <input type="text" @confirm="toSearch()" v-model="keyword" placeholder="请输入名称、型号、品牌、厂家搜索" />
  7 + <image class="search_icon" src="../../static/search.png" mode=""></image>
  8 + </view>
  9 + <view class="search_word" @click="toSearch()">搜索</view>
  10 + </view>
  11 + <!-- 轴承列表 -->
  12 + <view class="bearing_classify layer_nostar">
  13 + <!-- 左侧类目 -->
  14 + <view class="bearing_l">
  15 + <view class="bear_l_box flex_column_center">
  16 + <view class="bear_l_single flex_warp" :class="{ bear_l_active: isLeft == item.id }" v-for="(item, index) in leftList" :key="index" @click="changeLeft(item,index)">
  17 + <view class="bear_l_child">{{ item.name }}</view>
  18 + </view>
  19 + </view>
  20 + </view>
  21 + <!-- 右侧具体分类 -->
  22 + <view class="bearing_r">
  23 + <view class="bear_r_box">
  24 + <view class="bear_r_single" :class="{bear_r_active:isRight == item.id}" v-for="(item, index) in rightList" :key="index" @click="changeRight(item,index)">{{ item.name }}</view>
  25 + </view>
  26 + </view>
  27 + </view>
  28 + <!-- 热搜名片 -->
  29 + <view class="hot_search">
  30 + <!-- 名片 -->
  31 + <view class="hot_card_wrap flex_wrap_between">
  32 + <view class="card_single" v-for="(item,index) in cardList" :key="index" @click="toDetail(item)">
  33 + <image :src="item.front_image" mode=""></image>
  34 + </view>
  35 + </view>
  36 + <!-- 分页 -->
  37 + <view class="card_pagation layer_between">
  38 + <view class="prev_page" :class="{next_page:pageNum>1}" @click="prevPage()">上一页</view>
  39 + <view class="layer_between jump_page">
  40 + 跳转到
  41 + <input type="text" @confirm="jumpPage()" v-model="pageNum" />
  42 +
  43 + </view>
  44 + <view class="next_page" :class="{prev:pageNum >= totalPage}" @click="nextPage()">下一页</view>
  45 + <view class="total_page">共{{totalPage/1}}页</view>
  46 + </view>
  47 + </view>
  48 + </view>
  49 +</template>
  50 +
  51 +<script>
  52 + import App from "../../App.vue";
  53 +export default {
  54 + data() {
  55 + return {
  56 + // 搜索
  57 + keyword:"",
  58 + // 轴承列表
  59 + // 左侧
  60 + leftList: [],
  61 + isLeft: 0,
  62 + // 右侧
  63 + rightList: [],
  64 + isRight: -1,
  65 + // 名片列表
  66 + cardList:[],
  67 + // 分页
  68 + pageNum:1,
  69 + // 总页数
  70 + totalPage:"",
  71 + };
  72 + },
  73 + methods: {
  74 + // 首页分类数据 左侧一级分类
  75 + getType(){
  76 + let t = this;
  77 + t.leftList = [];
  78 + t.rightList = [];
  79 + let url = "/api/category/get_category_one";
  80 + App.post(url)
  81 + .then(res=>{
  82 + t.leftList = res;
  83 + // 数据回显
  84 + t.leftList.forEach(el=>{
  85 + if(el.id == t.isLeft){
  86 + t.rightList = el.children;
  87 + }
  88 + })
  89 + })
  90 + },
  91 + // 左侧列表选中
  92 + changeLeft(item,index) {
  93 + this.isLeft = item.id;
  94 + this.rightList = item.children;
  95 + },
  96 + // 右侧列表选中
  97 + changeRight(item,index){
  98 + this.isRight = item.id;
  99 + this.getCardList();
  100 + },
  101 + // 获取名片列表
  102 + getCardList(){
  103 + let t = this;
  104 + let url = "/api/goods/goods_list";
  105 + let params = {
  106 + category_id:t.isRight,
  107 + page:t.pageNum
  108 + };
  109 + App.post(url,params)
  110 + .then(res=>{
  111 + t.totalPage = res.page_sum;
  112 + t.cardList = res.list;
  113 + })
  114 + },
  115 + // 名片详情
  116 + toDetail(item){
  117 + uni.navigateTo({
  118 + url:"/pages/index/cardDetail?id="+item.id
  119 + })
  120 + },
  121 + // 搜索 去名片列表
  122 + toSearch(){
  123 + uni.navigateTo({
  124 + url:"/pages/index/search?keyword="+this.keyword
  125 + })
  126 + },
  127 + // 上一页
  128 + prevPage(){
  129 + if(this.pageNum <=1 )
  130 + return false;
  131 + this.pageNum --;
  132 + this.getCardList()
  133 + },
  134 + // 下一页
  135 + nextPage(){
  136 + if(this.pageNum == this.totalPage){
  137 + return false
  138 + }
  139 + this.pageNum ++;
  140 + this.getCardList()
  141 + },
  142 + // 跳转到某一页
  143 + jumpPage(){
  144 + if(this.pageNum>this.totalPage)
  145 + this.pageNum = this.totalPage;
  146 + this.getCardList()
  147 + },
  148 + },
  149 + onLoad(options) {
  150 + this.isLeft = options.pid;
  151 + this.isRight = options.id;
  152 + // 首页分类数据
  153 + this.getType();
  154 + // 名片列表数据
  155 + this.getCardList();
  156 + },
  157 +};
  158 +</script>
  159 +
  160 +<style>
  161 +@import url('../../style/index');
  162 +
  163 +</style>