index.php 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. <script src="/resources/js/html2canvas.min.js"></script>
  2. <!-- 装修所需的数据 -->
  3. <script type="text/javascript" src="/resources/js/diy-util.js"></script>
  4. <script type="text/javascript" src="/resources/js/hotzone.js"></script>
  5. <script>
  6. function getNavData() {
  7. const result = [{
  8. // 顶部导航
  9. "id": getRandomId(),
  10. "data": {
  11. backSrc: "",
  12. contentType: "1",
  13. isShowName: "1",
  14. logoSrc: "",
  15. mainPage: { // 主页面设置
  16. defColor: "#fff",
  17. name: "积分商城",
  18. type: "纯色",
  19. imgUrl: ""
  20. },
  21. name: "积分商城",
  22. positionChoose: "1",
  23. hideSearch: false,
  24. },
  25. "computedStyle": {
  26. "mode": 1,
  27. "style": 1,
  28. "titleSwitch": true,
  29. "titleMode": 1,
  30. "imageUrl": [],
  31. "position": 1,
  32. "searchSwitch": true,
  33. "searchBgColor": "",
  34. "statusBarColor": "#FFF",
  35. "defaultForm": {
  36. "defColor": "transparer"
  37. },
  38. "titleDistance": {
  39. "fontSize": 16,
  40. "height": 30,
  41. "width": 57,
  42. "marginLeft": 20
  43. },
  44. "statusBar": "1",
  45. "searchMarPad": {
  46. "marginLeft": 20,
  47. "paddingLeft": 14
  48. }
  49. },
  50. "funcListItem": {
  51. "type": "nav",
  52. "title": "顶部导航",
  53. "is_top": 1
  54. },
  55. "isShow": true,
  56. "is_show_permission": false,
  57. "is_drag": false,
  58. "disabled": true,
  59. "is_delete": false,
  60. "is_up": false,
  61. "is_down": false,
  62. "is_copy": false
  63. }, {
  64. // 轮播图
  65. "id": getRandomId(),
  66. "data": {
  67. buttonData: {
  68. typeIndex: 0,
  69. typeItem: null
  70. },
  71. buttonPointData: {
  72. open: true,
  73. pointIndex: 1,
  74. pointItem: {
  75. label: "resources/img/decorate/point-two.png",
  76. value: "two"
  77. },
  78. position: 1
  79. },
  80. carouselImgArr: [{
  81. hotZone: [],
  82. imgUrl: "resources/img/decorate/default_img.png",
  83. url: "",
  84. urlName: "",
  85. urlType: "",
  86. visible: false
  87. }],
  88. spaceInfo: [{
  89. disabled: false,
  90. hidden: true,
  91. maxValue: 20,
  92. name: "图片间距",
  93. unit: "px",
  94. value: 5
  95. },
  96. {
  97. disabled: false,
  98. hidden: false,
  99. maxValue: 50,
  100. name: "上边距",
  101. unit: "px",
  102. value: 0,
  103. },
  104. {
  105. disabled: false,
  106. hidden: false,
  107. maxValue: 50,
  108. name: "下边距",
  109. unit: "px",
  110. value: 0
  111. },
  112. {
  113. disabled: false,
  114. hidden: false,
  115. maxValue: 50,
  116. name: "左右边距",
  117. unit: "px",
  118. value: 12
  119. }
  120. ]
  121. },
  122. "computedStyle": {
  123. "searchBox": "",
  124. "spaceStyle": {
  125. marginBottom: "0px",
  126. marginLeft: "12px",
  127. marginRight: "12px",
  128. marginTop: "0px",
  129. height: '160px',
  130. },
  131. "searchIpts": {
  132. 'border-bottom-left-radius': "10px",
  133. 'border-bottom-right-radius': "10px",
  134. 'border-top-left-radius': "10px",
  135. 'border-top-right-radius': "10px"
  136. }
  137. },
  138. "permission": [],
  139. "funcListItem": {
  140. is_top: 0,
  141. title: "轮播广告",
  142. type: "carousel-img"
  143. },
  144. "isShow": true,
  145. "is_show_permission": false,
  146. "is_drag": false,
  147. "disabled": true,
  148. "is_delete": false,
  149. "is_up": false,
  150. "is_down": false,
  151. "is_copy": false
  152. }, {
  153. // 按钮组
  154. "id": getRandomId(),
  155. "data": {
  156. "buttonData": {
  157. "line_num": 1,
  158. "pattern": "fixed",
  159. "patternItem": null,
  160. "shape": "square",
  161. "single_line": 3,
  162. "style": 1,
  163. "type": 1,
  164. },
  165. "colorInfos": [{
  166. color: "",
  167. name: "底部背景",
  168. showAlpha: false,
  169. value: "transparent"
  170. },
  171. {
  172. color: "",
  173. name: "组件背景",
  174. showAlpha: false,
  175. value: "transparent"
  176. },
  177. {
  178. color: "#333333",
  179. name: "文字颜色",
  180. showAlpha: false,
  181. value: "#333333",
  182. }
  183. ],
  184. "iconList": [
  185. {
  186. img: 'resources/img/decorate/default_btn1.png',
  187. icon: 'el-icon-setting',
  188. is_show_tag: true,
  189. tags: '热门',
  190. tagsBgColor: '#f83287',
  191. tagsTextColor: '#ffffff',
  192. btnText: '按钮文字',
  193. link_params: null,
  194. },
  195. ],
  196. "sizeInfos": [{
  197. disabled: false,
  198. hidden: false,
  199. maxValue: 50,
  200. name: "上边距",
  201. unit: "px",
  202. value: 8
  203. },
  204. {
  205. disabled: false,
  206. hidden: false,
  207. maxValue: 50,
  208. name: "下边距",
  209. unit: "px",
  210. value: 8
  211. },
  212. {
  213. disabled: false,
  214. hidden: false,
  215. maxValue: 50,
  216. name: "左右边距",
  217. unit: "px",
  218. value: 0
  219. }
  220. ],
  221. defaultTabs: [{name: 'marketing',children:['score_mall_cate']}],
  222. },
  223. "computedStyle": {
  224. "iptBg": "",
  225. "searchBox": "",
  226. "searchIpts": {
  227. "marginBottom": "8px",
  228. "marginLeft": "0px",
  229. "marginRight": "0px",
  230. "marginTop": "8px",
  231. },
  232. "textStyle": "#333333"
  233. },
  234. "permission": [],
  235. "funcListItem": {
  236. is_top: 0,
  237. title: "按钮组",
  238. type: "button-group"
  239. },
  240. "isShow": false,
  241. "is_show_permission": false,
  242. "is_drag": false,
  243. "disabled": true,
  244. "is_delete": false,
  245. "is_up": false,
  246. "is_down": false,
  247. "is_copy": false
  248. }, {
  249. // 积分商品列表
  250. "id": getRandomId(),
  251. "data": {
  252. listType: 1,
  253. listShow: true,
  254. dataType: 0,
  255. colorInfos: [
  256. {
  257. name: "底部颜色", //名字
  258. color: "", //颜色
  259. showAlpha: false, //是否开启透明度
  260. value: "", //展示的值
  261. },
  262. {
  263. name: "组件颜色", //名字
  264. color: "#FFFFFF", //颜色
  265. showAlpha: false, //是否开启透明度
  266. value: "#FFFFFF", //展示的值
  267. }
  268. ],
  269. sizeInfos: [
  270. {
  271. disabled: false,
  272. hidden: false,
  273. maxValue: 20,
  274. name: "图片间距",
  275. unit: "px",
  276. value: 12,
  277. },
  278. {
  279. disabled: false,
  280. hidden: false,
  281. maxValue: 50,
  282. name: "上边距",
  283. unit: "px",
  284. value: 7,
  285. },
  286. {
  287. disabled: false,
  288. hidden: false,
  289. maxValue: 50,
  290. name: "下边距",
  291. unit: "px",
  292. value: 12,
  293. },
  294. {
  295. disabled: false,
  296. hidden: false,
  297. maxValue: 50,
  298. name: "左右边距",
  299. unit: "px",
  300. value: 12,
  301. },
  302. {
  303. disabled: false,
  304. hidden: false,
  305. maxValue: 20,
  306. name: "内边距",
  307. unit: "px",
  308. value: 0,
  309. },
  310. ],
  311. },
  312. "computedStyle": {
  313. searchBox: "",
  314. iptBg: "#FFFFFF",
  315. btnBackground: "#db0505",
  316. btnTextColor: "#fff",
  317. sizeInfos: {
  318. marginBottom: "12px",
  319. marginTop: "7px",
  320. aroundMargin: "12px",
  321. spacing: "12px",
  322. padding: "0px",
  323. },
  324. },
  325. "permission": [],
  326. "funcListItem": {
  327. is_top: 0,
  328. title: "商品列表",
  329. type: "score-list"
  330. },
  331. "isShow": true,
  332. "is_show_permission": false,
  333. "is_drag": false,
  334. "disabled": true,
  335. "is_delete": false,
  336. "is_up": false,
  337. "is_down": false,
  338. "is_copy": false
  339. }]
  340. return result
  341. }
  342. </script>
  343. <?php
  344. use common\helpers\ComponentHelper;
  345. use common\models\diy\DiyComponents;
  346. use common\helpers\AddonHelper;
  347. $diyPath = Yii::$app->viewPath . '/components/common/diy/common';
  348. $stylePath = Yii::$app->viewPath . '/components/common/diy/style-components';
  349. $components = DiyComponents::getDir($diyPath, $diyPath);
  350. $styleComponents = DiyComponents::getDir($stylePath, $stylePath);
  351. ComponentHelper::loadComponentView('diy/diy-preview');
  352. ComponentHelper::loadComponentView('diy/diy-style-preview');
  353. ComponentHelper::loadComponentView('style', AddonHelper::getAddonRootPath('ScoreMall') . 'backend/views/components/diy/score-list');
  354. ComponentHelper::loadComponentView('preview', AddonHelper::getAddonRootPath('ScoreMall') . 'backend/views/components/diy/score-list');
  355. // ComponentHelper::loadComponentView("components/score-list/style", __DIR__);
  356. // ComponentHelper::loadComponentView("components/score-list/style", __DIR__);
  357. foreach ($components as $item) {
  358. ComponentHelper::loadComponentView("diy/common/{$item}");
  359. }
  360. foreach ($styleComponents as $item) {
  361. ComponentHelper::loadComponentView("diy/style-components/{$item}");
  362. }
  363. $currentRoute = Yii::$app->controller->route;
  364. ?>
  365. <div id="app">
  366. <div style="padding-bottom: 10px;padding-right: 20px;background: #F4F6F8;" @click="save" flex="main:right">
  367. <el-button type="primary">保存</el-button>
  368. </div>
  369. <div class="diy-contain flex" v-loading="loading">
  370. <diy-preview :active-index="activeIndex" :list="previewList" @select-item="selectItme" @change-move="changeMove"></diy-preview>
  371. <transition name="fade">
  372. <diy-style-preview :active-item="activeItem" :active-index="activeIndex" :permission="permission" @update="changeDiyItem" v-if="showUpdate"></diy-style-preview>
  373. </transition>
  374. </div>
  375. <!-- 预览弹窗 -->
  376. <el-dialog title="预览弹窗" :modal-append-to-body="false" :visible.sync="dialogFormVisible">
  377. <div class="flex flex-x-center" style="height: 600px;overflow:auto">
  378. <img id="diy-test-preview" :src="previewSrc"></img>
  379. </div>
  380. <div slot="footer" class="dialog-footer">
  381. <el-button @click="dialogFormVisible = false">取 消</el-button>
  382. <el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
  383. </div>
  384. </el-dialog>
  385. </div>
  386. <script>
  387. Vue.prototype.$capitals = []; // 用户信息对象
  388. Vue.prototype.$eventBus = new Vue();
  389. var PageShareData = {
  390. pageIndex: false // 点击页面设置标识 => nav/style
  391. }; // 全局共享数据 - 没有响应式
  392. new Vue({
  393. el: '#app',
  394. data() {
  395. return {
  396. capital: [],
  397. dialogFormVisible: false,
  398. /**
  399. * @descriptions 浮动()、普通()、置顶(isTop)、弹窗(alert)四种显示组件
  400. * @param {string} type // diy组件类型
  401. * @param {string} title // 二级标题
  402. * @param {string} img // diy组件图片
  403. * @param {number} count // 可添加diy组件数量
  404. * @param {boolean} is_top // diy组件是否置顶组件 - 待添加 - 分添加等级 1 2 3 数字靠前权限越高
  405. * @param {object} permission // 组件的不可操作权限 {"is_delete": false,"is_drag": false,"disabled": true, // 禁用操作}
  406. */
  407. pageComponentsList: [],
  408. /**
  409. * @param {boolean} is_show_permission // 显示权限
  410. * @param {boolean} is_delete // 是否可删除
  411. * @param {boolean} is_up // 是否可上移
  412. * @param {boolean} is_down // 是否可下移
  413. * @param {boolean} is_drag // 是否可拖拽
  414. * @param {boolean} is_copy // 是否可复制
  415. * @param {boolean} disabled // 全部禁用操作
  416. */
  417. previewList: [], // 预览数组对象
  418. activeIndex: -1, // 预览激活索引
  419. activeItem: null, // 预览激活对象
  420. type: "add", // add新增 - edit编辑
  421. test: ["a", "b", "c"],
  422. showUpdate: true,
  423. responentData: null, // 详情响应的总数据
  424. permission: [], // 权限数组
  425. isClickPage: false, // 是否点击分页设置
  426. loading: false, // 数据加载
  427. saveLoading: false, // 保存数据
  428. fields: {
  429. upload_type: 'images'
  430. },
  431. previewSrc: "",
  432. }
  433. },
  434. provide() {
  435. return {
  436. capitals: this.capital
  437. }
  438. },
  439. watch: {
  440. activeIndex() {
  441. this.showUpdate = false
  442. setTimeout(() => {
  443. this.showUpdate = true
  444. }, 0)
  445. },
  446. },
  447. created() {
  448. // console.log(this.dynamicImgSrc('/abc/ss'));
  449. // 添加不同的模板nav
  450. this.previewList.push(...getNavData())
  451. this.init()
  452. this.detail()
  453. },
  454. methods: {
  455. savePreview() {
  456. this.activeIndex = -1
  457. this.activeItem = null
  458. this.$nextTick(() => {
  459. const contain = document.getElementById("diy-preview-contain");
  460. this.deepNode(contain);
  461. setTimeout(() => {
  462. this.dialogFormVisible = true
  463. html2canvas(contain, {
  464. useCORS: true
  465. }).then(canvas => {
  466. const src = canvas.toDataURL("image/png")
  467. this.upload(this.dataURLtoFile(src)).then(res => {
  468. if (res.code == 0) {
  469. this.previewSrc = res.data.url
  470. this.save(false)
  471. } else {
  472. this.$message({
  473. message: res.msg,
  474. type: 'warning'
  475. });
  476. }
  477. })
  478. })
  479. }, 0)
  480. })
  481. },
  482. dataURLtoFile(dataurl) { // 生成Blob
  483. var arr = dataurl.split(',');
  484. var mime = arr[0].match(/:(.*?);/)[1];
  485. var bstr = atob(arr[1]);
  486. var n = bstr.length;
  487. var u8arr = new Uint8Array(n);
  488. while (n--) {
  489. u8arr[n] = bstr.charCodeAt(n);
  490. }
  491. return new Blob([u8arr], {
  492. type: mime
  493. });
  494. },
  495. upload(file) {
  496. let formData = new FormData();
  497. const params = {
  498. upload_type: 'images'
  499. };
  500. params['r'] = 'common/file/upload';
  501. for (let i in this.fields) {
  502. formData.append(i, this.fields[i]);
  503. }
  504. formData.append('file', file, "image.png");
  505. return new Promise(successCallback => {
  506. this.$request({
  507. headers: {
  508. 'Content-Type': 'multipart/form-data'
  509. },
  510. params: params,
  511. method: 'post',
  512. data: formData,
  513. }).then(e => {
  514. successCallback(e.data)
  515. }).catch(e => {
  516. file._complete = true;
  517. });
  518. })
  519. },
  520. deepNode(contain) {
  521. if (contain.tagName === "IMG") {
  522. contain.src = contain.src + '?t=' + Date.now()
  523. contain.setAttribute('crossorigin', 'anonymous')
  524. }
  525. if (contain.children && contain.children.length) {
  526. [].forEach.call(contain.children, (item => {
  527. this.deepNode(item)
  528. }))
  529. }
  530. },
  531. pageSet() {
  532. PageShareData.pageIndex = true
  533. this.$eventBus.$emit("onPageClick")
  534. var index = 0;
  535. this.activeIndex = index
  536. this.activeItem = this.previewList[index]
  537. // this.changeDiyItem()
  538. },
  539. detail() {
  540. // 详情
  541. this.loading = true
  542. request({
  543. params: {
  544. r: 'score-mall/diy/index'
  545. },
  546. method: 'get',
  547. }).then(res => {
  548. if(res.data.code == 0){
  549. const previewList = JSON.parse(res.data.data.content)
  550. if(!previewList.length) return
  551. this.previewList = previewList
  552. } else {
  553. this.$message({
  554. message: res.data.msg,
  555. type: 'error'
  556. });
  557. }
  558. /* const {
  559. data
  560. } = res.data
  561. if (res.data.code != 0) {
  562. this.$message({
  563. message: res.data.msg,
  564. type: 'error'
  565. });
  566. return false
  567. }
  568. const previewList = JSON.parse(data.content)
  569. this.previewList = previewList */
  570. }).finally(res => {
  571. this.loading = false
  572. })
  573. },
  574. save: debounce(function(isLoading = true) {
  575. // 对接保存数据接口
  576. if (this.saveFlag) {
  577. console.log("重复提交");
  578. return
  579. }
  580. const title = this.previewList[0].data.name
  581. if (!title) {
  582. this.$message({
  583. message: '请输入标题',
  584. type: 'warning'
  585. });
  586. return
  587. }
  588. isLoading && (this.saveLoading = true)
  589. this.saveFlag = true // 防止重复提交限制
  590. request({
  591. params: {
  592. r: 'score-mall/diy/index'
  593. },
  594. method: 'post',
  595. data: {
  596. content: JSON.stringify(this.previewList),
  597. }
  598. }).then(res => {
  599. if (res.data.code != 0) {
  600. this.$message({
  601. message: res.data.msg,
  602. type: 'error'
  603. });
  604. } else {
  605. this.$message({
  606. message: res.data.msg,
  607. type: 'success'
  608. });
  609. }
  610. }).finally(res => {
  611. this.saveFlag = false
  612. this.saveLoading = false
  613. })
  614. },400),
  615. init() {
  616. this.$eventBus.$on("diy-preview-copy", (item = {}) => {
  617. this.copy(item)
  618. })
  619. this.$eventBus.$on("diy-preview-operateFn", (item = {}) => {
  620. this.operateFn(item)
  621. })
  622. this.$eventBus.$on("diy-back-set", () => {
  623. this.updateView(null, -1)
  624. })
  625. },
  626. validateCount(e) {
  627. // 校验组件能添加几个
  628. var msg = "";
  629. var list = this.previewList.filter(item => {
  630. return item.funcListItem.type === e.type
  631. });
  632. if (e && e.count && list.length >= e.count) {
  633. msg = `该组件只能添加${e.count}个哦`
  634. }
  635. if (msg) {
  636. this.$message({
  637. message: msg,
  638. type: 'warning'
  639. });
  640. }
  641. return msg
  642. },
  643. getIsTopArrLength() {
  644. return this.previewList.filter(item => {
  645. const e1 = item.funcListItem || {}
  646. return e1.is_top
  647. }).length
  648. },
  649. changeDiyItem(item, index, params = {}) {
  650. var {
  651. type
  652. } = params
  653. var list = deepClone(this.previewList) // 克隆一下
  654. if (type !== "isShow") {
  655. // 显示问题 -- 样式组件不让修改
  656. item.isShow = list[this.activeIndex].isShow;
  657. }
  658. // 直接全部覆盖
  659. list[this.activeIndex] = deepClone(item)
  660. this.activeItem = deepClone(item)
  661. this.previewList = list
  662. },
  663. selectItme(item, index) {
  664. console.info(item);
  665. if (this.activeIndex == index) {
  666. this.activeIndex = -1
  667. this.activeItem = null
  668. } else {
  669. this.activeIndex = index
  670. this.activeItem = item
  671. }
  672. console.info();
  673. this.$forceUpdate()
  674. },
  675. pushItem(list = [], target = {}) {
  676. var result = deepClone(list)
  677. result.push(target)
  678. return result
  679. },
  680. /**
  681. * 两种形式,一种push,追加index
  682. */
  683. addIndexItem(list = [], target = {}, index) { // 往指定的index添加item
  684. var result = deepClone(list)
  685. if (this.activeIndex < 0) {
  686. result.push(target)
  687. } else {
  688. var handleArr = [deepClone(result[index]), target]
  689. result.splice(index, 1, ...handleArr)
  690. }
  691. return result
  692. },
  693. // 操作相关
  694. copy() {
  695. if (!this.activeItem || this.activeItem.disabled || this.activeItem.is_copy === false) {
  696. return
  697. }
  698. var item = deepClone(this.activeItem)
  699. item.id = getRandomId()
  700. this.previewList = this.addIndexItem(this.previewList, item, this.activeIndex)
  701. },
  702. /**
  703. * @params {string} obj.type up - down - show
  704. */
  705. operateFn(obj) {
  706. const methods = {
  707. show: 'showItem',
  708. up: 'upItem',
  709. down: 'downItem',
  710. delete: 'deleteItem'
  711. }
  712. this[methods[obj.type]](obj.index)
  713. },
  714. showItem(index) {
  715. var item = deepClone(this.activeItem);
  716. item.isShow = !item.isShow
  717. this.changeDiyItem(item, index, {
  718. type: "isShow"
  719. })
  720. },
  721. updateView(item, index) {
  722. this.activeItem = item
  723. this.activeIndex = index
  724. },
  725. deleteItem(index) {
  726. if (this.activeItem.disabled || this.activeItem.is_delete === false) {
  727. return false
  728. }
  729. this.previewList.splice(index, 1);
  730. // 删除后失去焦点
  731. this.activeIndex = -1;
  732. this.activeItem = null;
  733. },
  734. upItem(index) {
  735. const topArr = this.previewList.filter(item => {
  736. const e1 = item.funcListItem || {}
  737. return e1.is_top
  738. }) // 操作上限
  739. const topIndex = Math.max(0, topArr.length)
  740. if (index <= 0 || this.activeItem.disabled || this.activeItem.is_up === false) {
  741. return false
  742. } else if (index <= topIndex) {
  743. alert("不可以再操作了噢");
  744. return false
  745. }
  746. var previewList = deepClone(this.previewList);
  747. this.previewList = this.swapItems(previewList, index, index - 1);
  748. this.updateView(this.previewList[index - 1], index - 1);
  749. },
  750. downItem(index) {
  751. if (this.activeItem.disabled || this.activeItem.is_down === false) {
  752. return false
  753. } else if (index === this.previewList.length - 1) {
  754. alert("不可以再操作了噢");
  755. return false
  756. }
  757. var previewList = deepClone(this.previewList);
  758. this.previewList = this.swapItems(previewList, index, index + 1);
  759. this.updateView(this.previewList[index + 1], index + 1);
  760. },
  761. swapItems(arr, index1, index2) {
  762. var item = deepClone(arr[index1]);
  763. arr[index1] = arr[index2]
  764. arr[index2] = item
  765. return arr
  766. },
  767. changeMove(e) {
  768. const {
  769. newIndex,
  770. list
  771. } = e
  772. // 移动拖拽改变索引
  773. this.previewList = deepClone(list);
  774. this.updateView(this.previewList[newIndex], newIndex);
  775. },
  776. // 更新主页面
  777. updateMainPage(item) {
  778. this.mainPage = deepClone(item);
  779. },
  780. // 处理兼容老数据
  781. addIsTop(list, type) {
  782. const obj = {
  783. ['nav']: 1,
  784. ['member-info']: 2
  785. }
  786. const top = obj[type]
  787. list.forEach(item => {
  788. if (item.funcListItem.type === type && !item.funcListItem.is_top) {
  789. item.funcListItem.is_top = top
  790. }
  791. });
  792. return list
  793. }
  794. }
  795. })
  796. // 拦截页面卸载
  797. /* window.onbeforeunload = function(e) {
  798. var e = window.event || e;
  799. e.returnValue = ("确定离开当前页面吗?");
  800. } */
  801. </script>
  802. <style>
  803. #app {
  804. display: flex;
  805. flex-direction: column;
  806. min-width: 1250px;
  807. }
  808. #diy-test-preview {
  809. margin: auto;
  810. }
  811. .diy-header-backs {
  812. cursor: pointer;
  813. }
  814. .fixed {
  815. position: fixed;
  816. left: 0;
  817. top: 0;
  818. width: 100%;
  819. height: 100%;
  820. z-index: 999;
  821. }
  822. .diy-header {
  823. height: 60px;
  824. background: #313131;
  825. opacity: 1;
  826. border-radius: 0px;
  827. justify-content: space-between;
  828. font-size: 13px;
  829. font-family: PingFang SC;
  830. font-weight: bold;
  831. color: #FFFFFF;
  832. padding: 0 30px;
  833. }
  834. .diy-contain {
  835. flex: 1;
  836. overflow: auto;
  837. background: #F4F6F8;
  838. justify-content: space-between;
  839. }
  840. .diy-func-list {
  841. box-sizing: border-box;
  842. width: 354px;
  843. background: #FFFFFF;
  844. border-radius: 0px;
  845. }
  846. .diy-preview {
  847. flex: 1;
  848. background: #F4F6F8;
  849. justify-content: space-around;
  850. }
  851. .fill-box {
  852. position: relative;
  853. width: 467px;
  854. height: 100%;
  855. }
  856. .flex {
  857. display: flex;
  858. }
  859. .flex-x-center {
  860. justify-content: center;
  861. }
  862. .flex-y-center {
  863. align-items: center;
  864. }
  865. /* */
  866. .fade-enter-active,
  867. .fade-leave-active {
  868. transition: opacity 1s;
  869. }
  870. .fade-enter,
  871. .fade-leave-to {
  872. opacity: 0;
  873. }
  874. .diy-text-font {
  875. font-size: 13px;
  876. font-weight: 700;
  877. color: #999999;
  878. }
  879. .fill-border-top {
  880. border-top: 10px solid #F4F6F8;
  881. }
  882. .fill-border-bottom {
  883. border-bottom: 10px solid #F4F6F8;
  884. }
  885. /* 导航栏 */
  886. .custom-page {
  887. width: 181px;
  888. height: 60px;
  889. line-height: 60px;
  890. background: var(--diy-theme);
  891. font-weight: 700;
  892. border-radius: 0px;
  893. text-align: center;
  894. }
  895. .save {
  896. font-size: 24px;
  897. vertical-align: middle;
  898. }
  899. .save+span {
  900. vertical-align: middle;
  901. }
  902. .sava_btn .el-button--primary {
  903. background: var(--diy-theme);
  904. border-color: var(--diy-theme);
  905. padding: 8px 14px;
  906. }
  907. .diy_nav_right>div {
  908. padding: 8px 14px;
  909. }
  910. .diy_nav_right .sava_btn {
  911. padding: 0;
  912. }
  913. .page_set>i {
  914. font-size: 24px;
  915. vertical-align: middle;
  916. }
  917. .page_set>span {
  918. vertical-align: middle;
  919. }
  920. .xiaoshou {
  921. cursor: pointer;
  922. }
  923. :root {
  924. /* 主题色 */
  925. --diy-theme: #F10009;
  926. /* 主要字体颜色 */
  927. --diy-color: #F10009;
  928. }
  929. /* 修改ele默认样式 */
  930. /* slider组件 */
  931. .el-slider__bar {
  932. background-color: var(--diy-theme);
  933. }
  934. .el-slider__button {
  935. border-color: var(--diy-theme);
  936. }
  937. /* input组件 */
  938. .el-input .el-input__inner:focus {
  939. border: 1px solid var(--diy-theme);
  940. }
  941. /* textarea */
  942. .el-textarea .el-textarea__inner:focus {
  943. border: 1px solid var(--diy-theme);
  944. }
  945. /* radio单选组件 */
  946. .el-radio__input.is-checked+.el-radio__label {
  947. color: var(--diy-color);
  948. }
  949. .el-radio__input.is-checked .el-radio__inner {
  950. border-color: var(--diy-theme);
  951. background: var(--diy-theme);
  952. }
  953. .el-radio-button__orig-radio:checked+.el-radio-button__inner {
  954. border-color: var(--diy-theme);
  955. box-shadow: -1px 0 0 0 var(--diy-theme);
  956. }
  957. /* 多选 */
  958. .el-checkbox__input.is-checked+.el-checkbox__label {
  959. color: var(--diy-color);
  960. }
  961. .el-checkbox__input.is-checked .el-checkbox__inner,
  962. .el-checkbox__input.is-indeterminate .el-checkbox__inner {
  963. border-color: var(--diy-theme);
  964. background: var(--diy-theme);
  965. }
  966. </style>