snow пре 11 месеци
родитељ
комит
32078c4839

+ 3 - 0
src/style/index.scss

@@ -117,6 +117,9 @@ html {
   min-width: 1040px !important;
 }
 
+.flip-list-move {
+  transition: transform 0.5s;
+}
 
 .el-dialog {
   min-width: 1024px !important;

+ 34 - 22
src/views/welcome/index.vue

@@ -1,50 +1,62 @@
 <script setup lang="ts">
-import { ref } from "vue"
+import { ref , computed} from "vue"
 import Header from "./layouts/header.vue"
 import Footer from "./layouts/footer.vue"
 
 import Draggable from "vuedraggable"
+import { data, generateDataSource } from "./panel"
 
-import { data } from "./panel"
 
-const editable = ref(true)
+const editable = ref(false)
+const disabled = computed(() => !editable.value)
 
-function handleDrop(evt) {
-  console.log(evt)
+const { currentData, record, undo } = generateDataSource(data)
+const leftPanels = ref<any[]>([])
+
+
+function handleEdit(){
+  record()
+  editable.value  = true
+}
+
+function handleConfirm(){
+  editable.value = false
+}
+
+function handleCancel(){
+  undo()
+  editable.value  = false
 }
 </script>
 
 <template>
   <div class="welcome">
     <div :class="`border-1 box-border p-[5px] ${editable ? 'border-[#9fd2ff]' : 'border-transparent'}`">
-      <!-- <Header v-model="editable" /> -->
-
+      <Header :editable="editable" @edit="handleEdit" />
       <div class="flex w-full">
-        <!-- left-start -->
-        <div class="w-[1100px] h-full mr-[10px]">
-          <Draggable :list="data.left" group="left" @change="handleDrop">
+        <div class="w-[1100px] h-full mr-[10px] flex-1">
+          <Draggable v-model="currentData.left" group="home" :animation="200" :disabled="disabled">
             <template #item="{ element }">
-              <div class="w-full h-[180px] mb-2">
-                <component :editable="editable" :is="element.key" />
+              <div class="w-full  mb-2">
+                <component :editable="editable" :is="element.key" ref="leftPanels" />
               </div>
             </template>
           </Draggable>
         </div>
-        <!-- left-end -->
 
-        <!-- right-start -->
-        <div class="flex-1 h-full">
-          <template v-for="item in data.right" :key="item.key">
-            <div class="w-full h-[180px] mb-2">
-              <component :editable="editable" :is="item.key" />
-            </div>
-          </template>
+        <div class="h-full w-[570px]">
+          <Draggable v-model="currentData.right" group="home" :animation="200" :disabled="disabled">
+            <template #item="{ element }">
+              <div class="w-full mb-2">
+                <component :editable="editable" :is="element.key" />
+              </div>
+            </template>
+          </Draggable>
         </div>
-        <!-- right-end -->
       </div>
     </div>
 
-    <Footer v-model="editable" />
+    <Footer :editable="editable" @confirm="handleConfirm" @cancel="handleCancel"  />
   </div>
 </template>
 

+ 5 - 5
src/views/welcome/layouts/footer.vue

@@ -1,12 +1,12 @@
 <script setup lang="ts">
-defineProps<{ modelValue: boolean }>()
-const emit = defineEmits(['update:modelValue']);
+defineProps<{ editable: boolean }>()
+const emit = defineEmits(['confirm', 'cancel']);
 </script>
 
 <template>
   <div
     class="fixed bottom-0 w-full left-0 w-full h-[48px] bg-white custom-shadow rounded-lg flex items-center justify-end py-[5px] px-[15px]"
-    v-if="modelValue">
+    v-if="editable">
 
     <ElButton class="mr-[30px]"  size="small">移动</ElButton>
 
@@ -19,8 +19,8 @@ const emit = defineEmits(['update:modelValue']);
     </el-button-group>
 
     <div class="ml-[10px]">
-      <ElButton  type="primary" size="small" @click="emit('update:modelValue', false)">保存</ElButton>
-      <ElButton class="ml-[5px]" size="small" @click="emit('update:modelValue', false)">取消</ElButton>
+      <ElButton  type="primary" size="small" @click="emit('confirm')">保存</ElButton>
+      <ElButton class="ml-[5px]" size="small" @click="emit('cancel')">取消</ElButton>
     </div>
   </div>
 </template>

+ 5 - 5
src/views/welcome/layouts/header.vue

@@ -1,11 +1,11 @@
 <script setup lang="ts">
-defineProps<{ modelValue: boolean }>()
-const emit = defineEmits(['update:modelValue']);
+defineProps<{ editable: boolean }>()
+const emit = defineEmits(['edit']);
 </script>
 
 <template>
   <div class="w-full h-[40px] mb-[10px] rounded-lg flex">
-    <div :class="`flex-1 h-full mr-[10px] p-[5px] ${modelValue ? '' : 'bg-white custom-shadow'}`">
+    <div :class="`flex-1 h-full mr-[10px] p-[5px] ${editable ? '' : 'bg-white custom-shadow'}`">
       <div class="bg-[#2a82ff] inline-block px-[10px] py-[5px] box-border text-[#FFF] rounded-lg select-none"
         style="font-size:12px">
         销售员
@@ -13,8 +13,8 @@ const emit = defineEmits(['update:modelValue']);
     </div>
 
     <div
-      v-if="!modelValue"
-      class="flex w-[82px] h-full bg-white  custom-shadow items-center p-[5px] select-none cursor-pointer hover:color-[#2a82ff]" @click="() => emit('update:modelValue',true)">
+      v-if="!editable"
+      class="flex w-[82px] h-full bg-white  custom-shadow items-center p-[5px] select-none cursor-pointer hover:color-[#2a82ff]" @click="() => emit('edit')">
       <IconifyIconOffline style="font-size:14px" icon="edits" />
       <p class="ml-[5px] mt-[1px]" style="font-size:12px">桌面配置</p>
     </div>

+ 24 - 10
src/views/welcome/panel/index.ts

@@ -1,4 +1,4 @@
-import { App } from "vue"
+import { App , ref} from "vue"
 import ExternalLinks from "./src/external-links.vue"
 import MessageCenter from "./src/message-center.vue"
 import Business from "./src/business.vue"
@@ -6,6 +6,8 @@ import Commonly from "./src/commonly.vue"
 import Notice from "./src/notice.vue"
 
 
+import { cloneDeep } from "lodash"
+
 export function setupPanelComponent(app: App) {
   app.component("ExternalLinks", ExternalLinks);
   app.component("MessageCenter", MessageCenter);
@@ -16,13 +18,25 @@ export function setupPanelComponent(app: App) {
 
 
 export const data = {
-  'left': [
-    { key: 'MessageCenter'},
-    { key: 'Business'},
-    { key: 'Commonly'},
-  ],
-  'right': [
-    { key: 'Notice'},
-    { key: 'ExternalLinks'},
-  ]
+  'left': [ { key: 'MessageCenter' },  { key: 'Business' }, { key: 'Commonly' } ],
+  'right': [  { key: 'Notice' }, { key: 'ExternalLinks' } ]
+}
+
+export function generateDataSource(_data: any) {
+  const currentData = ref(cloneDeep(_data))
+  let previousData = null
+
+  function record(){
+    previousData = cloneDeep(currentData.value)
+  }
+
+  function undo(){
+    currentData.value = previousData
+  }
+
+  return {
+    undo,
+    record,
+    currentData
+  }
 }

+ 11 - 4
src/views/welcome/panel/src/business.vue

@@ -1,27 +1,34 @@
 <script setup lang="ts">
+import { ref } from "vue"
 import Wrapper from "./wrapper.vue"
+import Draggable from "vuedraggable"
+
 
 defineProps<{ editable: boolean }>()
 
-const items= new Array(18).fill(0).map((_, index) => ({
+const data = ref(new Array(18).fill(0).map((_, index) => ({
     total: 3,
     key: index,
     text:`销售单-${index}`,
     bgColor: '#0296ff',
     tagColor: '#35b1ff'
-}))
+})))
 </script>
 
 <template>
   <Wrapper class="bg-[#ffffff]" title="日常业务" :editable="editable" addable>
     <div class="flex select-none mt-[5px] flex-wrap">
-      <div class="h-[60px] w-[70px] mr-[10px] flex flex-col items-center justify-between cursor-pointer mb-[5px]" v-for="item in items" :key="item.key">
+      <Draggable v-model="data" group="business" :animation="200" :disabled="!editable" style="display:flex;width:100%;flex-wrap:wrap">
+        <template #item="{ element }">
+          <div class="h-[60px] w-[70px] mr-[5px] flex flex-col items-center justify-between cursor-pointer mb-[5px]">
         <div class="w-[40px] h-[40px] bg-[#f1f4ff] flex items-center justify-center mb-[5px]" style="bottom:10px;font-size:24px;border-radius: 5px">
           <IconifyIconOffline icon="office-building" />
         </div>
 
-        <p style="font-size:12px">{{item.text}}</p>
+        <p style="font-size:12px">{{element.text}}</p>
       </div>
+        </template>
+      </Draggable>
     </div>
   </Wrapper>
 </template>

+ 22 - 15
src/views/welcome/panel/src/commonly.vue

@@ -1,28 +1,35 @@
 <script setup lang="ts">
+import { ref } from "vue"
 import Wrapper from "./wrapper.vue"
+import Draggable from "vuedraggable"
 
-const items= new Array(3).fill(0).map((_, index) => ({
-    key: index,
-    text:`常用查询-${index}`,
-    total: 3,
-    bgColor: '#0296ff',
-    tagColor: '#35b1ff'
-}))
+defineProps<{ editable: boolean }>()
 
-const generateStyles = (background: string) => ({ background })
+const data = ref(new Array(3).fill(0).map((_, index) => ({
+  key: index,
+  text: `常用查询-${index}`,
+  total: 3,
+  bgColor: '#0296ff',
+  tagColor: '#35b1ff'
+})))
 </script>
 
 
 <template>
-  <Wrapper class="bg-[#FFFFFF]" title="常用查询">
+  <Wrapper class="bg-[#FFFFFF]" title="常用查询" :editable="editable">
     <div class="flex select-none mt-[5px] flex-wrap">
-      <div class="h-[60px] w-[60px] mr-[10px] flex flex-col items-center justify-between cursor-pointer mb-[5px]" v-for="item in items" :key="item.key">
-        <div class="w-[40px] h-[40px] bg-[#f1f4ff] flex items-center justify-center mb-[5px]" style="bottom:10px;font-size:24px;border-radius: 5px">
-          <IconifyIconOffline icon="office-building" />
-        </div>
+      <Draggable v-model="data" group="commonly" :animation="200" :disabled="!editable" style="display:flex;width:100%;flex-wrap:wrap">
+        <template #item="{ element }">
+          <div class="h-[60px] w-[60px] mr-[10px] flex flex-col items-center justify-between cursor-pointer mb-[5px]">
+            <div class="w-[40px] h-[40px] bg-[#f1f4ff] flex items-center justify-center mb-[5px]"
+              style="bottom:10px;font-size:24px;border-radius: 5px">
+              <IconifyIconOffline icon="office-building" />
+            </div>
 
-        <p style="font-size:12px">{{item.text}}</p>
-      </div>
+            <p style="font-size:12px">{{ element.text }}</p>
+          </div>
+        </template>
+      </Draggable>
     </div>
   </Wrapper>
 </template>

+ 35 - 12
src/views/welcome/panel/src/external-links.vue

@@ -1,21 +1,44 @@
 <script setup lang="ts">
-const items= new Array(5).fill(0).map((_, index) => ({
-    key: index,
-    text:`外部网站-${index}`,
-}))
+import { ref } from "vue"
+import Wrapper from "./wrapper.vue"
+import Draggable from "vuedraggable"
+
+defineProps<{ editable: boolean }>()
+
+const data = ref(new Array(5).fill(0).map((_, index) => ({
+  key: index,
+  text: `外部网站-${index}`,
+})))
 </script>
 
 
 <template>
   <div class="flex flex-wrap">
-    <div
-      v-for="(item,index) in items"
-      :class="`w-[48.5%] h-[120px] bg-white custom-shadow p-[20px] select-none cursor-pointer relative mb-[${String((index + 1) / 2).indexOf('.') !== -1 ? '0' : '10px'}] ml-[${String((index + 1) / 2).indexOf('.') !== -1  ? '0' : '10px'}]`">
-      <p class="" style="font-size:14px">{{item.text}}</p>
+    <Draggable v-model="data" group="links" :animation="200" :disabled="!editable"
+      style="display:flex;width:100%;flex-wrap:wrap;gap:10px">
+      <template #item="{ element }">
+        <div class="w-[48.5%] h-[120px] bg-white custom-shadow p-[20px] select-none cursor-pointer relative">
+          <p class="" style="font-size:14px">{{ element.text }}</p>
+          <div class="absolute top-[50%] right-0 translate-[-50%]">
+            <IconifyIconOffline style="font-size:38px" icon="link" />
+          </div>
+
+          <div v-if="editable"
+            :class="`absolute right-0 top-0  bg-[#e2e8f3] h-[25px] rounded-bl-[100px] flex items-center`">
+            <div :class="`cursor-pointer hover:color-[#0296ff]`" style="padding-left:15px">
+              <IconifyIconOffline icon="edits" />
+            </div>
+
+            <div style="padding-left:5px">
+              <ElCheckbox />
+            </div>
 
-      <div class="absolute top-[50%] right-0 translate-[-50%]">
-        <IconifyIconOffline style="font-size:38px" icon="link" />
-      </div>
-    </div>
+            <div class="pl-[5px] pr-[5px] cursor-pointer hover:color-[#0296ff]">
+              <IconifyIconOffline icon="close" />
+            </div>
+          </div>
+        </div>
+      </template>
+    </Draggable>
   </div>
 </template>

+ 23 - 16
src/views/welcome/panel/src/message-center.vue

@@ -1,14 +1,17 @@
 <script setup lang="ts">
+import { ref } from "vue"
 import Wrapper from "./wrapper.vue"
+import Draggable from "vuedraggable"
 
 defineProps<{ editable: boolean }>()
 
-const items = new Array(5).fill(0).map((_, index) => ({
+
+const data = ref(new Array(5).fill(0).map((_, index) => ({
   text: '审批中心',
   total: index,
   bgColor: '#0296ff',
   tagColor: '#35b1ff'
-}))
+})))
 
 const generateStyles = (background: string) => ({ background })
 </script>
@@ -16,27 +19,31 @@ const generateStyles = (background: string) => ({ background })
 
 <template>
   <Wrapper title="消息中心" refresh :editable="editable">
-    <div class="flex select-none">
-      <div class="flex items-center ml-[5px]">
+    <div class="flex select-none flex-wrap">
+      <div class="flex items-center ml-[5px] mb-[10px]">
         <div class="h-[65px] w-[65px] bg-blue rounded-100 border-2 border-[#fff]"></div>
         <div class="ml-[10px]">
-          <p class="font-bold" style="fontSize:14px">你好 ! xxx</p>
+          <p class="font-bold" style="font-size:14px">你好 ! xxx</p>
           <p class="w-[120px] text-[#b2b4c1]" style="word-break: break-all">*************************!</p>
         </div>
       </div>
 
       <div class="flex flex-1 select-none">
-        <div class="w-[25%] h-[100px] ml-[10px] rounded-xl relative" :style="generateStyles(item.bgColor)"
-          v-for="(item, index) in items" :key="index">
-          <div class="absolute top-[10px] right-[10px] text-white" style="font-size:22px">
-            <IconifyIconOffline icon="checkbox-circle-line" />
-          </div>
-
-          <div class="flex flex-col w-[85px] text-white ml-[10px] mt-[20px]" style="font-size:12px">
-            <h3 style="fontSize:24px">{{ item.total }}</h3>
-            <p class="rounded-100 px-[5px] text-center" :style="generateStyles(item.tagColor)">{{ item.text }}</p>
-          </div>
-        </div>
+        <Draggable v-model="data" group="message" :animation="200" :disabled="!editable" style="display:flex;width:100%">
+          <template #item="{ element }">
+            <div class="w-[25%] h-[100px] ml-[8px] rounded-xl relative" :style="generateStyles(element.bgColor)">
+              <div class="absolute top-[10px] right-[10px] text-white" style="font-size:22px">
+                <IconifyIconOffline icon="checkbox-circle-line" />
+              </div>
+
+              <div class="flex flex-col w-[85px] text-white ml-[8px] mt-[20px]" style="font-size:12px">
+                <h3 style="font-size:24px">{{ element.total }}</h3>
+                <p class="rounded-100  text-center" :style="generateStyles(element.tagColor)">{{ element.text }}
+                </p>
+              </div>
+            </div>
+          </template>
+        </Draggable>
       </div>
     </div>
   </Wrapper>

+ 1 - 3
src/views/welcome/panel/src/notice.vue

@@ -6,13 +6,11 @@ const items= new Array(31).fill(0).map((_, index) => ({
     text:`xxxxxxxxxx-${index}`,
     time: `2024-01-${String(index).length === 1 ? `0${index}` : index}`
 }))
-
-const generateStyles = (background: string) => ({ background })
 </script>
 
 
 <template>
-  <Wrapper class="bg-[#ffffff]" title="系统通知" refresh>
+  <Wrapper class="bg-[#ffffff]" title="系统通知" refresh max-height="180px">
     <div class="flex select-none flex-wrap px-[5px]">
       <div class="flex w-full justify-between" v-for="item in items" :key="item.key" style="font-size:12px">
         <p>{{item.text}}</p>

+ 5 - 1
src/views/welcome/panel/src/wrapper.vue

@@ -5,6 +5,7 @@ defineProps<{
   refresh?:boolean
   background?:string
   editable?:boolean
+  maxHeight?:string
 }>()
 
 const emit = defineEmits(['refresh'])
@@ -12,7 +13,10 @@ const emit = defineEmits(['refresh'])
 
 
 <template>
-  <div :class="`w-full h-full rounded-lg bg-[${background ? background : '#FFFFFF'}] p-[10px] flex flex-col custom-shadow relative`">
+  <div 
+    :class="`w-full rounded-lg bg-[${background ? background : '#FFFFFF'}] p-[10px] flex flex-col custom-shadow relative`"
+    :style="`cursor:${editable ? 'move' : 'default'};maxHeight:${maxHeight ? maxHeight : ''}`"
+  >
     <div class="flex justify-between select-none">
       <p style="font-size:14px">{{title}}</p>
     </div>