index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. <template>
  2. <div class="app-container">
  3. <doc-alert title="公众号菜单" url="https://doc.iocoder.cn/mp/menu/" />
  4. <!-- 搜索工作栏 -->
  5. <el-form ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  6. <el-form-item label="公众号" prop="accountId">
  7. <el-select v-model="accountId" placeholder="请选择公众号">
  8. <el-option
  9. v-for="item in accountList"
  10. :key="parseInt(item.id)"
  11. :label="item.name"
  12. :value="parseInt(item.id)"
  13. />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item>
  17. <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  18. <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  19. </el-form-item>
  20. </el-form>
  21. <div class="public-account-management clearfix" v-loading="loading">
  22. <!--左边配置菜单-->
  23. <div class="left">
  24. <div class="weixin-hd">
  25. <div class="weixin-title">{{ name }}</div>
  26. </div>
  27. <div class="weixin-menu menu_main clearfix">
  28. <div class="menu_bottom" v-for="(item, i) of menuList" :key="i">
  29. <!-- 一级菜单 -->
  30. <div @click="menuClick(i, item)" class="menu_item" :class="{ active: isActive === i }"
  31. ><Icon icon="ep:fold" color="black" />{{ item.name }}
  32. </div>
  33. <!-- 以下为二级菜单-->
  34. <div class="submenu" v-if="isSubMenuFlag === i">
  35. <div class="subtitle menu_bottom" v-for="(subItem, k) in item.children" :key="k">
  36. <div
  37. class="menu_subItem"
  38. v-if="item.children"
  39. :class="{ active: isSubMenuActive === i + '' + k }"
  40. @click="subMenuClick(subItem, i, k)"
  41. >
  42. {{ subItem.name }}
  43. </div>
  44. </div>
  45. <!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号 -->
  46. <div
  47. class="menu_bottom menu_addicon"
  48. v-if="!item.children || item.children.length < 5"
  49. @click="addSubMenu(i, item)"
  50. >
  51. <Icon icon="ep:plus" />
  52. </div>
  53. </div>
  54. </div>
  55. <!-- 一级菜单加号 -->
  56. <div class="menu_bottom menu_addicon" v-if="menuList.length < 3" @click="addMenu">
  57. <Icon icon="ep:plus" />
  58. </div>
  59. </div>
  60. <div class="save_div">
  61. <el-button
  62. class="save_btn"
  63. type="success"
  64. size="small"
  65. @click="handleSave"
  66. v-hasPermi="['mp:menu:save']"
  67. >保存并发布菜单</el-button
  68. >
  69. <el-button
  70. class="save_btn"
  71. type="danger"
  72. size="small"
  73. @click="handleDelete"
  74. v-hasPermi="['mp:menu:delete']"
  75. >清空菜单</el-button
  76. >
  77. </div>
  78. </div>
  79. <!--右边配置-->
  80. <div v-if="showRightFlag" class="right">
  81. <div class="configure_page">
  82. <div class="delete_btn">
  83. <el-button size="small" type="danger" @click="handleDeleteMenu(tempObj)"
  84. >删除当前菜单<Icon icon="ep:delete"
  85. /></el-button>
  86. </div>
  87. <div>
  88. <span>菜单名称:</span>
  89. <el-input
  90. class="input_width"
  91. v-model="tempObj.name"
  92. placeholder="请输入菜单名称"
  93. :maxlength="nameMaxLength"
  94. clearable
  95. />
  96. </div>
  97. <div v-if="showConfigureContent">
  98. <div class="menu_content">
  99. <span>菜单标识:</span>
  100. <el-input
  101. class="input_width"
  102. v-model="tempObj.menuKey"
  103. placeholder="请输入菜单 KEY"
  104. clearable
  105. />
  106. </div>
  107. <div class="menu_content">
  108. <span>菜单内容:</span>
  109. <el-select v-model="tempObj.type" clearable placeholder="请选择" class="menu_option">
  110. <el-option
  111. v-for="item in menuOptions"
  112. :label="item.label"
  113. :value="item.value"
  114. :key="item.value"
  115. />
  116. </el-select>
  117. </div>
  118. <div class="configur_content" v-if="tempObj.type === 'view'">
  119. <span>跳转链接:</span>
  120. <el-input
  121. class="input_width"
  122. v-model="tempObj.url"
  123. placeholder="请输入链接"
  124. clearable
  125. />
  126. </div>
  127. <div class="configur_content" v-if="tempObj.type === 'miniprogram'">
  128. <div class="applet">
  129. <span>小程序的 appid :</span>
  130. <el-input
  131. class="input_width"
  132. v-model="tempObj.miniProgramAppId"
  133. placeholder="请输入小程序的appid"
  134. clearable
  135. />
  136. </div>
  137. <div class="applet">
  138. <span>小程序的页面路径:</span>
  139. <el-input
  140. class="input_width"
  141. v-model="tempObj.miniProgramPagePath"
  142. placeholder="请输入小程序的页面路径,如:pages/index"
  143. clearable
  144. />
  145. </div>
  146. <div class="applet">
  147. <span>小程序的备用网页:</span>
  148. <el-input
  149. class="input_width"
  150. v-model="tempObj.url"
  151. placeholder="不支持小程序的老版本客户端将打开本网页"
  152. clearable
  153. />
  154. </div>
  155. <p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
  156. </div>
  157. <div class="configur_content" v-if="tempObj.type === 'article_view_limited'">
  158. <el-row>
  159. <div class="select-item" v-if="tempObj && tempObj.replyArticles">
  160. <WxNews :articles="tempObj.replyArticles" />
  161. <el-row class="ope-row" justify="center" align="middle">
  162. <el-button type="danger" circle @click="deleteMaterial"
  163. ><icon icon="ep:delete"
  164. /></el-button>
  165. </el-row>
  166. </div>
  167. <div v-else>
  168. <el-row justify="center">
  169. <el-col :span="24" style="text-align: center">
  170. <el-button type="success" @click="openMaterial">
  171. 素材库选择<Icon icon="ep:circle-check" />
  172. </el-button>
  173. </el-col>
  174. </el-row>
  175. </div>
  176. <el-dialog title="选择图文" v-model="dialogNewsVisible" width="90%">
  177. <WxMaterialSelect
  178. :objData="{ type: 'news', accountId: accountId }"
  179. @select-material="selectMaterial"
  180. />
  181. </el-dialog>
  182. </el-row>
  183. </div>
  184. <div
  185. class="configur_content"
  186. v-if="tempObj.type === 'click' || tempObj.type === 'scancode_waitmsg'"
  187. >
  188. <WxReplySelect :objData="tempObj.reply" v-if="hackResetWxReplySelect" />
  189. </div>
  190. </div>
  191. </div>
  192. </div>
  193. <!-- 一进页面就显示的默认页面,当点击左边按钮的时候,就不显示了-->
  194. <div v-else class="right">
  195. <p>请选择菜单配置</p>
  196. </div>
  197. </div>
  198. </div>
  199. </template>
  200. <script setup>
  201. import { ref, nextTick } from 'vue'
  202. import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
  203. import WxNews from '@/views/mp/components/wx-news/main.vue'
  204. import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
  205. import { deleteMenu, getMenuList, saveMenu } from '@/api/mp/menu'
  206. import { getSimpleAccountList } from '@/api/mp/account'
  207. import { handleTree } from '@/utils/tree'
  208. import menuOptions from './menuOptions'
  209. const message = useMessage()
  210. // ======================== 列表查询 ========================
  211. // 遮罩层
  212. const loading = ref(true)
  213. // 显示搜索条件
  214. const showSearch = ref(true)
  215. // 公众号Id
  216. const accountId = ref(undefined)
  217. // 公众号名
  218. const name = ref('')
  219. const menuList = ref({ children: [] })
  220. // const menuList = ref(menuListData)
  221. // ======================== 菜单操作 ========================
  222. const isActive = ref(-1) // 一级菜单点中样式
  223. const isSubMenuActive = ref(-1) // 一级菜单点中样式
  224. const isSubMenuFlag = ref(-1) // 二级菜单显示标志
  225. // ======================== 菜单编辑 ========================
  226. const showRightFlag = ref(false) // 右边配置显示默认详情还是配置详情
  227. const nameMaxLength = ref(0) // 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符;
  228. const showConfigureContent = ref(true) // 是否展示配置内容;如果有子菜单,就不显示配置内容
  229. const hackResetWxReplySelect = ref(false) // 重置 WxReplySelect 组件
  230. const tempObj = ref({}) // 右边临时变量,作为中间值牵引关系
  231. const tempSelfObj = ref({
  232. // 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数
  233. })
  234. const dialogNewsVisible = ref(false) // 跳转图文时的素材选择弹窗
  235. // 公众号账号列表
  236. const accountList = ref([])
  237. onMounted(async () => {
  238. accountList.value = await getSimpleAccountList()
  239. // 选中第一个
  240. if (accountList.value.length > 0) {
  241. // @ts-ignore
  242. setAccountId(accountList.value[0].id)
  243. }
  244. await getList()
  245. })
  246. // ======================== 列表查询 ========================
  247. /** 设置账号编号 */
  248. const setAccountId = (id) => {
  249. accountId.value = id
  250. name.value = accountList.value.find((item) => item.id === accountId.value)?.name
  251. }
  252. const getList = async () => {
  253. loading.value = false
  254. getMenuList(accountId.value)
  255. .then((response) => {
  256. const menuData = convertMenuList(response)
  257. menuList.value = handleTree(menuData, 'id')
  258. })
  259. .finally(() => {
  260. loading.value = false
  261. })
  262. }
  263. /** 搜索按钮操作 */
  264. const handleQuery = () => {
  265. resetForm()
  266. // 默认选中第一个
  267. if (accountId.value) {
  268. setAccountId(accountId.value)
  269. }
  270. getList()
  271. }
  272. /** 重置按钮操作 */
  273. const resetQuery = () => {
  274. resetForm()
  275. // 默认选中第一个
  276. if (accountList.value.length > 0) {
  277. setAccountId(accountList.value[0].id)
  278. }
  279. handleQuery()
  280. }
  281. // 将后端返回的 menuList,转换成前端的 menuList
  282. const convertMenuList = (list) => {
  283. if (!list) return []
  284. const menuList = []
  285. list.forEach((item) => {
  286. const menu = {
  287. ...item
  288. }
  289. if (item.type === 'click' || item.type === 'scancode_waitmsg') {
  290. delete menu.replyMessageType
  291. delete menu.replyContent
  292. delete menu.replyMediaId
  293. delete menu.replyMediaUrl
  294. delete menu.replyDescription
  295. delete menu.replyArticles
  296. menu.reply = {
  297. type: item.replyMessageType,
  298. accountId: item.accountId,
  299. content: item.replyContent,
  300. mediaId: item.replyMediaId,
  301. url: item.replyMediaUrl,
  302. title: item.replyTitle,
  303. description: item.replyDescription,
  304. thumbMediaId: item.replyThumbMediaId,
  305. thumbMediaUrl: item.replyThumbMediaUrl,
  306. articles: item.replyArticles,
  307. musicUrl: item.replyMusicUrl,
  308. hqMusicUrl: item.replyHqMusicUrl
  309. }
  310. }
  311. menuList.push(menu)
  312. })
  313. return menuList
  314. }
  315. // 重置表单,清空表单数据
  316. const resetForm = () => {
  317. // 菜单操作
  318. isActive.value = -1
  319. isSubMenuActive.value = -1
  320. isSubMenuFlag.value = -1
  321. // 菜单编辑
  322. showRightFlag.value = false
  323. nameMaxLength.value = 0
  324. showConfigureContent.value = 0
  325. hackResetWxReplySelect.value = false
  326. tempObj.value = {}
  327. tempSelfObj.value = {}
  328. dialogNewsVisible.value = false
  329. }
  330. // ======================== 菜单操作 ========================
  331. // 一级菜单点击事件
  332. const menuClick = (i, item) => {
  333. // 右侧的表单相关
  334. resetEditor()
  335. showRightFlag.value = true // 右边菜单
  336. tempObj.value = item // 这个如果放在顶部,flag 会没有。因为重新赋值了。
  337. tempSelfObj.value.grand = '1' // 表示一级菜单
  338. tempSelfObj.value.index = i // 表示一级菜单索引
  339. nameMaxLength.value = 4
  340. showConfigureContent.value = !(item.children && item.children.length > 0) // 有子菜单,就不显示配置内容
  341. // 左侧的选中
  342. isActive.value = i // 一级菜单选中样式
  343. isSubMenuFlag.value = i // 二级菜单显示标志
  344. isSubMenuActive.value = -1 // 二级菜单去除选中样式
  345. }
  346. // 二级菜单点击事件
  347. const subMenuClick = (subItem, index, k) => {
  348. // 右侧的表单相关
  349. resetEditor()
  350. showRightFlag.value = true // 右边菜单
  351. console.log(subItem)
  352. tempObj.value = subItem // 将点击的数据放到临时变量,对象有引用作用
  353. tempSelfObj.value.grand = '2' // 表示二级菜单
  354. tempSelfObj.value.index = index // 表示一级菜单索引
  355. tempSelfObj.value.secondIndex = k // 表示二级菜单索引
  356. nameMaxLength.value = 7
  357. showConfigureContent.value = true
  358. // 左侧的选中
  359. isActive.value = -1 // 一级菜单去除样式
  360. isSubMenuActive.value = index + '' + k // 二级菜单选中样式
  361. }
  362. // 添加横向一级菜单
  363. const addMenu = () => {
  364. const menuKeyLength = menuList.value.length
  365. const addButton = {
  366. name: '菜单名称',
  367. children: [],
  368. reply: {
  369. // 用于存储回复内容
  370. type: 'text',
  371. accountId: accountId.value // 保证组件里,可以使用到对应的公众号
  372. }
  373. }
  374. menuList.value[menuKeyLength] = addButton
  375. menuClick(menuKeyLength.value - 1, addButton)
  376. }
  377. // 添加横向二级菜单;item 表示要操作的父菜单
  378. const addSubMenu = (i, item) => {
  379. // 清空父菜单的属性,因为它只需要 name 属性即可
  380. if (!item.children || item.children.length <= 0) {
  381. item.children = []
  382. delete item['type']
  383. delete item['menuKey']
  384. delete item['miniProgramAppId']
  385. delete item['miniProgramPagePath']
  386. delete item['url']
  387. delete item['reply']
  388. delete item['articleId']
  389. delete item['replyArticles']
  390. // 关闭配置面板
  391. showConfigureContent.value = false
  392. }
  393. let subMenuKeyLength = item.children.length // 获取二级菜单key长度
  394. let addButton = {
  395. name: '子菜单名称',
  396. reply: {
  397. // 用于存储回复内容
  398. type: 'text',
  399. accountId: accountId.value // 保证组件里,可以使用到对应的公众号
  400. }
  401. }
  402. item.children[subMenuKeyLength] = addButton
  403. subMenuClick(item.children[subMenuKeyLength], i, subMenuKeyLength)
  404. }
  405. // 删除当前菜单
  406. const handleDeleteMenu = async () => {
  407. try {
  408. await message.confirm('确定要删除吗?')
  409. if (tempSelfObj.value.grand === '1') {
  410. // 一级菜单的删除方法
  411. menuList.value.splice(tempSelfObj.value.index, 1)
  412. } else if (tempSelfObj.value.grand === '2') {
  413. // 二级菜单的删除方法
  414. menuList.value[tempSelfObj.value.index].children.splice(tempSelfObj.value.secondIndex, 1)
  415. }
  416. // 提示
  417. message.notifySuccess('删除成功')
  418. // 处理菜单的选中
  419. tempObj.value = {}
  420. showRightFlag.value = false
  421. isActive.value = -1
  422. isSubMenuActive.value = -1
  423. } catch {}
  424. }
  425. // ======================== 菜单编辑 ========================
  426. const handleSave = async () => {
  427. try {
  428. await message.confirm('确定要删除吗?')
  429. loading.value = true
  430. await saveMenu(accountId.value, convertMenuFormList())
  431. getList()
  432. message.notifySuccess('发布成功')
  433. } finally {
  434. loading.value = false
  435. }
  436. }
  437. // 表单 Editor 重置
  438. const resetEditor = () => {
  439. hackResetWxReplySelect.value = false // 销毁组件
  440. nextTick(() => {
  441. console.log('nextTick')
  442. hackResetWxReplySelect.value = true // 重建组件
  443. })
  444. }
  445. const handleDelete = async () => {
  446. try {
  447. await message.confirm('确定要删除吗?')
  448. loading.value = true
  449. await deleteMenu(accountId.value)
  450. handleQuery()
  451. message.notifySuccess('清空成功')
  452. } finally {
  453. loading.value = false
  454. }
  455. }
  456. // 将前端的 menuList,转换成后端接收的 menuList
  457. const convertMenuFormList = () => {
  458. const result = []
  459. menuList.value.forEach((item) => {
  460. let menu = convertMenuForm(item)
  461. result.push(menu)
  462. // 处理子菜单
  463. if (!item.children || item.children.length <= 0) {
  464. return
  465. }
  466. menu.children = []
  467. item.children.forEach((subItem) => {
  468. menu.children.push(convertMenuForm(subItem))
  469. })
  470. })
  471. return result
  472. }
  473. // 将前端的 menu,转换成后端接收的 menu
  474. const convertMenuForm = (menu) => {
  475. let result = {
  476. ...menu,
  477. children: undefined, // 不处理子节点
  478. reply: undefined // 稍后复制
  479. }
  480. if (menu.type === 'click' || menu.type === 'scancode_waitmsg') {
  481. result.replyMessageType = menu.reply.type
  482. result.replyContent = menu.reply.content
  483. result.replyMediaId = menu.reply.mediaId
  484. result.replyMediaUrl = menu.reply.url
  485. result.replyTitle = menu.reply.title
  486. result.replyDescription = menu.reply.description
  487. result.replyThumbMediaId = menu.reply.thumbMediaId
  488. result.replyThumbMediaUrl = menu.reply.thumbMediaUrl
  489. result.replyArticles = menu.reply.articles
  490. result.replyMusicUrl = menu.reply.musicUrl
  491. result.replyHqMusicUrl = menu.reply.hqMusicUrl
  492. }
  493. return result
  494. }
  495. // ======================== 菜单编辑(素材选择) ========================
  496. const openMaterial = () => {
  497. dialogNewsVisible.value = true
  498. }
  499. const selectMaterial = (item) => {
  500. const articleId = item.articleId
  501. const articles = item.content.newsItem
  502. // 提示,针对多图文
  503. if (articles.length > 1) {
  504. message.alertWarning('您选择的是多图文,将默认跳转第一篇')
  505. }
  506. dialogNewsVisible.value = false
  507. // 设置菜单的回复
  508. tempObj.value.articleId = articleId
  509. tempObj.value.replyArticles = []
  510. articles.forEach((article) => {
  511. tempObj.value.replyArticles.push({
  512. title: article.title,
  513. description: article.digest,
  514. picUrl: article.picUrl,
  515. url: article.url
  516. })
  517. })
  518. }
  519. const deleteMaterial = () => {
  520. delete tempObj.value['articleId']
  521. delete tempObj.value['replyArticles']
  522. }
  523. </script>
  524. <!--本组件样式-->
  525. <style lang="scss" scoped="scoped">
  526. /* 公共颜色变量 */
  527. .clearfix {
  528. *zoom: 1;
  529. }
  530. .clearfix::after {
  531. content: '';
  532. display: table;
  533. clear: both;
  534. }
  535. div {
  536. text-align: left;
  537. }
  538. .weixin-hd {
  539. color: #fff;
  540. text-align: center;
  541. position: relative;
  542. bottom: 426px;
  543. left: 0px;
  544. width: 300px;
  545. height: 64px;
  546. background: transparent url('./assets/menu_head.png') no-repeat 0 0;
  547. background-position: 0 0;
  548. background-size: 100%;
  549. }
  550. .weixin-title {
  551. color: #fff;
  552. font-size: 14px;
  553. width: 100%;
  554. text-align: center;
  555. position: absolute;
  556. top: 33px;
  557. left: 0px;
  558. }
  559. .weixin-menu {
  560. background: transparent url('./assets/menu_foot.png') no-repeat 0 0;
  561. padding-left: 43px;
  562. font-size: 12px;
  563. }
  564. .menu_option {
  565. width: 40% !important;
  566. }
  567. .public-account-management {
  568. min-width: 1200px;
  569. width: 1200px;
  570. margin: 0 auto;
  571. .left {
  572. float: left;
  573. display: inline-block;
  574. width: 350px;
  575. height: 715px;
  576. background: url('./assets/iphone_backImg.png') no-repeat;
  577. background-size: 100% auto;
  578. padding: 518px 25px 88px;
  579. position: relative;
  580. box-sizing: border-box;
  581. /*第一级菜单*/
  582. .menu_main {
  583. .menu_bottom {
  584. position: relative;
  585. float: left;
  586. display: inline-block;
  587. box-sizing: border-box;
  588. width: 85.5px;
  589. text-align: center;
  590. border: 1px solid #ebedee;
  591. background-color: #fff;
  592. cursor: pointer;
  593. &.menu_addicon {
  594. height: 46px;
  595. line-height: 46px;
  596. }
  597. .menu_item {
  598. height: 44px;
  599. line-height: 44px;
  600. // text-align: center;
  601. box-sizing: border-box;
  602. width: 100%;
  603. display: flex;
  604. align-items: center;
  605. justify-content: center;
  606. &.active {
  607. border: 1px solid #2bb673;
  608. }
  609. }
  610. .menu_subItem {
  611. height: 44px;
  612. line-height: 44px;
  613. text-align: center;
  614. box-sizing: border-box;
  615. &.active {
  616. border: 1px solid #2bb673;
  617. }
  618. }
  619. }
  620. i {
  621. color: #2bb673;
  622. }
  623. /*第二级菜单*/
  624. .submenu {
  625. position: absolute;
  626. width: 85.5px;
  627. bottom: 45px;
  628. .subtitle {
  629. background-color: #fff;
  630. box-sizing: border-box;
  631. }
  632. }
  633. }
  634. .save_div {
  635. margin-top: 15px;
  636. text-align: center;
  637. .save_btn {
  638. bottom: 20px;
  639. left: 100px;
  640. }
  641. }
  642. }
  643. /*右边菜单内容*/
  644. .right {
  645. float: left;
  646. width: 63%;
  647. background-color: #e8e7e7;
  648. padding: 20px;
  649. margin-left: 20px;
  650. -webkit-box-sizing: border-box;
  651. box-sizing: border-box;
  652. .configure_page {
  653. .delete_btn {
  654. text-align: right;
  655. margin-bottom: 15px;
  656. }
  657. .menu_content {
  658. margin-top: 20px;
  659. }
  660. .configur_content {
  661. margin-top: 20px;
  662. background-color: #fff;
  663. padding: 20px 10px;
  664. border-radius: 5px;
  665. }
  666. .blue {
  667. color: #29b6f6;
  668. margin-top: 10px;
  669. }
  670. .applet {
  671. margin-bottom: 20px;
  672. span {
  673. width: 20%;
  674. }
  675. }
  676. .input_width {
  677. width: 40%;
  678. }
  679. .material {
  680. .input_width {
  681. width: 30%;
  682. }
  683. .el-textarea {
  684. width: 80%;
  685. }
  686. }
  687. }
  688. }
  689. .el-input {
  690. width: 70%;
  691. margin-right: 2%;
  692. }
  693. }
  694. </style>
  695. <!--素材样式-->
  696. <style lang="scss" scoped>
  697. .pagination {
  698. text-align: right;
  699. margin-right: 25px;
  700. }
  701. .select-item {
  702. width: 280px;
  703. padding: 10px;
  704. margin: 0 auto 10px auto;
  705. border: 1px solid #eaeaea;
  706. }
  707. .select-item2 {
  708. padding: 10px;
  709. margin: 0 auto 10px auto;
  710. border: 1px solid #eaeaea;
  711. }
  712. .ope-row {
  713. padding-top: 10px;
  714. text-align: center;
  715. }
  716. .item-name {
  717. font-size: 12px;
  718. overflow: hidden;
  719. text-overflow: ellipsis;
  720. white-space: nowrap;
  721. text-align: center;
  722. }
  723. </style>