bottom-nav.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. <?php
  2. /**
  3. * @link:http://www.gdqijianshi.com/
  4. * @copyright: Copyright (c) 2020 广东七件事集团
  5. * 设置
  6. * Author: zal
  7. * Date: 2020-04-13
  8. * Time: 10:16
  9. */
  10. ?>
  11. <style>
  12. .nav-box {
  13. width: 220px;
  14. height: 45px;
  15. line-height: 45px;
  16. border: 1px solid #000000;
  17. text-align: center;
  18. }
  19. .bottom-icon {
  20. width: 80px;
  21. height: 80px;
  22. margin-right: 10px;
  23. border: 1px solid #eeeeee;
  24. cursor: move;
  25. }
  26. .nav-action {
  27. cursor: pointer;
  28. }
  29. .nav-icon {
  30. width: 30px;
  31. height: 30px;
  32. }
  33. .nav-add {
  34. border: 1px dashed #eeeeee;
  35. cursor: pointer;
  36. }
  37. .nav-add-icon {
  38. font-size: 50px;
  39. color: #eeeeee;
  40. }
  41. .form-body {
  42. padding: 20px 0;
  43. background-color: #fff;
  44. margin-bottom: 20px;
  45. }
  46. .button-item {
  47. padding: 9px 25px;
  48. }
  49. .mobile {
  50. width: 404px;
  51. height: 736px;
  52. border-radius: 30px;
  53. background-color: #fff;
  54. padding: 33px 12px;
  55. margin-right: 10px;
  56. }
  57. .screen {
  58. border: 2px solid #F3F5F6;
  59. height: 670px;
  60. width: 380px;
  61. margin: 0 auto;
  62. position: relative;
  63. background-color: #F7F7F7;
  64. }
  65. .screen .head {
  66. position: absolute;
  67. top: 0;
  68. left: 0;
  69. width: 376px;
  70. height: 60px;
  71. line-height: 60px;
  72. font-size: 18px;
  73. font-weight: bolder;
  74. text-align: center;
  75. }
  76. .screen .foot {
  77. position: absolute;
  78. bottom: 0;
  79. left: 0;
  80. width: 376px;
  81. /*padding: 5px 25px;*/
  82. height: 45px;
  83. /*display: flex;*/
  84. /*text-align: center;*/
  85. /*justify-content: space-between;*/
  86. /*font-size: 11px;*/
  87. }
  88. .screen .foot .nav-icon {
  89. height: 20px;
  90. width: 20px;
  91. }
  92. .screen .foot .nav-icon + div {
  93. margin-top: -10px;
  94. }
  95. .title {
  96. padding: 18px 20px;
  97. border-bottom: 1px solid #F3F3F3;
  98. background-color: #fff;
  99. }
  100. </style>
  101. <div id="app" v-cloak>
  102. <el-card shadow="never" style="border:0" body-style="background-color: #f3f3f3;padding: 10px 0 0;"
  103. v-loading="cardLoading">
  104. <div slot="header">
  105. <div>
  106. <span>底部导航设置</span>
  107. </div>
  108. </div>
  109. <div style="display: flex;">
  110. <div class="mobile">
  111. <div class="screen">
  112. <!-- <div class="head"
  113. :style="{backgroundColor: ruleForm.top_background_color, color: ruleForm.top_text_color}">这里是标题
  114. </div> -->
  115. <div class="foot"
  116. :style="{backgroundColor: ruleForm.bottom_background_color, color: ruleForm.bottom_text_color}">
  117. <div flex="dir:left box:mean">
  118. <div flex="dir:top cross:center" v-for="(item, index) in ruleForm.navs" @click="navClick(index)">
  119. <div>
  120. <img v-if="item.iconPath" :src="navCurrent == index ? item.selectedIconPath : item.iconPath" class="nav-icon">
  121. <el-image v-else>
  122. <div slot="error" class="image-slot">
  123. <i class="el-icon-picture-outline" style="font-size: 14px;"></i>
  124. </div>
  125. </el-image>
  126. </div>
  127. <div :style="{color:navCurrent == index ? ruleForm.active_color : ruleForm.inactive_color}">
  128. {{item.text}}
  129. </div>
  130. </div>
  131. </div>
  132. </div>
  133. </div>
  134. </div>
  135. <div style="width: 100%;">
  136. <el-form :model="ruleForm" :rules="rules" size="small" ref="ruleForm" label-width="120px">
  137. <div class="title">底部标签栏</div>
  138. <div class='form-body'>
  139. <el-form-item label="背景颜色" prop="bottom_background_color">
  140. <el-color-picker
  141. show-alpha
  142. color-format="rgb"
  143. v-model="ruleForm.bottom_background_color"
  144. :predefine="predefineColors">
  145. </el-color-picker>
  146. </el-form-item>
  147. <!-- <el-form-item label="导航阴影效果">-->
  148. <!-- <el-switch v-model="ruleForm.shadow" :active-value="1" :inactive-value="0"></el-switch>-->
  149. <!-- </el-form-item>-->
  150. <el-form-item label="文字颜色" prop="inactive_color">
  151. <el-color-picker
  152. color-format="rgb"
  153. v-model="ruleForm.inactive_color"
  154. :predefine="predefineColors">
  155. </el-color-picker>
  156. </el-form-item>
  157. <el-form-item label="选中文字颜色" prop="active_color">
  158. <el-color-picker
  159. color-format="rgb"
  160. v-model="ruleForm.active_color"
  161. :predefine="predefineColors">
  162. </el-color-picker>
  163. </el-form-item>
  164. <el-form-item label="底部导航图标">
  165. <div flex="main:left">
  166. <!-- 首页不能被拖拽特殊处理 -->
  167. <div @mouseenter="navIconEnter(index)"
  168. @mouseleave="navIconAway"
  169. style="position: relative"
  170. flex="dir:top box:mean"
  171. v-for="(item, index) in ruleForm.navs"
  172. class="bottom-icon" v-if="index == 0">
  173. <div flex="main:center cross:center">
  174. <img v-if="item.iconPath" :src="item.iconPath" class="nav-icon">
  175. <el-image v-else>
  176. <div slot="error" class="image-slot">
  177. <i class="el-icon-picture-outline" style="font-size: 18px;"></i>
  178. </div>
  179. </el-image>
  180. </div>
  181. <div flex="main:center cross:center">{{item.text}}</div>
  182. <div v-show="navIconIndex == index"
  183. style="position: absolute;bottom: 0;width: 100%;height: 25px;"
  184. class="nav-action"
  185. flex="box:mean">
  186. <span @click="navIconEdit(index)" style="background: rgba(64, 158, 255, 0.9);"
  187. flex="main:center cross:center">
  188. 编辑
  189. </span>
  190. <span @click="navIconDestroy(index)"
  191. style="background: rgba(245, 108, 108, 0.9);"
  192. flex="main:center cross:center">
  193. 删除
  194. </span>
  195. </div>
  196. </div>
  197. <!-- 非首页处理 -->
  198. <draggable flex="main:left" :options="{filter:'.bottom-icon-false',preventOnFilter:false}" style="display:flex;flex-wrap: wrap" v-model="ruleForm.navs" id="box">
  199. <div @mouseenter="navIconEnter(index)"
  200. @mouseleave="navIconAway"
  201. style="position: relative"
  202. flex="dir:top box:mean"
  203. v-for="(item, index) in ruleForm.navs"
  204. class="bottom-icon" v-if="index > 0">
  205. <div flex="main:center cross:center">
  206. <img :src="item.iconPath" class="nav-icon">
  207. </div>
  208. <div flex="main:center cross:center">{{item.text}}</div>
  209. <div v-show="navIconIndex == index"
  210. style="position: absolute;bottom: 0;width: 100%;height: 25px;"
  211. class="nav-action"
  212. flex="box:mean">
  213. <span @click="navIconEdit(index)" style="background: rgba(64, 158, 255, 0.9);"
  214. flex="main:center cross:center">
  215. 编辑
  216. </span>
  217. <span @click="navIconDestroy(index)"
  218. style="background: rgba(245, 108, 108, 0.9);"
  219. flex="main:center cross:center">
  220. 删除
  221. </span>
  222. </div>
  223. </div>
  224. </draggable>
  225. <div v-if="ruleForm.navs.length < navMaxCount"
  226. @click="navIconEdit('-1')"
  227. flex="main:center cross:center"
  228. class="bottom-icon nav-add">
  229. <i class="el-icon-plus nav-add-icon"></i>
  230. </div>
  231. </div>
  232. </el-form-item>
  233. </div>
  234. <el-button class="button-item" :loading="btnLoading" type="primary" @click="store('ruleForm')"
  235. size="small">保存
  236. </el-button>
  237. <el-button class="button-item" :loading="btnLoading" size="small" plain @click="restoreDefault">
  238. 恢复默认
  239. </el-button>
  240. </el-form>
  241. </div>
  242. </div>
  243. <el-dialog @close="dialogColse" title="导航菜单编辑" :visible.sync="dialogFormVisible" :close-on-click-modal="false">
  244. <el-form :model="dialogRuleForm" :rules="dialogRules" size="small" ref="dialogRuleForm" label-width="120px">
  245. <el-row>
  246. <el-col :span="18">
  247. <el-form-item label="图标" prop="iconPath">
  248. <com-attachment :multiple="false" :max="1" @selected="iconUrl">
  249. <el-tooltip effect="dark" content="建议尺寸64*64" placement="top">
  250. <el-button size="mini">选择文件</el-button>
  251. </el-tooltip>
  252. </com-attachment>
  253. <com-image mode="aspectFill" width="80px" height="80px"
  254. :src="dialogRuleForm.iconPath"></com-image>
  255. </el-form-item>
  256. <el-form-item label="选择状态图标" prop="selectedIconPath">
  257. <com-attachment :multiple="false" :max="1" @selected="activeIconUrl">
  258. <el-tooltip effect="dark" content="建议尺寸64*64" placement="top">
  259. <el-button size="mini">选择文件</el-button>
  260. </el-tooltip>
  261. </com-attachment>
  262. <com-image mode="aspectFill"
  263. width="80px"
  264. height="80px"
  265. :src="dialogRuleForm.selectedIconPath">
  266. </com-image>
  267. </el-form-item>
  268. <el-form-item label="显示" prop="text">
  269. <el-switch v-model="dialogRuleForm.is_show" :active-value="1" :inactive-value="0"></el-switch>
  270. </el-form-item>
  271. <el-form-item label="名称" prop="text">
  272. <el-input v-model.trim="dialogRuleForm.text"></el-input>
  273. </el-form-item>
  274. <el-form-item label="类型" prop="open_type" style="display: none;">
  275. <el-input disabled v-model="dialogRuleForm.open_type"></el-input>
  276. </el-form-item>
  277. <el-form-item label="导航链接" prop="url">
  278. <div flex="box:last">
  279. <el-input disabled v-model="dialogRuleForm.url"></el-input>
  280. <div v-if="nowNavIndex > 1">
  281. <com-pick-link @selected="selectNavUrl" :is-show-goods-cate-select="false">
  282. <el-button>选择链接</el-button>
  283. </com-pick-link>
  284. </div>
  285. </div>
  286. </el-form-item>
  287. </el-col>
  288. </el-row>
  289. </el-form>
  290. <div slot="footer">
  291. <el-button size="small" @click="dialogFormVisible = false">取 消</el-button>
  292. <el-button size="small" type="primary" @click="dialogFormSubmit('dialogRuleForm')">提 交</el-button>
  293. </div>
  294. </el-dialog>
  295. </el-card>
  296. </div>
  297. <!-- <script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.3/Sortable.min.js"></script> -->
  298. <script src="/resources/js/Sortable.min.js"></script>
  299. <!-- CDNJS :: Vue.Draggable (https://cdnjs.com/) -->
  300. <script src="<?= Yii::$app->request->baseUrl ?>/resources/unpkg/vuedraggable@2.18.1/dist/vuedraggable.umd.min.js"></script>
  301. <script>
  302. const app = new Vue({
  303. el: '#app',
  304. data() {
  305. return {
  306. ruleForm: {
  307. bottom_background_color: '#ffffff',
  308. top_background_color: '#ffffff',
  309. top_text_color: '#000000',
  310. active_color: '#ff4544',
  311. inactive_color: '#888',
  312. // shadow: false,
  313. navs: [],
  314. },
  315. defaultForm: {
  316. bottom_background_color: '#ffffff',
  317. top_background_color: '#ffffff',
  318. top_text_color: '#000000',
  319. active_color: '#ff4544',
  320. inactive_color: '#888',
  321. recover_default: 1,
  322. navs: [],
  323. },
  324. rules: {
  325. bottom_background_color: [
  326. {required: true, message: '请选择底栏背景颜色', trigger: 'change'},
  327. ],
  328. inactive_color: [
  329. {required: true, message: '请选择文字颜色', trigger: 'change'},
  330. ],
  331. active_color: [
  332. {required: true, message: '请选择文字选中状态颜色', trigger: 'change'},
  333. ],
  334. },
  335. predefineColors: [
  336. '#000',
  337. '#fff',
  338. '#888',
  339. '#ff4544'
  340. ],
  341. btnLoading: false,
  342. cardLoading: false,
  343. isNavAction: false,//编辑删除框是否显示
  344. navIconIndex: -1,//控制导航编辑隐藏显示
  345. navEditIndex: -1, //当前编辑的导航索引
  346. dialogFormVisible: false,
  347. dialogRuleForm: {
  348. selectedIconPath: '',
  349. text: '',
  350. iconPath: '',
  351. url: '',
  352. open_type: '',
  353. params: [],
  354. is_show: 1,
  355. },
  356. navMaxCount: 5, // 导航最大数量限制
  357. nowNavIndex: 5, // 当前选的导航按钮
  358. dialogRules: {
  359. iconPath: [
  360. {required: true, message: '请选择图标', trigger: 'change'},
  361. ],
  362. selectedIconPath: [
  363. {required: true, message: '请选择选中状态图标', trigger: 'change'},
  364. ],
  365. text: [
  366. {required: true, message: '请输入导航名称', trigger: 'change'},
  367. ],
  368. url: [
  369. {required: true, message: '请选择导航链接', trigger: 'change'},
  370. ],
  371. },
  372. navCurrent: 0,
  373. };
  374. },
  375. methods: {
  376. store(formName) {
  377. this.$refs[formName].validate((valid) => {
  378. let self = this;
  379. if (valid) {
  380. self.btnLoading = true;
  381. request({
  382. params: {
  383. r: 'mall/decorate/bottom-nav'
  384. },
  385. method: 'post',
  386. data: {
  387. form: self.ruleForm,
  388. }
  389. }).then(e => {
  390. self.btnLoading = false;
  391. if (e.data.code == 0) {
  392. self.$message.success(e.data.msg);
  393. } else {
  394. self.$message.error(e.data.msg);
  395. }
  396. }).catch(e => {
  397. self.$message.error(e.data.msg);
  398. self.btnLoading = false;
  399. });
  400. } else {
  401. console.log('error submit!!');
  402. return false;
  403. }
  404. });
  405. },
  406. getDetail() {
  407. let self = this;
  408. self.cardLoading = true;
  409. request({
  410. params: {
  411. r: 'mall/decorate/bottom-nav',
  412. },
  413. method: 'get',
  414. }).then(e => {
  415. self.cardLoading = false;
  416. if (e.data.code == 0) {
  417. if (!isEmpty(e.data.data.detail)) {
  418. if (e.data.data.detail.inactive_color) {
  419. self.ruleForm = e.data.data.detail;
  420. }
  421. if (e.data.data.detail.navs) {
  422. self.ruleForm.navs = e.data.data.detail.navs;
  423. }
  424. }
  425. } else {
  426. self.$message.error(e.data.msg);
  427. }
  428. }).catch(e => {
  429. console.log(e);
  430. });
  431. },
  432. handleClick(tab, event) {
  433. console.log(tab, event);
  434. },
  435. // 鼠标移入事件
  436. navIconEnter(index) {
  437. this.navIconIndex = index;
  438. },
  439. // 鼠标离开事件
  440. navIconAway() {
  441. this.navIconIndex = -1;
  442. },
  443. // 导航图标编辑
  444. navIconEdit(index) {
  445. this.nowNavIndex = this.ruleForm.navs.length + 1;
  446. this.dialogFormVisible = true;
  447. if (index != -1) {
  448. this.nowNavIndex = index + 1;
  449. this.navEditIndex = index;
  450. this.dialogRuleForm = this.ruleForm.navs[index]
  451. }
  452. },
  453. // 弹框关闭事件回调
  454. dialogColse() {
  455. this.navEditIndex = -1;
  456. this.clearDialogData();
  457. },
  458. clearDialogData() {
  459. this.dialogRuleForm = {
  460. selectedIconPath: '',
  461. text: '',
  462. iconPath: '',
  463. url: '',
  464. open_type: '',
  465. params: [],
  466. };
  467. },
  468. // 导航图标删除
  469. navIconDestroy(index) {
  470. this.ruleForm.navs.splice(index, 1)
  471. },
  472. dialogFormSubmit(formName) {
  473. this.$refs[formName].validate((valid) => {
  474. let self = this;
  475. if (valid) {
  476. self.dialogFormVisible = false;
  477. if (self.navEditIndex != -1) {
  478. self.ruleForm.navs[self.navEditIndex] = self.dialogRuleForm;
  479. } else {
  480. self.ruleForm.navs.push(self.dialogRuleForm);
  481. }
  482. self.navEditIndex = -1;
  483. this.clearDialogData();
  484. } else {
  485. console.log('error submit!!');
  486. return false;
  487. }
  488. });
  489. },
  490. // 添加图标
  491. iconUrl(e) {
  492. if (e.length) {
  493. this.dialogRuleForm.iconPath = e[0].url
  494. this.$refs.dialogRuleForm.validateField('iconPath');
  495. }
  496. },
  497. // 添加选择状态图标
  498. activeIconUrl(e) {
  499. if (e.length) {
  500. this.dialogRuleForm.selectedIconPath = e[0].url
  501. this.$refs.dialogRuleForm.validateField('selectedIconPath');
  502. }
  503. },
  504. // 导航链接选择
  505. selectNavUrl(e) {
  506. let self = this;
  507. e.forEach(function (item) {
  508. let open_url = item.route;
  509. if (item.open_type === 'web') {
  510. open_url = item.params.link;
  511. }
  512. if (item.open_type === 'applet') {
  513. open_url = item.params.app_path;
  514. }
  515. if (item.open_type === 'call') {
  516. open_url = item.params.telphone;
  517. }
  518. if (item.open_type === 'wechat_video_account') {
  519. open_url = item.params.feedId;
  520. }
  521. self.dialogRuleForm.url = open_url;
  522. self.dialogRuleForm.open_type = item.params.open_type;
  523. self.dialogRuleForm.params = item.params;
  524. });
  525. },
  526. // 恢复默认
  527. restoreDefault() {
  528. let self = this;
  529. self.$confirm('恢复默认, 是否继续?', '提示', {
  530. confirmButtonText: '确定',
  531. cancelButtonText: '取消',
  532. type: 'warning'
  533. }).then(() => {
  534. self.btnLoading = true;
  535. request({
  536. params: {
  537. r: 'mall/decorate/bottom-nav',
  538. },
  539. method: 'post',
  540. data: {
  541. form: self.defaultForm
  542. }
  543. }).then(e => {
  544. self.btnLoading = false;
  545. if (e.data.code === 0) {
  546. self.$message.success(e.data.msg);
  547. self.getDetail();
  548. } else {
  549. self.$message.error(e.data.msg);
  550. }
  551. }).catch(e => {
  552. console.log(e);
  553. });
  554. }).catch(() => {
  555. self.$message.info('已取消')
  556. });
  557. },
  558. navClick(index) {
  559. this.navCurrent = index
  560. }
  561. },
  562. mounted: function () {
  563. this.getDetail();
  564. }
  565. });
  566. </script>