diy-img-setting.php 17 KB

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