index.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <template>
  2. <div class="ele-body ele-body-card">
  3. <profile-card />
  4. <link-card ref="linkCard" />
  5. <vue-draggable
  6. tag="el-row"
  7. v-model="data"
  8. handle=".el-card__header"
  9. :component-data="{ props: { gutter: 15 } }"
  10. :animation="300"
  11. :set-data="() => void 0"
  12. @end="onEnd"
  13. >
  14. <el-col
  15. v-for="(d, i) in data"
  16. :key="d.name"
  17. v-bind="styleResponsive ? { md: d.md, sm: d.sm } : { span: d.md }"
  18. >
  19. <component
  20. :is="d.name"
  21. :title="d.title"
  22. @remove="onRemove(i)"
  23. @edit="onEdit(i)"
  24. />
  25. </el-col>
  26. </vue-draggable>
  27. <el-card shadow="never" body-style="padding: 0;">
  28. <div class="ele-cell" style="line-height: 42px">
  29. <div
  30. class="ele-cell-content ele-text-primary workplace-bottom-btn"
  31. @click="add"
  32. >
  33. <i class="el-icon-circle-plus-outline"></i> 添加视图
  34. </div>
  35. <el-divider direction="vertical" />
  36. <div
  37. class="ele-cell-content ele-text-primary workplace-bottom-btn"
  38. @click="reset"
  39. >
  40. <i class="el-icon-refresh-left"></i> 重置布局
  41. </div>
  42. </div>
  43. </el-card>
  44. <!-- 编辑弹窗 -->
  45. <ele-modal width="680px" :visible.sync="visible" title="未添加的视图" :maxable="true">
  46. <el-row :gutter="15" style="margin-bottom: -15px" >
  47. <el-col v-for="item in notAddedData" :key="item.name" :md="8" :sm="24">
  48. <div
  49. class="workplace-card-item ele-border-lighter"
  50. @click="addView(item)"
  51. >
  52. <div class="workplace-card-header ele-border-lighter">
  53. {{ item.title }}
  54. </div>
  55. <div class="workplace-card-body ele-text-placeholder">
  56. <i class="el-icon-plus"></i>
  57. </div>
  58. </div>
  59. </el-col>
  60. </el-row>
  61. <ele-empty v-if="!notAddedData.length" text="已添加所有视图" />
  62. </ele-modal>
  63. </div>
  64. </template>
  65. <script>
  66. import VueDraggable from 'vuedraggable';
  67. import ProfileCard from './components/profile-card.vue';
  68. import LinkCard from './components/link-card.vue';
  69. import ActivitiesCard from './components/activities-card.vue';
  70. import TaskCard from './components/task-card.vue';
  71. import GoalCard from './components/goal-card.vue';
  72. import ProjectCard from './components/project-card.vue';
  73. import UserList from './components/user-list.vue';
  74. export default {
  75. name: 'DashboardWorkplace',
  76. components: {
  77. VueDraggable,
  78. ProfileCard,
  79. LinkCard,
  80. ActivitiesCard,
  81. TaskCard,
  82. GoalCard,
  83. ProjectCard,
  84. UserList
  85. },
  86. data() {
  87. // 默认布局
  88. const defaultData = [
  89. {
  90. name: 'activities-card',
  91. title: '最新动态',
  92. md: 8,
  93. sm: 24
  94. },
  95. {
  96. name: 'task-card',
  97. title: '我的任务',
  98. md: 8,
  99. sm: 24
  100. },
  101. {
  102. name: 'goal-card',
  103. title: '本月目标',
  104. md: 8,
  105. sm: 24
  106. },
  107. {
  108. name: 'project-card',
  109. title: '项目进度',
  110. md: 16,
  111. sm: 24
  112. },
  113. {
  114. name: 'user-list',
  115. title: '小组成员',
  116. md: 8,
  117. sm: 24
  118. }
  119. ];
  120. // 获取缓存布局
  121. const cache = (() => {
  122. const str = localStorage.getItem('workplace-layout');
  123. try {
  124. return str ? JSON.parse(str) : null;
  125. } catch (e) {
  126. return null;
  127. }
  128. })();
  129. return {
  130. defaultData,
  131. data: [...(cache ?? defaultData)],
  132. visible: false
  133. };
  134. },
  135. computed: {
  136. // 未添加的数据
  137. notAddedData() {
  138. return this.defaultData.filter(
  139. (d) => !this.data.some((t) => t.name === d.name)
  140. );
  141. },
  142. // 是否开启响应式布局
  143. styleResponsive() {
  144. return this.$store.state.theme.styleResponsive;
  145. }
  146. },
  147. methods: {
  148. /* 添加 */
  149. add() {
  150. this.visible = true;
  151. },
  152. /* 重置布局 */
  153. reset() {
  154. this.data = [...this.defaultData];
  155. this.cacheData();
  156. this.$refs.linkCard.reset();
  157. this.$message.success('已重置');
  158. },
  159. /* 缓存布局 */
  160. cacheData() {
  161. localStorage.setItem('workplace-layout', JSON.stringify(this.data));
  162. },
  163. /* 删除视图 */
  164. onRemove(index) {
  165. this.data = this.data.filter((_d, i) => i !== index);
  166. this.cacheData();
  167. },
  168. /* 编辑视图 */
  169. onEdit(index) {
  170. console.log('index:', index);
  171. this.$message.info('点击了编辑');
  172. },
  173. /* 添加视图 */
  174. addView(item) {
  175. this.data.push(item);
  176. this.cacheData();
  177. this.$message.success('已添加');
  178. },
  179. /* 排序改变 */
  180. onEnd() {
  181. this.cacheData();
  182. }
  183. }
  184. };
  185. </script>
  186. <style lang="scss" scoped>
  187. .ele-body {
  188. :deep(.el-card__header) {
  189. cursor: move;
  190. position: relative;
  191. }
  192. :deep(.el-row > .el-col.sortable-chosen > .el-card) {
  193. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
  194. }
  195. }
  196. .workplace-bottom-btn {
  197. text-align: center;
  198. cursor: pointer;
  199. transition: background-color 0.2s;
  200. &:hover {
  201. background: hsla(0, 0%, 60%, 0.05);
  202. }
  203. }
  204. /* 添加弹窗 */
  205. .workplace-card-item {
  206. margin-bottom: 15px;
  207. border-width: 1px;
  208. border-style: solid;
  209. border-radius: 4px;
  210. position: relative;
  211. cursor: pointer;
  212. transition: box-shadow 0.3s;
  213. &:hover {
  214. box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);
  215. }
  216. .workplace-card-header {
  217. border-bottom-width: 1px;
  218. border-bottom-style: solid;
  219. padding: 8px;
  220. }
  221. }
  222. .workplace-card-body {
  223. font-size: 24px;
  224. padding: 40px 10px;
  225. text-align: center;
  226. }
  227. </style>