瀏覽代碼

Merge branch 'dev_zyh' of United_Software/k_online_ui into feature

Jack Zhou 9 月之前
父節點
當前提交
32bbde45cf

+ 0 - 1
package.json

@@ -11,7 +11,6 @@
     "preview": "vite preview",
     "build-only": "vite build",
     "build:dev": "vite build --mode development",
-    "build:test": "vite build --mode test",
     "build:pro": "vite build --mode product",
     "type-check": "vue-tsc --build --force",
     "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",

+ 26 - 3
src/api/module/notificationMessage.ts

@@ -6,15 +6,38 @@ const baseUrl = `${base}/main_new_version.php`
 /**
  * 保存用户个人信息或日期和数字格式化配置
  * @param save_model profile 代表基本信息的save, no_profile 代表格式信息的save
- * @param user_name
- * @param email
+ * @param first_name
+ * @param last_name
  * @param date_fromat
  * @param numbers_format
  */
 export const saveUserInfo = (params: any) => {
-  return HttpAxios.get(`${baseUrl}`, {
+  return HttpAxios.post(`${baseUrl}`, {
     action: 'system_setting',
     operate: 'personal_profile_save',
     ...params
   })
 }
+
+/**
+ * 获取milestone消息列表
+ * @param save_model profile 代表基本信息的save, no_profile 代表格式信息的save
+ */
+export const getNotificationList = (params: any) => {
+  return HttpAxios.get(`${baseUrl}`, {
+    action: 'notifications_rules',
+    operate: 'notifications_init',
+    ...params
+  })
+}
+
+/**
+ * 获取notification消息的see all详情
+ */
+export const getNotificationDetails = (params: any) => {
+  return HttpAxios.post(`${baseUrl}`, {
+    action: 'notifications_rules',
+    operate: 'notifications_see_all',
+    ...params
+  })
+}

+ 30 - 12
src/components/NotificationMessageCard/src/components/EventCard.vue

@@ -2,13 +2,14 @@
 import { transportationMode } from '@/components/transportationMode'
 import { useRouter } from 'vue-router'
 import { getTimezone } from '@/utils/tools'
+import dayjs from 'dayjs'
 
 const router = useRouter()
 
 interface EventCardPropsData {
   type: string // 'milestone' | 'container' | 'delay' | 'change'
   numericRecords?: number // 多条记录数 (Daily Update消息)
-  isRead: boolean // 是否已读 (true 已读,false 未读)
+  isRead?: boolean // 是否已读 (true 已读,false 未读)
   title?: string // Milestone Update
   mode?: string // 运输方式
   no: string // HBOL: SHJN2301234
@@ -37,8 +38,8 @@ const props = defineProps<{
 const handleSeeAll = (data: any) => {
   router.push({
     name: 'System Message Detail',
-    params: {
-      data: JSON.stringify(data) // 将数据转换为字符串并作为查询参数传递
+    query: {
+      frequency_type: data.frequency_type
     }
   })
 }
@@ -140,19 +141,31 @@ const handleSeeAll = (data: any) => {
         <span class="font_family icon-icon_location_b"></span>
         <span>{{ data.location }}</span>
       </div>
-      <div class="delay-time" v-if="data.type === 'delay' && data.info?.time">
-        <span class="font_family icon-icon_delay_b"></span>
-        <span>{{ data.info.timeLabel }}</span>
-        <span>{{ data.info.time }}</span>
+      <div
+        :class="{ 'delay-time': data.type === 'delay', 'change-time': data.type === 'change' }"
+        v-if="(data.type === 'delay' || 'change') && data.info?.time"
+      >
+        <span
+          v-if="data.type === 'delay'"
+          style="margin-right: 5px"
+          class="font_family icon-icon_delay_b"
+        ></span>
+        <span v-else class="font_family icon-icon_time_b"></span>
+        <span style="margin-right: 2px">{{ data.info.timeLabel }}&nbsp;</span>
+        <span style="margin-right: 3px">{{
+          dayjs(data.info.time).format('MMM DD, YYYY hh:mm')
+        }}</span>
         <span>{{ getTimezone(data.info.timezone) }}</span>
       </div>
-      <div class="change-time" v-if="data.type === 'change' && data.info?.time">
+      <!-- <div class="change-time" v-if="data.type === 'change' && data.info?.time">
         <span style="margin-left: 1px" class="font_family icon-icon_time_b"></span>
         <span>{{ data.info?.time }}</span>
-      </div>
-      <div class="time">
-        <span style="margin-left: 1px" class="font_family icon-icon_time_b"></span>
-        <span>{{ data.time }}</span>
+      </div> -->
+      <div class="time" :class="{ grey: data.type === 'delay' || data.type === 'change' }">
+        <span class="font_family icon-icon_time_b"></span>
+        <span style="margin-right: 2px">{{ data.timeLabel }}</span>
+        <span style="margin-right: 3px">{{ dayjs(data.time).format('MMM DD, YYYY hh:mm') }}</span>
+        <span>{{ getTimezone(data.timezone) }}</span>
       </div>
       <div class="previous" v-if="data.previous">
         <span class="previous-icon"></span>
@@ -272,6 +285,11 @@ const handleSeeAll = (data: any) => {
       align-items: center;
       margin-top: 8px;
       height: 16px;
+      &.grey {
+        span {
+          color: var(--color-neutral-3);
+        }
+      }
       span {
         color: var(--color-neutral-2);
         font-size: 12px;

+ 8 - 0
src/stores/modules/user.ts

@@ -1,5 +1,6 @@
 import { defineStore } from 'pinia'
 import { useVisitedRowState } from './visitedRow'
+import dayjs from 'dayjs'
 
 interface UserInfo {
   uname: string
@@ -10,6 +11,8 @@ interface UserInfo {
   expire_day: number
   date_format: string
   numbers_format: string
+  PASSWORD_CHANGE_CYCLE: number // 密码修改周期(多少天需要改一次)
+  last_pwd_change: string // 上次密码修改时间
 }
 interface UserState {
   userInfo: UserInfo
@@ -29,6 +32,11 @@ export const useUserStore = defineStore('user', {
       } else {
         return state.userInfo.uname || ''
       }
+    },
+    expireDay(state) {
+      const userInfo = state.userInfo
+
+      return userInfo.PASSWORD_CHANGE_CYCLE - dayjs().diff(dayjs(userInfo.last_pwd_change), 'day')
     }
   },
   actions: {

+ 1 - 1
src/utils/tools.ts

@@ -26,7 +26,7 @@ export const formatTimezone = (time: string, timezone?: string) => {
  * @returns
  */
 export const getTimezone = (timezone: string): string => {
-  if (timezone) return ''
+  if (!timezone) return ''
   const offset = moment.tz(`${moment().year()}-01-01`, timezone).format('Z')
   return `UTC${offset.slice(0, 3)}`
 }

+ 11 - 1
src/views/Layout/src/components/Header/HeaderView.vue

@@ -206,7 +206,7 @@ const notificationDrawer = ref(false)
           class="font_family icon-icon_notice_b"
           style="font-size: 18px"
         ></span> -->
-
+        <span class="unread-tip-icon"></span>
         <el-button
           style="height: 40px; width: 40px; margin-right: 0px"
           class="el-button--text"
@@ -405,11 +405,21 @@ const notificationDrawer = ref(false)
   }
 
   .notice-icon {
+    position: relative;
     display: flex;
     align-items: center;
     justify-content: center;
     margin-top: 2px;
     cursor: pointer;
+    .unread-tip-icon {
+      position: absolute;
+      top: 9px;
+      right: 8px;
+      width: 5px;
+      height: 5px;
+      border-radius: 50%;
+      background-color: var(--color-theme);
+    }
   }
 }
 </style>

+ 9 - 0
src/views/Layout/src/components/Header/components/ChangePasswordDialog.vue

@@ -1,4 +1,9 @@
 <script setup lang="ts">
+import { useUserStore } from '@/stores/modules/user'
+import dayjs from 'dayjs'
+
+const userStore = useUserStore()
+
 const dialogVisible = ref(false)
 
 const openDialog = () => {
@@ -50,6 +55,10 @@ const handleUpdate = () => {
     .then((res) => {
       if (res.code === 200) {
         ElMessage.success('Password updated successfully')
+        userStore.setUserInfo({
+          ...userStore.userInfo,
+          last_pwd_change: dayjs().format('YYYY-MM-DD HH:mm:ss')
+        })
         dialogVisible.value = false
       } else if (res.code === 400) {
         if (res.msg === 'Old password is incorrect') {

+ 152 - 103
src/views/Layout/src/components/Header/components/NotificationDrawer.vue

@@ -1,126 +1,172 @@
 <script setup lang="ts">
 import NotificationMessageCard from '@/components/NotificationMessageCard/src/NotificationMessageCard.vue'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+const loading = ref(false)
 
 const drawerModel = defineModel('drawerModel', { type: Boolean, default: false })
+
 const notificationType = ref('all')
-const notificationTypeList = ref([
-  {
-    label: 'All Notifications',
-    value: 'all'
-  },
-  {
-    label: 'Milestone Update',
-    value: 'feature1'
-  },
-  {
-    label: 'Container Status Update',
-    value: 'all2'
-  },
-  {
-    label: 'Departure/Arrival Delay',
-    value: 'feature3'
-  },
-  {
-    label: 'ETD/ETA Change',
-    value: 'all4'
-  },
-  {
-    label: 'Feature Update',
-    value: 'feature5'
-  }
-])
+const notificationTypeList = ref({
+  all: 'All Notifications',
+  Milestone_Update: 'Milestone Update',
+  Container_Status_Update: 'Container Status Update',
+  Container_Arrival: 'Container Arrival',
+  'Departure/Arrival_Delay': 'Departure/Arrival Delay',
+  'ETD/ETA_Change': 'ETD/ETA Change',
+  Feature_Update: 'Feature Update'
+})
 
-const notificationList = [
-  {
-    notificationType: 'feature',
-    info: {
-      isRead: true,
-      title: 'Feature Update',
-      header: 'New feature online: Quick search has been released!',
-      content:
-        'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-    }
-  },
-  {
-    notificationType: 'event',
-    info: {
-      type: 'milestone',
-      isMultiple: true,
-      numericRecords: 3,
-      isRead: true,
-      title: 'Milestone Update',
-      mode: 'Ocean Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8',
-      info: {
-        route: ['Hong Kong', 'Shanghai', 'Ningbo']
+const notificationList = ref<any[]>([])
+// const notificationList = [
+//   {
+//     notificationType: 'feature',
+//     info: {
+//       isRead: true,
+//       title: 'Feature Update',
+//       header: 'New feature online: Quick search has been released!',
+//       content:
+//         'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
+//     }
+//   },
+//   {
+//     notificationType: 'event',
+//     info: {
+//       type: 'milestone',
+//       isMultiple: true,
+//       numericRecords: 3,
+//       isRead: true,
+//       title: 'Milestone Update',
+//       mode: 'Ocean Freight',
+//       no: 'HBOL: SHJN2301234',
+//       tag: 'Booking Confirmed',
+//       location: 'Hong Kong',
+//       time: 'Jan 10, 2025 14:30 UTC+8',
+//       info: {
+//         route: ['Hong Kong', 'Shanghai', 'Ningbo']
+//       }
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       title: 'Password Notifications',
+//       isExpiration: true,
+//       tips: 'Password Expiration in 311 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       isRead: false,
+//       title: 'Password Notifications',
+//       isExpiration: false,
+//       tips: 'Password Expiration in 3 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       isRead: true,
+//       title: 'Password Notifications',
+//       isExpiration: true,
+//       tips: 'Password Expiration in 31111 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   }
+// ]
+
+const getNotificationList = () => {
+  loading.value = true
+  $api
+    .getNotificationList({
+      rules_type: 'Milestone_Update'
+    })
+    .then((res) => {
+      if (res.code === 200) {
+        notificationList.value = res.data
+        console.log(res, 'test')
       }
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      title: 'Password Notifications',
-      isExpiration: true,
-      tips: 'Password Expiration in 311 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      isRead: false,
-      title: 'Password Notifications',
-      isExpiration: false,
-      tips: 'Password Expiration in 3 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      isRead: true,
-      title: 'Password Notifications',
-      isExpiration: true,
-      tips: 'Password Expiration in 31111 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  }
-]
+    })
+    .finally(() => {
+      loading.value = false
+    })
+}
+
+const handleMarkAllRead = () => {
+  // 标记所有为已读
+  // notificationList.value.forEach((item) => {
+  //   item.isRead = true
+  // })
+}
+
+const handleViewAll = () => {
+  router.push('/system-message')
+}
+
+const handleSettingMessage = () => {
+  // 跳转消息设置页面
+  // router.push('/')
+}
+
+const clearData = () => {
+  notificationList.value = []
+}
 </script>
 
 <template>
-  <el-drawer class="notice-drawer" v-model="drawerModel" size="432px">
+  <el-drawer
+    @open="getNotificationList"
+    @closed="clearData"
+    class="notice-drawer"
+    v-model="drawerModel"
+    size="432px"
+  >
     <template #header>
       <el-select size="large" v-model="notificationType" class="notification-type">
         <el-option
-          v-for="item in notificationTypeList"
-          :key="item.value"
-          :label="item.label"
-          :value="item.value"
+          v-for="(label, value) in notificationTypeList"
+          :key="value"
+          :label="label"
+          :value="value"
         />
       </el-select>
     </template>
     <template #default>
-      <div class="notification-header">
-        <div class="mark-all-read">
-          <span class="font_family icon-icon_confirm_b show-icon"></span>
-          <span>Mark all read</span>
+      <div v-vloading="loading" style="height: 100%">
+        <div class="notification-header">
+          <el-button @click="handleMarkAllRead" class="mark-all-read el-button--text" size="small">
+            <span class="font_family icon-icon_confirm_b show-icon"></span>
+            <span>Mark all read</span>
+          </el-button>
+          <div class="view-all">
+            <el-button
+              style="height: 24px; width: 86px"
+              class="el-button--text"
+              @click="handleViewAll"
+            >
+              <span class="font_family icon-icon_confirm_b show-icon"></span>
+              <span>View all</span>
+            </el-button>
+            <el-button
+              class="el-button--text"
+              style="height: 24px; width: 24px; padding: 0"
+              @click="handleSettingMessage"
+            >
+              <span class="font_family icon-icon_administration_b"></span>
+            </el-button>
+          </div>
         </div>
-        <div class="view-all">
-          <span class="font_family icon-icon_confirm_b show-icon"></span>
-          <span>View all</span>
-          <span class="font_family icon-icon_administration_b setting"></span>
+        <div class="notification-content">
+          <NotificationMessageCard :data="notificationList" />
         </div>
       </div>
-      <div class="notification-content">
-        <NotificationMessageCard :data="notificationList" />
-      </div>
     </template>
   </el-drawer>
 </template>
@@ -235,6 +281,7 @@ div.layout-toolbar {
     .notification-header {
       display: flex;
       justify-content: space-between;
+      align-items: center;
       position: sticky;
       top: 0;
       height: 40px;
@@ -245,9 +292,11 @@ div.layout-toolbar {
       .mark-all-read {
         span {
           color: var(--color-theme);
+          font-size: 14px;
           vertical-align: middle;
         }
         .show-icon {
+          font-size: 16px;
           margin-right: 2px;
         }
       }

+ 47 - 42
src/views/Layout/src/components/Menu/MenuView.vue

@@ -17,49 +17,54 @@ watch(
   }
 )
 const getMenuList = () => {
-  // $api.getMenuList().then((res) => {
-  //   if (res.code === 200) {
-  //     menuList.value = res.data
-  //   }
-  // })
-  menuList.value = [
-    {
-      index: '1',
-      label: 'Dashboard',
-      icon: 'icon_data_fill_b',
-      path: '/dashboard'
-    },
-    {
-      index: 2,
-      label: 'Booking',
-      icon: 'icon_booking__fill_b',
-      path: '/booking'
-    },
-    {
-      index: 3,
-      label: 'Tracking',
-      icon: 'icon_tracking__fill_b',
-      path: '/tracking'
-    },
-    {
-      index: 4,
-      label: 'System Management',
-      icon: 'icon_system__management_fill_b',
-      type: 'list',
-      children: [
-        {
-          index: '4-1',
-          label: 'Operation Log',
-          path: '/Operationlog'
-        },
-        {
-          index: '4-2',
-          label: 'System Message',
-          path: '/system-message'
-        }
-      ]
+  $api.getMenuList().then((res) => {
+    if (res.code === 200) {
+      menuList.value = res.data
     }
-  ]
+  })
+  // menuList.value = [
+  //   {
+  //     index: '1',
+  //     label: 'Dashboard',
+  //     icon: 'icon_data_fill_b',
+  //     path: '/dashboard'
+  //   },
+  //   {
+  //     index: 2,
+  //     label: 'Booking',
+  //     icon: 'icon_booking__fill_b',
+  //     path: '/booking'
+  //   },
+  //   {
+  //     index: 3,
+  //     label: 'Tracking',
+  //     icon: 'icon_tracking__fill_b',
+  //     path: '/tracking'
+  //   },
+  //   {
+  //     index: 4,
+  //     label: 'System Management',
+  //     icon: 'icon_system__management_fill_b',
+  //     type: 'list',
+  //     children: [
+  //       {
+  //         index: '4-1',
+  //         label: 'System Message',
+  //         path: '/system-message'
+  //       },
+  //       {
+  //         index: '4-2',
+  //         label: 'System Settings',
+  //         path: '/SystemSettings'
+  //       },
+  //       {
+  //         index: '4-3',
+  //         label: 'Operation Log',
+  //         path: '/Operationlog'
+  //       }
+  //     ]
+  //   }
+  // ]
 }
 getMenuList()
 //监听窗口大小

+ 100 - 9
src/views/SystemMessage/src/SystemMessage.vue

@@ -1,6 +1,5 @@
 <script setup lang="ts">
 import EventCard from '@/components/NotificationMessageCard/src/components/EventCard.vue'
-import PersonalProfile from './components/PersonalProfile.vue'
 
 const collapseVModel = ref<string[]>(['1'])
 
@@ -28,10 +27,24 @@ const setActiveItem = (item: string) => {
   activeItem.value = item
 }
 
+// const getNotificationList = () => {
+//   $api
+//     .getNotificationList({
+//       rules_type: 'Milestone_Update'
+//     })
+//     .then((res) => {
+//       if (res.code === 200) {
+//         notificationList.value = res.data.info
+//         console.log(res, 'test')
+//       }
+//     })
+// }
+
 const activeName = ref('first')
 
 const handleClick = () => {}
 
+// const notificationList = ref<any[]>([])
 const notificationList = [
   {
     type: 'milestone',
@@ -43,7 +56,73 @@ const notificationList = [
     no: 'SHJN2301234',
     tag: 'Booking Confirmed',
     location: 'Hong Kong',
-    time: 'Jan 10, 2025 14:30 UTC+8'
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai'
+  },
+  {
+    type: 'container',
+    isRead: false,
+    mode: '',
+    no: 'SHJN2301234',
+    tag: 'Unloaded From Vessel',
+    location: 'Hong Kong',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
+    previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
+  },
+  {
+    type: 'delay',
+    numericRecords: 0,
+    isRead: false,
+    title: 'Delay Daily Summary (Jan 10, 2025)',
+    mode: 'Air Freight',
+    no: 'SHJN2301234',
+    tag: 'Departure Delay',
+    location: 'Hong Kong',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
+    info: {
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai',
+      departureDelayNum: 10,
+      arrivalDelayNum: 8
+    }
+  },
+  {
+    type: 'container',
+    isRead: false,
+    mode: '',
+    no: 'SHJN2301234',
+    tag: 'Unloaded From Vessel',
+    location: 'Hong Kong',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
+    previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
+  },
+  {
+    type: 'delay',
+    numericRecords: 0,
+    isRead: false,
+    title: 'Delay Daily Summary (Jan 10, 2025)',
+    mode: 'Air Freight',
+    no: 'SHJN2301234',
+    tag: 'Departure Delay',
+    location: 'Hong Kong',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
+    info: {
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai',
+      departureDelayNum: 10,
+      arrivalDelayNum: 8
+    }
   },
   {
     type: 'container',
@@ -52,7 +131,9 @@ const notificationList = [
     no: 'SHJN2301234',
     tag: 'Unloaded From Vessel',
     location: 'Hong Kong',
-    time: 'Jan 10, 2025 14:30 UTC+8',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
     previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
   },
   {
@@ -64,9 +145,13 @@ const notificationList = [
     no: 'SHJN2301234',
     tag: 'Departure Delay',
     location: 'Hong Kong',
-    time: 'Jan 10, 2025 14:30 UTC+8',
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai',
     info: {
-      time: 'ATD: Jan 12, 16:30 (+2 days delay)',
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai',
       departureDelayNum: 10,
       arrivalDelayNum: 8
     }
@@ -82,13 +167,20 @@ const notificationList = [
     info: {
       etdChangeNum: 20,
       etaChangeNum: 10,
-      time: 'Updated ETD: Jan 17, 15:00'
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai'
     },
     location: 'Hong Kong',
     changeTime: 'Updated ETD: Jan 17, 15:00',
-    time: 'Jan 10, 2025 14:30 UTC+8'
+    timeLabel: 'ATA: ',
+    time: '2510-12-1 14:30 UTC+8',
+    timezone: 'Asia/Shanghai'
   }
 ]
+// onMounted(() => {
+//   getNotificationList()
+// })
 </script>
 
 <template>
@@ -143,7 +235,6 @@ const notificationList = [
               <span>33</span>
             </div>
           </template>
-          <PersonalProfile />
         </el-tab-pane>
         <el-tab-pane label="Read" name="third">Role</el-tab-pane>
       </el-tabs>
@@ -250,7 +341,7 @@ const notificationList = [
     }
   }
   :deep(.el-tabs) {
-    height: calc(100% - 40px);
+    height: calc(100%);
     .el-tabs__content {
       overflow-y: auto;
     }

+ 20 - 6
src/views/SystemMessage/src/components/SystemMessageDetail.vue

@@ -6,32 +6,46 @@ const notificationData: any = {
   numericRecords: 3,
   notificationList: [
     {
-      isRead: true,
       mode: 'Ocean Freight',
       no: 'HBOL: SHJN2301234',
       tag: 'Booking Confirmed',
       location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8'
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai'
     },
     {
-      isRead: false,
       mode: 'Air Freight',
       no: 'HBOL: SHJN2301234',
       tag: 'Booking Confirmed',
       location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8'
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai'
     },
     {
-      isRead: false,
       mode: 'Air Freight',
       no: 'HBOL: SHJN2301234',
       tag: 'Booking Confirmed',
       location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8',
+      timeLabel: 'ATA: ',
+      time: '2510-12-1 14:30 UTC+8',
+      timezone: 'Asia/Shanghai',
       previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
     }
   ]
 }
+
+const getNotificationList = () => {
+  $api.getNotificationDetails().then((res) => {
+    if (res.code === 200) {
+      console.log(res, 'test')
+    }
+  })
+}
+onMounted(() => {
+  getNotificationList()
+})
 </script>
 
 <template>

+ 11 - 3
src/views/SystemSettings/src/SystemSettings.vue

@@ -3,10 +3,11 @@ import { ref, onMounted } from 'vue'
 import AddRSettingTableules from './components/SettingTable'
 import MonitoringTable from './components/MonitoringTable'
 import { useRouter } from 'vue-router'
+import PersonalProfile from './components/PersonalProfile.vue'
 
 const router = useRouter()
 
-const TabActive = ref('Subscribe Notifications')
+const TabActive = ref('Personal Profile')
 const isMilestoneChecked = ref(false)
 const isContainerChecked = ref(false)
 const isDepartureChecked = ref(false)
@@ -212,7 +213,7 @@ onMounted(() => {
 <template>
   <div class="Title">System Settings</div>
   <el-tabs v-model="TabActive" class="demo-tabs">
-    <el-tab-pane label="Personal Profile" name="Personal Profile"> Personal Profile </el-tab-pane>
+    <el-tab-pane label="Personal Profile" name="Personal Profile"><PersonalProfile /></el-tab-pane>
     <el-tab-pane label="Subscribe Notifications" name="Subscribe Notifications">
       <div class="subscribedTitle">Notification Events for Subscribed Shipments</div>
       <div class="SubscribeCollapse">
@@ -455,4 +456,11 @@ onMounted(() => {
 .el-button--main {
   margin-bottom: 4px;
 }
-</style>
+
+.demo-tabs {
+  height: calc(100% - 68px);
+  :deep(.el-tabs__content) {
+    overflow-y: auto;
+  }
+}
+</style>

+ 37 - 13
src/views/SystemMessage/src/components/PersonalProfile.vue → src/views/SystemSettings/src/components/PersonalProfile.vue

@@ -76,15 +76,13 @@ const handleDateFormat = (value: string) => {
   monthFormat.value = dateFormatExample.value[value][0].value
 }
 
-const numbersFormat = ref(userStore.userInfo?.numbers_format)
-
-// 判断用户是否指定数字格式化,没有指定则自动判断
-const isSpecifyNumbersFormat = () => {
-  numbersFormat.value = isEuropean() ? 'European' : 'US/UK'
+const initNumbersFormat = () => {
+  return userStore.userInfo?.numbers_format || (isEuropean() ? 'European' : 'US/UK')
 }
-isSpecifyNumbersFormat()
+const numbersFormat = ref(initNumbersFormat())
 
 const saveConfig = (model: string) => {
+  console.log(123123)
   let params = {}
   if (model === 'profile') {
     params = {
@@ -95,13 +93,31 @@ const saveConfig = (model: string) => {
   } else {
     params = {
       save_model: 'no_profile',
-      date_fromat: monthFormat.value,
-      number_format: numbersFormat.value
+      date_format: monthFormat.value,
+      numbers_format: numbersFormat.value
     }
   }
+  console.log(params, 'value')
   $api.saveUserInfo(params).then((res: any) => {
-    if (res.cdoe === 200) {
-      console.log(res)
+    console.log(res, 'res')
+    if (res.code === 200) {
+      const updatedInfo =
+        model === 'profile'
+          ? {
+              ...userStore.userInfo,
+              first_name: form.firstName,
+              last_name: form.lastName
+            }
+          : {
+              ...userStore.userInfo,
+              date_format: monthFormat.value,
+              numbers_format: numbersFormat.value
+            }
+
+      userStore.setUserInfo(updatedInfo)
+      ElMessage.success('Save successfully')
+    } else {
+      ElMessage.error('Save failed')
     }
   })
 }
@@ -138,7 +154,9 @@ const saveConfig = (model: string) => {
               Password
               <span style="margin: 0 2px 0 8px" class="font_family icon-icon_time_b"></span>
               <span>Your password will be expire in</span>
-              <span style="margin-left: 4px; color: var(--color-theme)">4 day(s)</span>
+              <span style="margin-left: 4px; color: var(--color-theme)"
+                >{{ userStore.expireDay }} day(s)</span
+              >
             </p>
             <div class="password-change">
               <el-input
@@ -213,7 +231,7 @@ const saveConfig = (model: string) => {
                   style="padding: 0 40px"
                   class="el-button--dark save-icon"
                   size="large"
-                  >Save</el-button
+                  >Save1222</el-button
                 >
               </el-col>
             </el-row>
@@ -240,7 +258,11 @@ const saveConfig = (model: string) => {
                 </el-radio></el-col
               >
               <el-col>
-                <el-button style="padding: 0 40px" class="el-button--dark save-icon" size="large"
+                <el-button
+                  @click="saveConfig('no_profile')"
+                  style="padding: 0 40px"
+                  class="el-button--dark save-icon"
+                  size="large"
                   >Save</el-button
                 >
               </el-col>
@@ -256,6 +278,8 @@ const saveConfig = (model: string) => {
 
 <style scoped lang="scss">
 .personal-profile {
+  padding: 24px;
+  padding-top: 9px;
   .basic-information,
   .personal-preferences {
     border: 1px solid var(--color-border);