diy-img-setting.php 17 KB

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