diy-img-setting.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-attachment');
  4. ComponentHelper::loadComponentView('com-pick-link');
  5. ?>
  6. <template id="diy-img-setting">
  7. <diy-style-contain class="diy-img-setting" :title="topName" :show-title="showTitle" :contain-style="imgContainStyle" :style="{'border-top': showTitle? '':'none'}">
  8. <div class="suggest" v-if="suggestSite == 1">{{suggestSizeText}}</div>
  9. <div class="diy-img-models">
  10. <div class="diy-img-model" :style="{'margin-bottom': '10px','padding': showHotZone?'0':''}" v-for="(item,index) in newImgInfos" :key="index" @mouseover="overModel(index)" @mouseleave="leaveModel">
  11. <div flex="cross:center">
  12. <com-attachment :style="{'width': showHotZone?'100%':''}" display="unset" :multiple="false" :max="1" type="images" @selected="coverPic($event,index)">
  13. <div class="card-upload img-upload-bor" :style="{width: showHotZone?'':imgPopSize[0] + 'px',height: showHotZone?'':imgPopSize[1] + 'px'}" v-if="!item.imgUrl.length">
  14. <i class="el-icon-plus icon-plugs-center"></i>
  15. </div>
  16. <div class="diy-sty-img" flex="main:center cross:center" :class="{'diy-img-hot-zone':showHotZone}" v-else @mouseover="mouseOverImg($event,index)" @mouseleave="mouseLeaveImg" :style="{width: showHotZone?'':imgPopSize[0] + 'px',height: showHotZone?'':imgPopSize[1] + 'px'}">
  17. <el-image class="diy-sty-img-u" :src="item.imgUrl"></el-image>
  18. <div class="diy-upd-img" :class="{'diy-upd-hot': showHotZone}" v-show="showHotZone || index == selImgIndex">替换</div>
  19. <i class="el-icon-close diy-upd-icon" @click.stop="delImg(index)" v-show="!showHotZone && index == selImgIndex"></i>
  20. <div v-if="showHotZone" class="img-hot-model" @click.stop="updatedHotZone(index)">
  21. <div v-for="(hot,hotIndex) in item.hotZone" :key="hotIndex" flex="main:center cross:center" :style="{'height': (hot.heightPer * 100) + '%','width': (hot.widthPer * 100) + '%','left': (hot.leftPer * 100) + '%','top': (hot.topPer * 100) + '%',}" class="img-hot-zone-model">
  22. {{hot.urlName || '暂无链接'}}
  23. </div>
  24. </div>
  25. </div>
  26. </com-attachment>
  27. <diy-url :text="item.urlName" @add="addUrl(index)" style="margin-left: 10px;" v-if="showUrl"></diy-url>
  28. <div v-if="showInput">
  29. <div flex="cross:center" style="margin-left: 4px;">
  30. <div style="width: 100px; text-align: right; margin-right: 4px;">小程序原始ID:</div>
  31. <el-input style="flex: 1" @input="textChange($event, 'app_appid', index)" type="text" placeholder="请输入小程序原始ID" v-model="item.app_appid" maxlength="50" size="small" show-word-limit></el-input>
  32. </div>
  33. <div flex="cross:center" style="margin-left: 4px;">
  34. <div style="width: 100px; text-align: right; margin-right: 4px;">小程序AppID:</div>
  35. <el-input style="flex: 1" @input="textChange($event, 'wx_appid', index)" type="text" placeholder="请输入小程序AppID" v-model="item.wx_appid" maxlength="50" size="small" show-word-limit></el-input>
  36. </div>
  37. <div flex="cross:center" style="margin-left: 4px;">
  38. <div style="width: 100px; text-align: right; margin-right: 4px;">小程序路径:</div>
  39. <el-input style="flex: 1" @input="textChange($event, 'wx_url', index)" type="text" placeholder="请输入小程序路径" v-model="item.wx_url" maxlength="200" size="small" show-word-limit></el-input>
  40. </div>
  41. </div>
  42. <div class="diy-img-del-model" v-show="newImgInfos.length > 1&&(selModelIndex == index || item.visible)">
  43. <el-popover placement="bottom" width="120" v-model="item.visible">
  44. <p class="diy-del-text">确定删除吗?</p>
  45. <div flex="cross:center">
  46. <el-button class="diy-del-btn" size="mini" plain @click="delModel(index)">删除</el-button>
  47. <el-button size="mini" plain @click="item.visible = false">取消</el-button>
  48. </div>
  49. <i class="el-icon-close" slot="reference" style="color:#999;"></i>
  50. </el-popover>
  51. </div>
  52. </div>
  53. <div class="img_button_text" v-if="suggestSite == 2">{{suggestSizeText}}</div>
  54. </div>
  55. <div class="diy-add-img" @click="addModel" v-if="openAddImg">
  56. +添加 {{maxImgLength >= 999?'':newImgInfos.length + '/' + maxImgLength}}
  57. </div>
  58. </div>
  59. <el-dialog width="50%" title="热区编辑器" append-to-body :visible.sync="hotZonePop">
  60. <div class="diy-hotzone-pop">
  61. <HotZone :image="selHotZoneImg.imgUrl" :zones-init="selHotZoneImg.hotZone" @add-url="addHotZoneUrl" @save="getSave"></HotZone>
  62. </div>
  63. </el-dialog>
  64. <com-pick-link @close="updatePop" :pop-boo="urlPop" @selected="selectedUrl" :default-tabs="defaultTabs"></com-pick-link>
  65. <el-dialog width="50%" title="添加链接" append-to-body :visible.sync="xunaiPop" :close-on-press-escape="false" :close-on-click-modal="false">
  66. <div class="diy-xunai-pop">
  67. <el-input v-model="xunaiUrl" placeholder="请输入链接" style="width: 100%;"></el-input>
  68. </div>
  69. <span slot="footer" class="dialog-footer">
  70. <el-button @click="xunaiPop=false">取 消</el-button>
  71. <el-button type="primary" @click="getxunaiUrl">确 定</el-button>
  72. </span>
  73. </el-dialog>
  74. </diy-style-contain>
  75. </template>
  76. <script>
  77. /**
  78. * 颜色组件
  79. *
  80. */
  81. Vue.component('diy-img-setting', {
  82. template: '#diy-img-setting',
  83. name: 'diy-img-setting',
  84. props: {
  85. showTitle: { //是否开启标题
  86. type: Boolean,
  87. default: true
  88. },
  89. imgContainStyle: { //最外层样式
  90. type: Object,
  91. default: () => {}
  92. },
  93. showHotZone: { //是否有热区:开启需要关闭showUrl
  94. type: Boolean,
  95. default: false
  96. },
  97. showUrl: { //是否开启链接选择
  98. type: Boolean,
  99. default: true
  100. },
  101. showInput: { //是否开启输入框输入
  102. type: Boolean,
  103. default: false
  104. },
  105. suggestSite: { //尺寸建议位置 1:在顶部 2:在图片下方
  106. type: [Number, String],
  107. default: 1
  108. },
  109. suggestSizeText: { //建议尺寸文本
  110. type: String,
  111. default: "建议图片宽为750,高度420"
  112. },
  113. openAddImg: { //是否开启添加按钮
  114. type: Boolean,
  115. default: false
  116. },
  117. topName: { //头部标题
  118. type: String,
  119. default: "图片设置",
  120. },
  121. imgPopSize: { //上传图片框的宽高展示 [宽度,高度]
  122. type: Array,
  123. default: () => {
  124. return ['60', '60']
  125. }
  126. },
  127. defImgUrl: { //全局默认图片
  128. type: String,
  129. default: "",
  130. },
  131. maxImgLength: { //最多添加图片数量
  132. type: [String, Number],
  133. default: 5
  134. },
  135. /**
  136. 是否开启默认创建
  137. */
  138. defAddImgBoo: {
  139. type: Boolean,
  140. default: false,
  141. },
  142. /**
  143. 默认创建多少个
  144. 注:defAddImgBoo需要开启
  145. */
  146. defImgCount: {
  147. type: [String, Number],
  148. default: 1
  149. },
  150. /**
  151. 数据格式
  152. {
  153. url: "", //链接路径
  154. urlName: '', //链接名
  155. urlType: '', //链接类型
  156. imgUrl: "" //图片路径
  157. visible: false, //删除弹窗
  158. hotZone: [{
  159. leftPer: 0,
  160. topPer: 0,
  161. widthPer: 0.30,
  162. heightPer: 0.30,
  163. url: '', //链接路径
  164. urlName: '', //链接名
  165. urlType: '', //链接类型
  166. }], //热区数据
  167. }
  168. 注:可传一个空数组
  169. */
  170. imgInfos: { //图片数据
  171. type: Array,
  172. default: () => {
  173. return []
  174. }
  175. },
  176. defaultTabs: { // 选择需要的tabs栏
  177. type: Array,
  178. default () {
  179. return ["mall", "goods", "addons", "other"]
  180. },
  181. },
  182. type:{
  183. type: String,
  184. default: ''
  185. }
  186. },
  187. data() {
  188. return {
  189. newImgInfos: [],
  190. selModelIndex: -1, //鼠标移入的模块下标
  191. selImgIndex: -1, //鼠标移入的图片下标
  192. visible: false,
  193. hotZonePop: false,
  194. selHotZoneIndex: -1, //选中图片下标
  195. selHotZoneImg: [], //选中图片数据热区
  196. urlPop: false,
  197. urlIndex: -1,
  198. hotZoneIndex: -1, //点击热区的下标
  199. xunaiPop:false,//寻艾弹窗
  200. xunaiUrl:''//寻艾链接
  201. }
  202. },
  203. created() {
  204. console.log('type', this.type);
  205. },
  206. watch: {
  207. imgInfos: {
  208. deep: true,
  209. immediate: true,
  210. handler(val) {
  211. let that = this;
  212. this.newImgInfos = [];
  213. if (val.length == 0) {
  214. this.addModel();
  215. } else {
  216. this.newImgInfos = val;
  217. }
  218. }
  219. }
  220. },
  221. methods: {
  222. // 添加
  223. addModel() {
  224. if (this.newImgInfos.length >= this.maxImgLength) {
  225. this.$notify({
  226. title: '',
  227. message: '最多添加' + this.maxImgLength + '个',
  228. type: 'warning'
  229. });
  230. return;
  231. }
  232. let obj = {
  233. url: "", //链接路径
  234. imgUrl: this.defImgUrl ? this.defImgUrl : "", //图片路径
  235. visible: false, //删除弹窗
  236. urlName: '', //链接名
  237. urlType: '', //链接类型
  238. app_appid: '',
  239. wx_appid: '',
  240. wx_url: '',
  241. hotZone: [{
  242. leftPer: 0,
  243. topPer: 0,
  244. widthPer: 0.30,
  245. heightPer: 0.30,
  246. url: '',
  247. urlName: '',
  248. urlType: '', //链接类型
  249. }], //热区数据
  250. }
  251. if (this.newImgInfos.length == 0) {
  252. this.newImgInfos = [];
  253. for (let i = 0; i < Number(this.defImgCount); i++) {
  254. this.newImgInfos.push(JSON.parse(JSON.stringify(obj)));
  255. }
  256. // 关闭默认创建
  257. // this.$emit("closeAddImg",false);
  258. } else {
  259. this.newImgInfos.push(obj);
  260. }
  261. this.changImg();
  262. },
  263. // 删除
  264. delModel(index) {
  265. if (this.newImgInfos.length == 1) {
  266. this.newImgInfos[index].visible = false;
  267. this.$notify({
  268. title: '',
  269. message: '最少保留一个',
  270. type: 'warning'
  271. });
  272. return;
  273. }
  274. this.newImgInfos.splice(index, 1);
  275. this.changImg();
  276. },
  277. // 添加图片
  278. coverPic(e, i) {
  279. console.info(e, i);
  280. this.newImgInfos[i].imgUrl = e[0].url;
  281. console.info(this.newImgInfos);
  282. this.changImg();
  283. },
  284. // 删除图片
  285. delImg(index) {
  286. this.newImgInfos[index].imgUrl = "";
  287. this.changImg();
  288. },
  289. // 鼠标移入图片
  290. mouseOverImg(event, index) {
  291. this.selImgIndex = index;
  292. },
  293. // 鼠标移出图片
  294. mouseLeaveImg() {
  295. this.selImgIndex = -1;
  296. },
  297. // 鼠标移入模块
  298. overModel(index) {
  299. this.selModelIndex = index;
  300. },
  301. // 鼠标移出模块
  302. leaveModel() {
  303. this.selModelIndex = -1;
  304. },
  305. // 编辑热区
  306. updatedHotZone(index) {
  307. this.hotZonePop = true;
  308. // this.selHotZoneImg = [];
  309. this.selHotZoneImg = JSON.parse(JSON.stringify(this.newImgInfos[index]));
  310. this.urlIndex = index;
  311. },
  312. // 获取热区数据
  313. getSave(val) {
  314. this.newImgInfos[this.urlIndex].hotZone = val;
  315. this.hotZonePop = false;
  316. this.changImg();
  317. },
  318. // 图片添加链接
  319. addUrl(index) {
  320. this.urlIndex = index;
  321. if (this.type == 'xun-ai') {
  322. this.xunaiUrl=this.newImgInfos[this.urlIndex].url.link
  323. if (this.newImgInfos[this.urlIndex].url) {
  324. this.xunaiUrl=this.newImgInfos[this.urlIndex].url.link
  325. }else{
  326. this.xunaiUrl=''
  327. }
  328. this.xunaiPop = true;
  329. }else{
  330. this.urlPop = true;
  331. }
  332. },
  333. updatePop(boo) {
  334. this.urlPop = boo;
  335. },
  336. selectedUrl(val) {
  337. console.log(val);
  338. if (!val.length) {
  339. return false
  340. }
  341. let urlInfo = val[0];
  342. if (this.hotZoneIndex == -1) {
  343. this.newImgInfos[this.urlIndex].urlName = getOtherUrlName(urlInfo.open_type) || urlInfo.title;
  344. this.newImgInfos[this.urlIndex].url = urlInfo.params;
  345. this.newImgInfos[this.urlIndex].urlType = urlInfo.open_type;
  346. this.urlIndex = -1;
  347. } else {
  348. this.selHotZoneImg.hotZone[this.hotZoneIndex].urlName = getOtherUrlName(urlInfo.open_type) || urlInfo.title;
  349. this.selHotZoneImg.hotZone[this.hotZoneIndex].url = urlInfo.params;
  350. this.selHotZoneImg.hotZone[this.hotZoneIndex].urlType = urlInfo.open_type;
  351. }
  352. this.urlPop = false;
  353. this.changImg();
  354. },
  355. textChange(event, field, index) {
  356. if (index !== undefined && this.newImgInfos[index]) {
  357. this.newImgInfos[index][field] = event;
  358. // 触发数据更新(通知父组件)
  359. this.changImg();
  360. }
  361. },
  362. //热区添加链接
  363. addHotZoneUrl(index) {
  364. console.log(index);
  365. this.hotZoneIndex = index;
  366. if (this.type == 'xun-ai') {
  367. if (this.selHotZoneImg.hotZone[this.hotZoneIndex].url) {
  368. this.xunaiUrl=this.selHotZoneImg.hotZone[this.hotZoneIndex].url.link
  369. }else{
  370. this.xunaiUrl=''
  371. }
  372. this.xunaiPop = true;
  373. }else{
  374. this.urlPop = true;
  375. }
  376. },
  377. // 通信
  378. changImg() {
  379. this.$emit("change", this.newImgInfos);
  380. },
  381. getxunaiUrl(){
  382. const urlInfo={
  383. "title": "",
  384. "open_type": "web",
  385. "navigate": "navigateTo",
  386. "route": "",
  387. "params": {
  388. "link": this.xunaiUrl,
  389. "open_type": "web"
  390. }
  391. }
  392. if (!urlInfo.params.link) {
  393. return false
  394. }
  395. if (this.hotZoneIndex == -1) {
  396. console.log(urlInfo.params,this.urlIndex);
  397. this.newImgInfos[this.urlIndex].url = urlInfo.params;
  398. this.newImgInfos[this.urlIndex].urlName ='寻艾页面链接:自定义链接'
  399. this.urlIndex = -1;
  400. }else{
  401. this.selHotZoneImg.hotZone[this.hotZoneIndex].urlName ='寻艾页面链接:自定义链接'
  402. this.selHotZoneImg.hotZone[this.hotZoneIndex].url =urlInfo.params;
  403. }
  404. this.changImg();
  405. this.xunaiUrl=''
  406. this.xunaiPop=false
  407. }
  408. }
  409. });
  410. </script>
  411. <style scoped>
  412. .suggest {
  413. margin: 20px 0 12px;
  414. background: #EAF3FE;
  415. border: 1px solid #2D8CF0;
  416. opacity: 1;
  417. border-radius: 3px;
  418. padding: 14px 17px 17px;
  419. font-size: 12px;
  420. font-weight: bold;
  421. color: #999999;
  422. }
  423. .diy-img-models {
  424. margin-bottom: 6px;
  425. }
  426. .diy-img-model {
  427. padding: 12px 9px 7px;
  428. background: #F6F5F8;
  429. position: relative;
  430. border-radius: 4px;
  431. }
  432. .img-upload-bor {
  433. position: relative;
  434. border: 1px dashed #D5D5D5;
  435. }
  436. .icon-plugs-center {
  437. position: absolute;
  438. top: 50%;
  439. left: 50%;
  440. transform: translate(-50%, -50%);
  441. }
  442. .diy-url {
  443. height: 39px;
  444. background: #EDF2FC;
  445. border-radius: 2px;
  446. font-size: 11px;
  447. font-weight: bold;
  448. line-height: 0px;
  449. color: #999999;
  450. flex: 1;
  451. padding: 9px 15px 14px;
  452. margin-left: 14px;
  453. }
  454. .diy-url-icon {
  455. font-size: 13px;
  456. margin-right: 10px;
  457. }
  458. .diy-add-img {
  459. font-size: 14px;
  460. font-weight: bold;
  461. color: #999999;
  462. border: 1px dashed #707070;
  463. border-radius: 5px;
  464. padding: 9px 0;
  465. text-align: center;
  466. margin-top: 24px;
  467. }
  468. .diy-sty-img {
  469. position: relative;
  470. background: #FFF;
  471. }
  472. .diy-upd-img {
  473. position: absolute;
  474. bottom: 0;
  475. left: 0;
  476. color: #999999;
  477. background: rgb(0 0 0 / 50%);
  478. width: 100%;
  479. text-align: center;
  480. min-height: 6%;
  481. z-index: 101;
  482. }
  483. .diy-upd-icon {
  484. position: absolute;
  485. top: -6px;
  486. right: -6px;
  487. background: rgb(0 0 0 / 50%);
  488. border-radius: 50%;
  489. color: #FFF;
  490. padding: 2px;
  491. font-size: 12px;
  492. }
  493. .diy-upd-img:hover,
  494. .diy-upd-icon:hover,
  495. .diy-url:hover,
  496. .diy-add-img:hover {
  497. cursor: pointer;
  498. }
  499. .diy-img-del-model {
  500. position: absolute;
  501. top: 10px;
  502. right: 9px;
  503. z-index: 101;
  504. }
  505. .diy-del-text {
  506. text-align: center;
  507. margin-bottom: 10px;
  508. }
  509. .diy-del-btn {
  510. border: 1px solid #bb3f3f;
  511. color: #bb3f3f;
  512. }
  513. .img_button_text {
  514. font-size: 12px;
  515. font-weight: bold;
  516. color: #999999;
  517. margin-top: 2px;
  518. }
  519. .diy-sty-img-u {
  520. max-height: 100%;
  521. width: 100%;
  522. }
  523. .diy-img-hot-zone {
  524. width: 100%;
  525. min-height: 200px;
  526. max-height: 950px;
  527. }
  528. .diy-upd-hot {
  529. height: 30px;
  530. line-height: 30px;
  531. }
  532. .img-hot-model {
  533. position: absolute;
  534. height: 100%;
  535. width: 100%;
  536. top: 0;
  537. left: 0;
  538. z-index: 100;
  539. }
  540. .img-hot-model:hover,
  541. .diy-img-del-model:hover {
  542. cursor: pointer;
  543. }
  544. .img-hot-zone-model {
  545. border: 1px solid red;
  546. position: absolute;
  547. background: rgba(233, 243, 253, 0.8);
  548. color: #3892F1;
  549. border: 1px solid #3892F1;
  550. }
  551. .diy-img-setting .el-dialog__header {
  552. border-bottom: 1px solid #f2f2f2;
  553. padding: 12px 22px;
  554. }
  555. .diy-img-setting .el-dialog__body {
  556. padding: 0;
  557. }
  558. .diy-hotzone-pop {
  559. padding: 10px 20px;
  560. }
  561. </style>