layout.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <template lang="pug">
  2. .dashboard(:class="{'is-inapp': isInApp}")
  3. client-only
  4. .sidebar-page
  5. .sidebar-layout
  6. b-sidebar.brd-sidebar(
  7. type="is-dark"
  8. :mobile="expanded ? 'fullwidth' : 'reduce'"
  9. :position="isInApp ? 'fixed' : 'static'"
  10. :reduce="reduce"
  11. :fullheight="true"
  12. open
  13. )
  14. .inner
  15. .brand(v-if="!isInApp")
  16. .logo
  17. .text
  18. span Dashboard
  19. sup Beta
  20. .navbar-burger.burger(v-else @click="triggerSidebar")
  21. span
  22. span
  23. span
  24. b-menu.is-custom-mobile
  25. b-menu-list
  26. b-menu-item(
  27. label="概览"
  28. icon-pack="progico"
  29. icon="progico-home"
  30. tag="router-link"
  31. to="/dashboard"
  32. :replace="isInApp"
  33. :active="curRoutePath === '/'"
  34. @click.native="onMenuClick"
  35. )
  36. b-menu-item(
  37. label="我的API"
  38. icon-pack="progico"
  39. icon="progico-api"
  40. tag="router-link"
  41. to="/dashboard/apis"
  42. :replace="isInApp"
  43. :active="curRoutePath === '/apis'"
  44. @click.native="onMenuClick"
  45. )
  46. //- b-menu-item(
  47. label="统计中心"
  48. icon-pack="progico"
  49. icon="progico-stats"
  50. tag="router-link"
  51. to="/dashboard/stats"
  52. :replace="isInApp"
  53. :active="curRoutePath === '/stats'"
  54. @click.native="onMenuClick"
  55. )
  56. b-menu-item(
  57. label="调试工具"
  58. icon-pack="progico"
  59. icon="progico-debug"
  60. tag="router-link"
  61. to="/dashboard/inspector"
  62. :replace="isInApp"
  63. :active="curRoutePath === '/inspector'"
  64. @click.native="onMenuClick"
  65. )
  66. .dashboard-container
  67. b-navbar(v-if="!isInApp")
  68. template(slot="end")
  69. b-navbar-item(href="/") 返回首页
  70. .navbar-split
  71. NavUserCell(
  72. v-if="userInfo"
  73. :user-info="userInfo"
  74. :clickable="false"
  75. )
  76. router-view.dashboard-main
  77. </template>
  78. <script lang="ts">
  79. import Vue from 'vue'
  80. import NavUserCell from '../../components/NavUserCell.vue'
  81. import bridge from '../../utils/bridge'
  82. export default Vue.extend({
  83. layout: 'kaifain_v2',
  84. components: {
  85. NavUserCell
  86. },
  87. data() {
  88. return {
  89. reduce: false,
  90. isInApp: false,
  91. expanded: false
  92. }
  93. },
  94. head: {
  95. title: '控制台'
  96. },
  97. computed: {
  98. userInfo(): any {
  99. return this.$store.state.userinfo
  100. },
  101. curRoutePath(): string {
  102. return this.$route.path.replace(/^\/dashboard\/?/, '/')
  103. }
  104. },
  105. methods: {
  106. triggerSidebar() {
  107. this.expanded = !this.expanded
  108. },
  109. onMenuClick() {
  110. if (this.expanded) {
  111. setTimeout(() => {
  112. this.expanded = false
  113. }, 32)
  114. }
  115. }
  116. },
  117. created() {
  118. if (process.client) {
  119. // @ts-ignore
  120. this.isInApp = bridge.isInApp || false
  121. }
  122. }
  123. })
  124. </script>
  125. <style lang="scss">
  126. @import '../../assets/styles/vars';
  127. $dashboard-bg: #f9f9fa;
  128. .dashboard {
  129. background: $dashboard-bg;
  130. .page-header {
  131. margin: -1.25rem 0.25rem 2rem 0.25rem;
  132. .title {
  133. font-size: 1.5rem;
  134. margin: 0 !important;
  135. }
  136. .actions {
  137. margin-bottom: -0.25rem;
  138. }
  139. }
  140. .modal {
  141. z-index: 42;
  142. }
  143. .sidebar-page {
  144. display: flex;
  145. flex-direction: column;
  146. width: 100%;
  147. min-height: 100%;
  148. .sidebar-layout {
  149. display: flex;
  150. flex-direction: row;
  151. min-height: 100%;
  152. }
  153. }
  154. .navbar {
  155. background: $dashboard-bg;
  156. color: #777;
  157. position: sticky;
  158. top: 0;
  159. }
  160. .navbar-end {
  161. padding-right: 1rem;
  162. }
  163. .navbar-item {
  164. font-size: 0.875rem;
  165. color: #777;
  166. }
  167. .navbar-split {
  168. background: #e7e7e7;
  169. width: 1px;
  170. height: 16px;
  171. margin: 1px 12px 0;
  172. align-self: center;
  173. }
  174. .dashboard-container {
  175. flex: 1;
  176. overflow-y: scroll;
  177. height: 100vh;
  178. }
  179. .dashboard-main {
  180. padding: 2rem;
  181. }
  182. .section {
  183. padding: 0;
  184. }
  185. .card {
  186. background: #fff;
  187. border-radius: 6px;
  188. box-shadow: 0 1px 6px rgba(0,0,0,0.02);
  189. .header {
  190. padding: 1.5rem;
  191. display: flex;
  192. justify-content: space-between;
  193. align-items: center;
  194. + .content {
  195. padding-top: 0;
  196. }
  197. }
  198. .caption {
  199. color: $ink;
  200. font-size: 1rem;
  201. font-weight: 500;
  202. }
  203. .content {
  204. padding: 1.5rem 1.5rem 2rem;
  205. min-height: 6rem;
  206. > .empty {
  207. font-size: 0.875rem;
  208. color: #999;
  209. text-align: center;
  210. padding: 1.5rem;
  211. }
  212. .is-link {
  213. color: $primary;
  214. }
  215. }
  216. .view-all {
  217. color: #999;
  218. font-size: 0.875rem;
  219. padding: 1rem 1.75rem;
  220. display: flex;
  221. align-items: center;
  222. border-top: 1px solid #eee;
  223. .icon {
  224. font-size: 0.8em;
  225. }
  226. &:hover {
  227. color: $primary;
  228. }
  229. }
  230. }
  231. .api-list {
  232. padding: 0 1.5rem;
  233. }
  234. .common-table {
  235. .table {
  236. font-size: 0.875rem;
  237. line-height: 1.35;
  238. td,
  239. th {
  240. vertical-align: middle;
  241. }
  242. th {
  243. padding: 0.75em 1em;
  244. border-bottom: 1px solid #eaeaea;
  245. }
  246. td {
  247. padding: 0.5em 1em;
  248. border-color: #f6f6f6;
  249. &::before {
  250. white-space: nowrap;
  251. margin-right: 1rem;
  252. }
  253. }
  254. .control {
  255. padding-right: 1.5rem;
  256. }
  257. }
  258. .skeleton-cell {
  259. padding: 0.5rem 0;
  260. }
  261. .empty {
  262. text-align: center;
  263. color: #8c8c8c;
  264. padding: 1rem;
  265. }
  266. .key {
  267. color: #777;
  268. }
  269. .value {
  270. word-break: break-all;
  271. }
  272. .desc {
  273. font-size: 0.9em;
  274. color: #777;
  275. padding-bottom: 0.5em;
  276. display: inline-block;
  277. word-break: break-all;
  278. }
  279. }
  280. &.is-inapp {
  281. .page-header {
  282. .title {
  283. display: none;
  284. }
  285. }
  286. .dashboard-container {
  287. padding-left: 56px;
  288. }
  289. }
  290. @media screen and (max-width: 1023px) {
  291. .navbar-menu {
  292. background: $dashboard-bg;
  293. box-shadow: none;
  294. }
  295. .navbar-split {
  296. height: 1px;
  297. width: auto;
  298. margin: 8px 12px;
  299. }
  300. }
  301. @media screen and (max-width: 768px) {
  302. .b-table .table-wrapper.has-mobile-cards {
  303. .control {
  304. width: 66%;
  305. }
  306. tr {
  307. border-radius: 4px;
  308. box-shadow: 0 1px 6px rgba(51, 49, 49, 0.03);
  309. }
  310. }
  311. .common-table .table {
  312. .control {
  313. padding-right: 0;
  314. }
  315. }
  316. .dashboard-main {
  317. padding: 0.25rem 0.25rem 2rem;
  318. }
  319. .page-header {
  320. margin: -0.25rem 1.25rem 1.5rem 1.25rem;
  321. }
  322. .card {
  323. .header {
  324. padding-top: 1.25rem;
  325. padding-bottom: 1.25rem;
  326. }
  327. .header,
  328. .content {
  329. padding-left: 1rem;
  330. padding-right: 1rem;
  331. }
  332. .caption {
  333. font-size: 0.9375rem;
  334. }
  335. }
  336. }
  337. @media screen and (max-width: 480px) {
  338. .is-float-btn {
  339. position: fixed;
  340. z-index: 30;
  341. bottom: 0.5rem;
  342. right: 16px;
  343. width: calc(100% - 88px);
  344. }
  345. .api-list {
  346. padding: 0 1.25rem;
  347. }
  348. .modal {
  349. justify-content: flex-start;
  350. }
  351. &.is-inapp {
  352. .page-header {
  353. margin: 0;
  354. }
  355. }
  356. }
  357. }
  358. .b-sidebar.brd-sidebar {
  359. .sidebar-content {
  360. width: 240px;
  361. > .inner {
  362. padding: 1em;
  363. }
  364. .navbar-burger {
  365. color: #fff;
  366. margin: -0.75rem -0.2rem 0.25rem -0.2rem;
  367. }
  368. &.is-dark {
  369. background: $ink;
  370. box-shadow: none;
  371. }
  372. &.is-fixed {
  373. transition: width 0.25s ease;
  374. }
  375. }
  376. .menu-list {
  377. a {
  378. margin-bottom: 0.5rem;
  379. padding: 0.75em 0.875em;
  380. color: #808080;
  381. white-space: nowrap;
  382. &.is-active {
  383. background: $primary;
  384. color: #fff;
  385. }
  386. }
  387. .icon + span {
  388. margin-left: 1rem;
  389. font-size: 0.9375rem;
  390. }
  391. }
  392. .brand {
  393. display: flex;
  394. align-items: center;
  395. color: #fff;
  396. margin: 0 0.5rem 2rem;
  397. .logo {
  398. background: url('../../assets/img/logo.png') center left no-repeat;
  399. background-size: auto 100%;
  400. width: 34px;
  401. height: 34px;
  402. opacity: 0.98;
  403. }
  404. .text {
  405. font-weight: 600;
  406. margin-left: 16px;
  407. sup {
  408. font-size: 0.625em;
  409. font-weight: 500;
  410. vertical-align: top;
  411. margin: 0 -5px 0 5px;
  412. color: lighten($primary, 4);
  413. display: inline-block;
  414. top: 0;
  415. }
  416. }
  417. }
  418. @media screen and (max-width: 768px) {
  419. .sidebar-content {
  420. > .inner {
  421. padding-left: 0.375rem;
  422. padding-right: 0.375rem;
  423. }
  424. &.is-fullwidth-mobile {
  425. width: 224px;
  426. }
  427. &.is-mini-mobile {
  428. width: 56px;
  429. .brand {
  430. margin: 0 0 1.5rem;
  431. justify-content: center;
  432. .logo {
  433. width: 32px;
  434. height: 32px;
  435. }
  436. .text {
  437. display: none;
  438. }
  439. }
  440. &:not(.is-mini-expanded),
  441. &.is-mini-expanded:not(:hover) {
  442. .menu-list {
  443. li {
  444. a {
  445. text-align: center;
  446. padding: 0.75em 0.5em;
  447. span:nth-child(2) {
  448. display: none;
  449. }
  450. }
  451. ul {
  452. padding-left: 0;
  453. li {
  454. a {
  455. display: inline-block;
  456. }
  457. }
  458. }
  459. }
  460. }
  461. .menu-label:not(:last-child) {
  462. margin-bottom: 0;
  463. }
  464. }
  465. }
  466. }
  467. }
  468. }
  469. </style>