lusa vor 2 Wochen
Ursprung
Commit
938ac30102

+ 3 - 0
ui/sp-user-center/.vite/deps_temp_2f92bf5a/package.json

@@ -0,0 +1,3 @@
+{
+  "type": "module"
+}

+ 3 - 0
ui/sp-user-center/.vite/deps_temp_f55f56aa/package.json

@@ -0,0 +1,3 @@
+{
+  "type": "module"
+}

+ 19 - 0
ui/sp-user-center/src/api/app.ts

@@ -0,0 +1,19 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+
+// Get Home App List
+export function getHomeApp(): AxiosPromise<any> {
+  return request({
+    url: '/app/manage/getHomeApp',
+    method: 'post'
+  });
+}
+
+// Jump to Page
+export function jumpToPage(pageId: number): AxiosPromise<any> {
+  return request({
+    url: '/app/manage/jumpToPage',
+    method: 'post',
+    params: { pageId }
+  });
+}

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/businessList.vue

@@ -27,6 +27,7 @@ import {
 } from '@/api/business/allBusiness';
 
 import {AllBusinessVO, AllBusinessQuery, AllBusinessForm} from '@/api/business/allBusiness/types';
+import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
 import auth from '@/plugins/auth'
 import Table from '@/components/Table/index.vue'
 import {tableTypes} from '@/components/Table/types'

+ 2 - 1
ui/sp-user-center/src/components/detailCommon/emailList.vue

@@ -74,7 +74,8 @@
 
 <script setup lang="ts">
     import { getMailList, fileDownload, delEmails, trashEmails, setClickRecord, getRecord, getEmailDetailContent } from '@/api/emails';
-    import { EmailsVO } from '@/api/emails/types';
+import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
+import { EmailsVO } from '@/api/emails/types';
     import Table from '@/components/Table/index.vue'
     import { tableTypes } from '@/components/Table/types'
     import downloadPlugins from '@/plugins/download'

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/liaison.vue

@@ -14,6 +14,7 @@
 <script setup lang="ts">
 import { listLiaison, delLiaison } from '@/api/customer/liaison';
 import { LiaisonVO, LiaisonQuery } from '@/api/customer/liaison/types';
+import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
 import auth from '@/plugins/auth'
 import Table from '@/components/Table/index.vue'
 import { tableTypes } from '@/components/Table/types'

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/orderForm.vue

@@ -17,6 +17,7 @@
 
 <script setup lang="ts">
 import { listOrderForm, delOrderForm } from '@/api/orderForm';
+import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
 import { OrderFormVO, OrderFormQuery } from '@/api/orderForm/types';
 import Table from '@/components/Table/index.vue'
 import { tableTypes } from '@/components/Table/types'

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/quotationForm.vue

@@ -14,6 +14,7 @@
 
 <script setup lang="ts">
 import { quotationList} from '@/api/customer';
+import { ElButton } from 'element-plus';
 import Table from '@/components/Table/index.vue'
 import QuotationDetail from '@/components/common/quotationDetail.vue'
 import {downLodaQuotationById,} from '@/api/product/index'

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/sendRecord.vue

@@ -118,6 +118,7 @@
 
 <script setup name="SendRecord" lang="ts">
 import { listSendRecord, getSendRecord, delSendRecord, addSendRecord } from '@/api/customer/sendRecord';
+import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
 import { SendRecordVO, SendRecordQuery, SendRecordForm } from '@/api/customer/sendRecord/types';
 // import SelectUser from '@/components/SelectOrg/SelectUser.vue';
 import CorrelationSelect from '@/components/common/correlationSelect.vue';

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/task.vue

@@ -48,6 +48,7 @@
 
 <script setup lang="ts">
 import { listTask, delTask } from '@/api/task';
+import { ElButton } from 'element-plus';
 import { TaskVO, TaskQuery } from '@/api/task/types';
 import Table from '@/components/Table/index.vue'
 import { tableTypes } from '@/components/Table/types'

+ 1 - 0
ui/sp-user-center/src/components/detailCommon/workOrder.vue

@@ -15,6 +15,7 @@
 
 <script setup lang="ts">
 import { listOrder, delOrder } from '@/api/order';
+import { ElButton } from 'element-plus';
 import { OrderVO, OrderQuery } from '@/api/order/types';
 import Table from '@/components/Table/index.vue'
 import { tableTypes } from '@/components/Table/types'

+ 1 - 0
ui/sp-user-center/src/layout/components/notice/SetMsgTools.vue

@@ -34,6 +34,7 @@
 
 <script setup name="MessageTemplate" lang="ts">
 import {listPageBuUserSet, changeEnable, setMessageConfig} from '@/api/system/messageTemplate';
+import { ElButton, ElSwitch, ElMessage } from 'element-plus';
 import { MessageTemplateVO, MessageTemplateQuery } from '@/api/system/messageTemplate/types';
 import auth from '@/plugins/auth'
 import Table from '@/components/Table/index.vue'

+ 5 - 0
ui/sp-user-center/src/router/index.ts

@@ -44,6 +44,11 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/index.vue'),
     },
 
+    {
+        path: '/login',
+        component: () => import('@/views/login.vue'),
+        hidden: true
+    },
 
     {
         path: '/:pathMatch(.*)*',

+ 2 - 2
ui/sp-user-center/src/store/modules/userHobit.ts

@@ -12,8 +12,8 @@ export const userHobit = defineStore('userHobit', () => {
     }
 
     const gethobit = async () => {
-        const res = await getPersonalize()
-        setAllTableCloumn(res.result)
+        // const res = await getPersonalize()
+        // setAllTableCloumn(res.result)
     }
 
     const getCloumnByCode = (code: string) => {

+ 224 - 0
ui/sp-user-center/src/views/error/404.vue

@@ -0,0 +1,224 @@
+<template>
+  <div class="wscn-http404-container">
+    <div class="wscn-http404">
+      <div class="pic-404">
+        <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
+        <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
+      </div>
+      <div class="bullshit">
+        <div class="bullshit__oops">OOPS!</div>
+        <div class="bullshit__info">All rights reserved
+          <a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
+        </div>
+        <div class="bullshit__headline">{{ message }}</div>
+        <div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>
+        <a href="" class="bullshit__return-home">Back to home</a>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue';
+
+const message = computed(() => {
+  return 'The webmaster said that you can not enter this page...';
+});
+</script>
+
+<style lang="scss" scoped>
+.wscn-http404-container{
+  transform: translate(-50%,-50%);
+  position: absolute;
+  top: 40%;
+  left: 50%;
+}
+.wscn-http404 {
+  position: relative;
+  width: 1200px;
+  padding: 0 50px;
+  overflow: hidden;
+  .pic-404 {
+    position: relative;
+    float: left;
+    width: 600px;
+    overflow: hidden;
+    &__parent {
+      width: 100%;
+    }
+    &__child {
+      position: absolute;
+      &.left {
+        width: 80px;
+        top: 17px;
+        left: 220px;
+        opacity: 0;
+        animation-name: cloudLeft;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      &.mid {
+        width: 46px;
+        top: 10px;
+        left: 420px;
+        opacity: 0;
+        animation-name: cloudMid;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1.2s;
+      }
+      &.right {
+        width: 62px;
+        top: 100px;
+        left: 500px;
+        opacity: 0;
+        animation-name: cloudRight;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      @keyframes cloudLeft {
+        0% {
+          top: 17px;
+          left: 220px;
+          opacity: 0;
+        }
+        20% {
+          top: 33px;
+          left: 188px;
+          opacity: 1;
+        }
+        80% {
+          top: 81px;
+          left: 92px;
+          opacity: 1;
+        }
+        100% {
+          top: 97px;
+          left: 60px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudMid {
+        0% {
+          top: 10px;
+          left: 420px;
+          opacity: 0;
+        }
+        20% {
+          top: 40px;
+          left: 360px;
+          opacity: 1;
+        }
+        80% {
+          top: 130px;
+          left: 180px;
+          opacity: 1;
+        }
+        100% {
+          top: 160px;
+          left: 120px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudRight {
+        0% {
+          top: 100px;
+          left: 500px;
+          opacity: 0;
+        }
+        20% {
+          top: 120px;
+          left: 460px;
+          opacity: 1;
+        }
+        80% {
+          top: 180px;
+          left: 340px;
+          opacity: 1;
+        }
+        100% {
+          top: 200px;
+          left: 300px;
+          opacity: 0;
+        }
+      }
+    }
+  }
+  .bullshit {
+    position: relative;
+    float: left;
+    width: 300px;
+    padding: 30px 0;
+    overflow: hidden;
+    &__oops {
+      font-size: 32px;
+      font-weight: bold;
+      line-height: 40px;
+      color: #1482f0;
+      opacity: 0;
+      margin-bottom: 20px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-fill-mode: forwards;
+    }
+    &__headline {
+      font-size: 20px;
+      line-height: 24px;
+      color: #222;
+      font-weight: bold;
+      opacity: 0;
+      margin-bottom: 10px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.1s;
+      animation-fill-mode: forwards;
+    }
+    &__info {
+      font-size: 13px;
+      line-height: 21px;
+      color: grey;
+      opacity: 0;
+      margin-bottom: 30px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.2s;
+      animation-fill-mode: forwards;
+    }
+    &__return-home {
+      display: block;
+      float: left;
+      width: 110px;
+      height: 36px;
+      background: #1482f0;
+      border-radius: 100px;
+      text-align: center;
+      color: #ffffff;
+      opacity: 0;
+      font-size: 14px;
+      line-height: 36px;
+      cursor: pointer;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.3s;
+      animation-fill-mode: forwards;
+    }
+    @keyframes slideUp {
+      0% {
+        transform: translateY(60px);
+        opacity: 0;
+      }
+      100% {
+        transform: translateY(0);
+        opacity: 1;
+      }
+    }
+  }
+}
+</style>

+ 65 - 101
ui/sp-user-center/src/views/index.vue

@@ -13,54 +13,14 @@
 
     <!-- Main Content -->
     <div class="main-content">
-      <!-- Recently Used Section -->
-      <div class="section">
-        <h2 class="section-title">最近使用</h2>
+      <div class="section" v-for="app in appList" :key="app.appId">
+        <h2 class="section-title">{{ app.appName }}</h2>
         <div class="icon-grid">
-          <div class="icon-item" v-for="item in recentlyUsed" :key="item.name" @click="handleClick(item)">
-            <div class="icon-wrapper" >
-              <img :src="item.icon" :alt="item.name" />
+          <div class="icon-item" v-for="page in app.appPages" :key="page.pageId" @click="handleClick(page)">
+            <div class="icon-wrapper">
+              <img :src="getIconPath(page.appName)" :alt="page.appName" />
             </div>
-            <span class="icon-label">{{ item.name }}</span>
-          </div>
-        </div>
-      </div>
-
-      <!-- Pending My Approval Section -->
-      <div class="section">
-        <h2 class="section-title">待我审批</h2>
-        <div class="icon-grid">
-          <div class="icon-item" v-for="item in pendingApproval" :key="item.name" @click="handleClick(item)">
-            <div class="icon-wrapper" >
-              <img :src="item.icon" :alt="item.name" />
-            </div>
-            <span class="icon-label">{{ item.name }}</span>
-          </div>
-        </div>
-      </div>
-
-      <!-- My Approvals Section -->
-      <div class="section">
-        <h2 class="section-title">我的审批</h2>
-        <div class="icon-grid">
-          <div class="icon-item" v-for="item in myApprovals" :key="item.name" @click="handleClick(item)">
-            <div class="icon-wrapper" >
-              <img :src="item.icon" :alt="item.name" />
-            </div>
-            <span class="icon-label">{{ item.name }}</span>
-          </div>
-        </div>
-      </div>
-
-      <!-- My Tasks Section -->
-      <div class="section">
-        <h2 class="section-title">我的任务</h2>
-        <div class="icon-grid">
-          <div class="icon-item" v-for="item in myTasks" :key="item.name" @click="handleClick(item)">
-            <div class="icon-wrapper" :style="{ backgroundColor: item.color }">
-              <img :src="item.icon" :alt="item.name" />
-            </div>
-            <span class="icon-label">{{ item.name }}</span>
+            <span class="icon-label">{{ page.appName }}</span>
           </div>
         </div>
       </div>
@@ -69,66 +29,70 @@
 </template>
 
 <script setup name="Index" lang="ts">
-import { ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { getHomeApp, jumpToPage } from '@/api/app';
 
-interface MenuItem {
-  name: string;
-  icon: string;
-  color: string;
-  route?: string;
+interface AppPage {
+  pageId: number;
+  appName: string;
 }
 
-// Recently Used Items
-const recentlyUsed = ref<MenuItem[]>([
-  { name: '立项', icon: '/src/assets/images/home/立项@2x.png', color: '#5DCDFF' },
-  { name: '项目变更', icon: '/src/assets/images/home/项目变更@2x.png', color: '#6B8CFF' },
-  { name: '进出场单', icon: '/src/assets/images/home/进出场单@2x.png', color: '#FF9F5A' },
-  { name: '文档', icon: '/src/assets/images/home/文档@2x.png', color: '#5FD4A8' },
-  { name: '申购', icon: '/src/assets/images/home/申购@2x.png', color: '#7B6CFF' },
-  { name: 'BOM变更', icon: '/src/assets/images/home/BOM变更@2x.png', color: '#FF6B9D' },
-  { name: '兑换', icon: '/src/assets/images/home/兑换@2x.png', color: '#C77CFF' },
-  { name: '兑换付款', icon: '/src/assets/images/home/兑换付款@2x.png', color: '#FFB84D' },
-]);
+interface AppInfo {
+  appId: number;
+  appName: string;
+  appPages: AppPage[];
+}
 
-// Pending My Approval Items
-const pendingApproval = ref<MenuItem[]>([
-  { name: '立项', icon: '/src/assets/images/home/project_initiation.png', color: '#5DCDFF' },
-  { name: '项目变更', icon: '/src/assets/images/home/project_change.png', color: '#6B8CFF' },
-  { name: '进出场单', icon: '/src/assets/images/home/entry_exit_form.png', color: '#FF9F5A' },
-  { name: '文档', icon: '/src/assets/images/home/document.png', color: '#5FD4A8' },
-  { name: '申购', icon: '/src/assets/images/home/purchase_request.png', color: '#7B6CFF' },
-  { name: 'BOM变更', icon: '/src/assets/images/home/bom_change.png', color: '#FF6B9D' },
-  { name: '兑换', icon: '/src/assets/images/home/redeem.png', color: '#C77CFF' },
-  { name: '兑换付款', icon: '/src/assets/images/home/redeem_payment.png', color: '#FFB84D' },
-]);
+const appList = ref<AppInfo[]>([]);
+
+// Icon Mapping
+const iconMap: Record<string, string> = {
+  '立项': 'project_initiation.png',
+  '项目变更': 'project_change.png',
+  '进出场单': 'entry_exit_form.png',
+  '文档': 'document.png',
+  '申购': 'purchase_request.png',
+  'BOM变更': 'bom_change.png',
+  '兑换': 'redeem.png',
+  '兑换付款': 'redeem_payment.png',
+  '配置品审批': 'configuration_approval.png',
+  '投标入场': 'entry_approval.png',
+  '配置付款': 'configuration_payment.png',
+  '项目汇总': 'project_summary.png',
+  '工单生成': 'work_order_service.png',
+};
 
-// My Approvals Items
-const myApprovals = ref<MenuItem[]>([
-  { name: '配置品审批', icon: '/src/assets/images/home/configuration_approval.png', color: '#6B8CFF' },
-  { name: '投标入场', icon: '/src/assets/images/home/entry_approval.png', color: '#5FD4A8' },
-  { name: '投标入场', icon: '/src/assets/images/home/entry_approval.png', color: '#7B6CFF' },
-  { name: '配置付款', icon: '/src/assets/images/home/configuration_payment.png', color: '#FFB84D' },
-  { name: '项目汇总', icon: '/src/assets/images/home/project_summary.png', color: '#5DCDFF' },
-  { name: '工单生成', icon: '/src/assets/images/home/work_order_service.png', color: '#5FD4A8' },
-]);
+// Helper to get icon path
+const getIconPath = (name: string) => {
+  const filename = iconMap[name] || 'document.png'; // Default icon
+  return new URL(`/src/assets/images/home/${filename}`, import.meta.url).href;
+};
 
-// My Tasks Items
-const myTasks = ref<MenuItem[]>([
-  { name: '配置付款', icon: '/src/assets/images/home/configuration_payment.png', color: '#FFB84D' },
-  { name: '项目汇总', icon: '/src/assets/images/home/project_summary.png', color: '#5DCDFF' },
-  { name: '工单生成', icon: '/src/assets/images/home/work_order_service.png', color: '#5FD4A8' },
-]);
+const handleClick = async (item: AppPage) => {
+  console.log('Clicked:', item.appName, item.pageId);
+  try {
+    const res = await jumpToPage(item.pageId);
+    if (res.result) {
+        window.open(res.result, '_blank');
+    }
+  } catch (error) {
+    console.error('Jump to page failed:', error);
+  }
+};
 
-const handleClick = (item: MenuItem) => {
-  console.log('Clicked:', item.name);
-  // Add navigation logic here
-  if (item.route) {
-    // router.push(item.route);
+const initData = async () => {
+  try {
+    const res = await getHomeApp();
+    if (res.result) {
+      appList.value = res.result;
+    }
+  } catch (error) {
+    console.error('Failed to get home app list:', error);
   }
 };
 
 onMounted(() => {
-  console.log('Home page mounted');
+  initData();
 });
 </script>
 
@@ -140,6 +104,11 @@ onMounted(() => {
 }
 
 .header {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 100;
   display: flex;
   justify-content: space-between;
   align-items: center;
@@ -177,7 +146,7 @@ onMounted(() => {
 .main-content {
   max-width: 1400px;
   margin: 0 auto;
-  padding: 40px 20px;
+  padding: 92px 20px 40px 20px; // 72px header height + 20px spacing
 }
 
 .section {
@@ -224,10 +193,6 @@ onMounted(() => {
 
     &:hover {
       transform: translateY(-4px);
-
-      .icon-wrapper {
-        // box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
-      }
     }
 
     .icon-wrapper {
@@ -238,7 +203,6 @@ onMounted(() => {
       align-items: center;
       justify-content: center;
       transition: all 0.3s ease;
-    //   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
 
       img {
         width: 64px;

+ 3 - 3
ui/sp-user-center/src/views/login.vue

@@ -99,7 +99,7 @@ const checkOut = async (type: number) => {
 const redirect = ref(undefined);
 const loginRef = ref<ElFormInstance>();
 
-const loginType = ref(2)
+const loginType = ref(1)
 
 watch(() => router.currentRoute.value, (newRoute: any) => {
   redirect.value = newRoute.query && newRoute.query.redirect;
@@ -123,7 +123,7 @@ const handleLogin = () => {
       // 调用action的登录方法
         const [err] = await to(userStore.login(loginForm.value));
         //获取用户列表配置
-        userHobitStore.gethobit()
+        // userHobitStore.gethobit()
       if (!err) {
         await router.push({ path: redirect.value || '/' });
         loading.value = false;
@@ -137,7 +137,7 @@ const handleLogin = () => {
   });
 };
 onMounted(() => {
-    checkOut(2)
+    checkOut(1)
 });
 </script>
 

+ 20 - 0
ui/sp-user-center/src/views/redirect/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div></div>
+</template>
+
+<script setup lang="ts">
+import { unref } from 'vue';
+import { useRouter } from 'vue-router';
+
+const { currentRoute, replace } = useRouter();
+
+const { params, query } = unref(currentRoute);
+const { path } = params;
+
+const _path = Array.isArray(path) ? path.join('/') : path;
+
+replace({
+  path: '/' + _path,
+  query,
+});
+</script>

+ 1 - 1
ui/sp-user-center/vite.config.ts

@@ -36,7 +36,7 @@ export default defineConfig(({mode, command}: ConfigEnv): UserConfig => {
                 '/api/': {
                     changeOrigin: true,
                     // 接口地址
-                    target: mode === 'dev67' ? 'http://192.168.1.67:18090' : 'http://localhost:18090',
+                    target: mode === 'dev67' ? 'http://192.168.1.67:10010' : 'http://localhost:10010',
                     // target: 'http://192.168.1.193:18090',
                     pathRewrite: {
                         ['^' + env.VITE_APP_BASE_API]: ''

Datei-Diff unterdrückt, da er zu groß ist
+ 268 - 0
ui/sp-user-center/vite.config.ts.timestamp-1766566524412-75fb9cb060e12.mjs


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.