Browse Source

Merge remote-tracking branch 'origin/master'

wwj 1 month ago
parent
commit
e7647ee60d

+ 6 - 0
src/api/system/studentAttendance/index.ts

@@ -81,4 +81,10 @@ export const StudentAttendanceApi = {
   exportStudentAttendanceExcusedExcel: async (params) => {
     return await request.download({ url: `/system/student-attendance/export-excusedExcel`, params })
   },
+
+  // 周出勤情况
+  getWeekendAttendance: async () => {
+    return await request.get({ url: `/system/student-attendance/weekendAttendance` })
+  },
+
 }

+ 5 - 0
src/api/system/user/index.ts

@@ -188,3 +188,8 @@ export const getAttendanceTemplate = async () => {
 export const deletestudentFace = (userNumber: number) => {
   return request.delete({ url: '/md/acs/deleteStudentFace?userNumber=' + userNumber })
 }
+
+// 基本信息展示
+export const getDetail = () => {
+  return request.get({ url: '/system/user/getDetail' })
+}

+ 3 - 2
src/components/UploadFile/src/UploadImg.vue

@@ -79,7 +79,8 @@ const props = defineProps({
   width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
   borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px)
   showDelete: propTypes.bool.def(true), // 是否显示删除按钮
-  showBtnText: propTypes.bool.def(true) // 是否显示按钮文字
+  showBtnText: propTypes.bool.def(true), // 是否显示按钮文字
+  successMessage : propTypes.string.def("上传成功!"), // 上传成功提示信息
 })
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
@@ -117,7 +118,7 @@ const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
 
 // 图片上传成功提示
 const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
-  message.success('上传成功')
+  message.success(props.successMessage)
   emit('update:modelValue', res.data)
 }
 

+ 5 - 2
src/components/UploadFile/src/UploadImgs.vue

@@ -78,7 +78,8 @@ const props = defineProps({
   fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
   height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
   width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
-  borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
+  borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px)
+  successMessage : propTypes.bool.def(true), // 上传成功提示信息
 })
 
 const { uploadUrl, httpRequest } = useUpload()
@@ -116,7 +117,9 @@ interface UploadEmits {
 
 const emit = defineEmits<UploadEmits>()
 const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
-  message.success('上传成功')
+  if(props.successMessage){
+    message.success('上传成功')
+  }
   // 删除自身
   const index = fileList.value.findIndex((item) => item.response?.data === res.data)
   fileList.value.splice(index, 1)

+ 204 - 128
src/views/Home/Index.vue

@@ -1,3 +1,53 @@
+
+  <!-- <div>
+                                                                  <el-card shadow="never">
+                                                                    <el-skeleton :loading="loading" animated>
+                                                                      <el-row :gutter="16" justify="space-between">
+                                                                        <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+                                                                          <div class="flex items-center">
+                                                                            <el-avatar :src="avatar" :size="70" class="mr-16px">
+                                                                              <img src="@/assets/imgs/avatar.gif" alt="" />
+                                                                            </el-avatar>
+                                                                            <div>
+                                                                              <div class="text-20px">
+                                                                                {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
+                                                                              </div>
+                                                                              <div class="mt-10px text-14px text-gray-500">
+                                                                                {{ t('workplace.toady') }},20℃ - 32℃!
+                                                                              </div>
+                                                                            </div>
+                                                                          </div>
+                                                                        </el-col>
+                                                                        <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+                                                                          <div class="h-70px flex items-center justify-end lt-sm:mt-10px">
+                                                                            <div class="px-8px text-right">
+                                                                              <div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>
+                                                                              <CountTo class="text-20px" :start-val="0" :end-val="totalSate.project" :duration="2600" />
+                                                                            </div>
+                                                                            <el-divider direction="vertical" />
+                                                                            <div class="px-8px text-right">
+                                                                              <div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>
+                                                                              <CountTo class="text-20px" :start-val="0" :end-val="totalSate.todo" :duration="2600" />
+                                                                            </div>
+                                                                            <el-divider direction="vertical" border-style="dashed" />
+                                                                            <div class="px-8px text-right">
+                                                                              <div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>
+                                                                              <CountTo class="text-20px" :start-val="0" :end-val="totalSate.access" :duration="2600" />
+                                                                            </div>
+                                                                          </div>
+                                                                        </el-col>
+                                                                      </el-row>
+                                                                    </el-skeleton>
+                                                                  </el-card>
+                                                                </div> -->
+  <!-- 日期
+                                                                                                  <div class="mt-16px text-12px text-gray-400">
+                                                                                                    {{ formatTime(item.date, 'yyyy-MM-dd') }}
+                                                                                                  </div> -->
+  <!-- 更多<el-link type="primary" :underline="false" href="https://github.com/yudaocode" target="_blank"> {{
+                                                    t('action.more') }}
+                                                  </el-link> -->
+
 <template>
   <el-skeleton :loading="loading" animated>
     <el-row :gutter="8">
@@ -239,19 +289,15 @@
 import { set } from 'lodash-es'
 import { EChartsOption, List } from 'echarts'
 import { formatTime } from '@/utils'
-
 import { useUserStore } from '@/store/modules/user'
 import { useWatermark } from '@/hooks/web/useWatermark'
 import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
 import { pieOptions, barOptions } from './echarts-data'
-
 import { center } from "diagram-js/lib/util/PositionUtil";
-
 import { reactive, onMounted, watchEffect } from "vue";
 import { vue3ScrollSeamless } from "vue3-scroll-seamless";
-
 import * as UserApi from '@/api/system/user'
-import { on } from 'events'
+import  { StudentAttendanceApi } from '@/api/system/studentAttendance'
 
 defineOptions({ name: 'Home' })
 
@@ -261,42 +307,29 @@ const { setWatermark } = useWatermark()
 const loading = ref(true)
 const avatar = userStore.getUser.avatar
 const username = userStore.getUser.nickname
-let pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
-// 获取统计数
-let totalSate = reactive<WorkplaceTotal>({
-  project: 0,
-  access: 0,
-  todo: 0
-})
 
+
+
+/*基本信息*/
 const detail = reactive({
-  "deptNum": undefined,
-  "teacherNum": undefined,
-  "studentNum": undefined
+  deptNum: undefined,
+  teacherNum: undefined,
+  studentNum: undefined
 })
-
-const getCount = async () => {
-  const data = {
-    project: 40,
-    access: 2340,
-    todo: 10,
-    college: 80,
-    normal: 125,
-    unusual: 5
-  }
-  totalSate = Object.assign(totalSate, data)
+const getDetail = async () => {
+  const data = await UserApi.getDetail()
+  console.log("基本信息", data);
+  detail.deptNum = data.deptNum
+  detail.teacherNum = data.teacherNum
+  detail.studentNum = data.studentNum
 }
-
 // 获取项目数
 let projects = reactive<Project[]>([])
 const getProject = async () => {
-  // console.log("getProject",detail.deptNum);
-
   const data = [
     {
       name: '学院工作间数量',
       icon: 'svg-icon:gzs',
-
       message: String(detail.deptNum) + '个',
       time: new Date()
     },
@@ -317,6 +350,146 @@ const getProject = async () => {
   projects = Object.assign(projects, data)
 }
 
+
+/**出勤统计 */
+// 获取统计数
+let totalSate = reactive<WorkplaceTotal>({
+  project: 0,
+  access: 0,
+  todo: 0
+})
+const getCount = async () => {
+  const data = {
+    project: 40,
+    access: 2340,
+    todo: 10,
+    college: 80,
+    normal: 125,
+    unusual: 5
+  }
+  totalSate = Object.assign(totalSate, data)
+}
+
+/**实时人数统计 */
+let pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
+
+/**周出勤情况 */
+let barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
+  const getWeekend = async () => {
+  try {
+    const res = await StudentAttendanceApi.getWeekendAttendance();
+    console.log("周出勤情况", res);
+     // 更新图表数据
+     barOptionsData.series = [
+      {
+        name: '正常出勤',
+        type: 'bar',
+        data: [res.normalNum], // 将正常出勤人数放入数据中
+      },
+      {
+        name: '缺勤',
+        type: 'bar',
+        data: [res.errorNum], // 将缺勤人数放入数据中
+      }
+    ];
+  } catch (error) {
+    console.error("获取周出勤情况失败:", error);
+  }
+};
+
+
+/**缺勤预警 */
+const list2 = reactive([
+  { trainNumber: '张一', destination: '101', departureTime: '09:00', ID: '10' },
+  { trainNumber: '张二', destination: '102', departureTime: '09:15', ID: '15' },
+  { trainNumber: '张三', destination: '103', departureTime: '09:30', ID: '13' },
+  { trainNumber: '张四', destination: '104', departureTime: '09:45', ID: '18' },
+  { trainNumber: '张五', destination: '105', departureTime: '10:00', ID: '19' },
+  { trainNumber: '李一', destination: '201', departureTime: '10:15', ID: '12' },
+  { trainNumber: '李二', destination: '202', departureTime: '10:30', ID: '02' },
+  { trainNumber: '李三', destination: '203', departureTime: '10:45', ID: '09' },
+  { trainNumber: '李四', destination: '204', departureTime: '11:00', ID: '16' },
+  { trainNumber: '李五', destination: '205', departureTime: '11:15', ID: '20' },
+  { trainNumber: '王一', destination: '301', departureTime: '11:30', ID: '28' },
+  { trainNumber: '王二', destination: '302', departureTime: '11:45', ID: '36' },
+  { trainNumber: '王三', destination: '303', departureTime: '12:00', ID: '07' },
+  { trainNumber: '王四', destination: '304', departureTime: '12:15', ID: '41' },
+  { trainNumber: '王五', destination: '305', departureTime: '12:30', ID: '15' },
+  { trainNumber: '王六', destination: '306', departureTime: '12:45', ID: '22' },
+  { trainNumber: '王七', destination: '307', departureTime: '13:00', ID: '27' }
+
+]);
+const class2Options = reactive({
+  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
+  limitMoveNum: list2.length,//无缝滚动列表元素的长度,一般设置为列表的长度
+  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
+});
+
+/**实时打卡状态 */
+//打卡滚动列表
+const list = reactive([
+  { trainNumber: '张一', destination: '101', departureTime: '09:00', status: '准点' },
+  { trainNumber: '张二', destination: '102', departureTime: '09:15', status: '准点' },
+  { trainNumber: '张三', destination: '103', departureTime: '09:30', status: '晚点' },
+  { trainNumber: '张四', destination: '104', departureTime: '09:45', status: '准点' },
+  { trainNumber: '张五', destination: '105', departureTime: '10:00', status: '准点' },
+  { trainNumber: '李一', destination: '201', departureTime: '10:15', status: '准点' },
+  { trainNumber: '李二', destination: '202', departureTime: '10:30', status: '晚点' },
+  { trainNumber: '李三', destination: '203', departureTime: '10:45', status: '准点' },
+  { trainNumber: '李四', destination: '204', departureTime: '11:00', status: '晚点' },
+  { trainNumber: '李五', destination: '205', departureTime: '11:15', status: '准点' },
+  { trainNumber: '王一', destination: '301', departureTime: '11:30', status: '准点' },
+  { trainNumber: '王二', destination: '302', departureTime: '11:45', status: '准点' },
+  { trainNumber: '王三', destination: '303', departureTime: '12:00', status: '晚点' },
+  { trainNumber: '王四', destination: '304', departureTime: '12:15', status: '准点' },
+  { trainNumber: '王五', destination: '305', departureTime: '12:30', status: '准点' },
+  { trainNumber: '王六', destination: '306', departureTime: '12:45', status: '准点' },
+  { trainNumber: '王七', destination: '307', departureTime: '13:00', status: '晚点' }
+
+]);
+const classOptions = reactive({
+  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
+  limitMoveNum: list.length,//无缝滚动列表元素的长度,一般设置为列表的长度
+  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
+
+});
+
+/** 学生毕业条件达成率 */
+//在线情况滚动列表
+const list1 = reactive([
+  { destination: '101', departureNumber: '98%' },
+  { destination: '102', departureNumber: '94%' },
+  { destination: '103', departureNumber: '96%' },
+  { destination: '104', departureNumber: '98%' },
+  { destination: '105', departureNumber: '93%' },
+  { destination: '201', departureNumber: '97%' },
+  { destination: '202', departureNumber: '95%' },
+  { destination: '203', departureNumber: '98%' },
+  { destination: '204', departureNumber: '96%' },
+  { destination: '205', departureNumber: '94%' },
+  { destination: '301', departureNumber: '97%' },
+  { destination: '302', departureNumber: '96%' },
+  { destination: '303', departureNumber: '95%' },
+  { destination: '304', departureNumber: '97%' },
+  { destination: '305', departureNumber: '98%' },
+  { destination: '306', departureNumber: '99%' },
+  { destination: '307', departureNumber: '96%' }
+
+]);
+const list1Options = reactive({
+  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
+  limitMoveNum: list1.length,//无缝滚动列表元素的长度,一般设置为列表的长度
+  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
+
+});
+
+onMounted(() => {
+  getDetail()
+  getWeekend()
+})
+
+
+
 // 获取通知公告
 let notice = reactive<Notice[]>([])
 const getNotice = async () => {
@@ -497,7 +670,7 @@ const getUserAccessSource = async () => {
 };
 
 
-let barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
+
 
 // 周活跃量
 const getWeeklyUserActivity = async () => {
@@ -543,103 +716,6 @@ const getWeeklyUserActivity = async () => {
   barOptionsData = Object.assign(barOptionsData, options);
 };
 
-//打卡滚动列表
-const list = reactive([
-  { trainNumber: '张一', destination: '101', departureTime: '09:00', status: '准点' },
-  { trainNumber: '张二', destination: '102', departureTime: '09:15', status: '准点' },
-  { trainNumber: '张三', destination: '103', departureTime: '09:30', status: '晚点' },
-  { trainNumber: '张四', destination: '104', departureTime: '09:45', status: '准点' },
-  { trainNumber: '张五', destination: '105', departureTime: '10:00', status: '准点' },
-  { trainNumber: '李一', destination: '201', departureTime: '10:15', status: '准点' },
-  { trainNumber: '李二', destination: '202', departureTime: '10:30', status: '晚点' },
-  { trainNumber: '李三', destination: '203', departureTime: '10:45', status: '准点' },
-  { trainNumber: '李四', destination: '204', departureTime: '11:00', status: '晚点' },
-  { trainNumber: '李五', destination: '205', departureTime: '11:15', status: '准点' },
-  { trainNumber: '王一', destination: '301', departureTime: '11:30', status: '准点' },
-  { trainNumber: '王二', destination: '302', departureTime: '11:45', status: '准点' },
-  { trainNumber: '王三', destination: '303', departureTime: '12:00', status: '晚点' },
-  { trainNumber: '王四', destination: '304', departureTime: '12:15', status: '准点' },
-  { trainNumber: '王五', destination: '305', departureTime: '12:30', status: '准点' },
-  { trainNumber: '王六', destination: '306', departureTime: '12:45', status: '准点' },
-  { trainNumber: '王七', destination: '307', departureTime: '13:00', status: '晚点' }
-
-]);
-const classOptions = reactive({
-  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
-  limitMoveNum: list.length,//无缝滚动列表元素的长度,一般设置为列表的长度
-  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
-
-});
-
-//在线情况滚动列表
-const list1 = reactive([
-  { destination: '101', departureNumber: '98%' },
-  { destination: '102', departureNumber: '94%' },
-  { destination: '103', departureNumber: '96%' },
-  { destination: '104', departureNumber: '98%' },
-  { destination: '105', departureNumber: '93%' },
-  { destination: '201', departureNumber: '97%' },
-  { destination: '202', departureNumber: '95%' },
-  { destination: '203', departureNumber: '98%' },
-  { destination: '204', departureNumber: '96%' },
-  { destination: '205', departureNumber: '94%' },
-  { destination: '301', departureNumber: '97%' },
-  { destination: '302', departureNumber: '96%' },
-  { destination: '303', departureNumber: '95%' },
-  { destination: '304', departureNumber: '97%' },
-  { destination: '305', departureNumber: '98%' },
-  { destination: '306', departureNumber: '99%' },
-  { destination: '307', departureNumber: '96%' }
-
-]);
-const list1Options = reactive({
-  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
-  limitMoveNum: list1.length,//无缝滚动列表元素的长度,一般设置为列表的长度
-  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
-
-});
-
-const list2 = reactive([
-  { trainNumber: '张一', destination: '101', departureTime: '09:00', ID: '10' },
-  { trainNumber: '张二', destination: '102', departureTime: '09:15', ID: '15' },
-  { trainNumber: '张三', destination: '103', departureTime: '09:30', ID: '13' },
-  { trainNumber: '张四', destination: '104', departureTime: '09:45', ID: '18' },
-  { trainNumber: '张五', destination: '105', departureTime: '10:00', ID: '19' },
-  { trainNumber: '李一', destination: '201', departureTime: '10:15', ID: '12' },
-  { trainNumber: '李二', destination: '202', departureTime: '10:30', ID: '02' },
-  { trainNumber: '李三', destination: '203', departureTime: '10:45', ID: '09' },
-  { trainNumber: '李四', destination: '204', departureTime: '11:00', ID: '16' },
-  { trainNumber: '李五', destination: '205', departureTime: '11:15', ID: '20' },
-  { trainNumber: '王一', destination: '301', departureTime: '11:30', ID: '28' },
-  { trainNumber: '王二', destination: '302', departureTime: '11:45', ID: '36' },
-  { trainNumber: '王三', destination: '303', departureTime: '12:00', ID: '07' },
-  { trainNumber: '王四', destination: '304', departureTime: '12:15', ID: '41' },
-  { trainNumber: '王五', destination: '305', departureTime: '12:30', ID: '15' },
-  { trainNumber: '王六', destination: '306', departureTime: '12:45', ID: '22' },
-  { trainNumber: '王七', destination: '307', departureTime: '13:00', ID: '27' }
-
-]);
-const class2Options = reactive({
-  step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
-  limitMoveNum: list2.length,//无缝滚动列表元素的长度,一般设置为列表的长度
-  direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
-
-});
-
-const getDetail = async () => {
-  loading.value = true
-  try {
-    // const D = await UserApi.getDetail();
-    // detail.deptNum = D.deptNum
-    // detail.studentNum = D.studentNum
-    // detail.teacherNum = D.teacherNum
-
-
-  } finally {
-    loading.value = false
-  }
-}
-
 const getAllApi = async () => {
   await Promise.all([
     await getDetail(),

+ 5 - 2
src/views/Profile/components/FaceInfo.vue

@@ -2,7 +2,9 @@
   <ContentWrap>
     <el-form ref="formRef" :model="formData" label-width="100px">
       <el-form-item label="人脸信息" prop="photoUrl">
-        <UploadImg v-model="formData.photoUrl">
+        <UploadImg v-model="formData.photoUrl"       
+          successMessage = "加载成功,请点击确认上传!!"
+        >
           <template #default>
             <el-image
               v-if="formData.photoUrl"
@@ -13,6 +15,8 @@
             />
           </template>
         </UploadImg>
+
+        
       </el-form-item>
 
       <el-form-item>
@@ -46,7 +50,6 @@ const submitForm = async () => {
     const data = formData as unknown as ProfileVO;
     const res = await importUserData(data.photoUrl);
     console.log('API 响应:', res);
-   
       message.success('照片上传成功');
       // 在这里处理成功上传后的逻辑,例如更新用户信息
 

+ 0 - 2
src/views/system/graduateStudent/UserForm.vue

@@ -192,9 +192,7 @@ const formData = ref({
   workPlace:""
 })
 const formRules = reactive<FormRules>({
-  username: [{ required: true, message: '账号不能为空', trigger: 'blur' }],
   nickname: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
-  password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }],
   email: [
     { required: true, message: '邮箱不能为空', trigger: 'blur' },
     {

+ 2 - 1
src/views/system/studentAttendanceManage/studentAttendanceExcused/StudentAttendanceForm.vue

@@ -84,6 +84,7 @@ const formRef = ref() // 表单 Ref
 /** 日期选择器的禁用日期 */
 const disabledDate = (date) => {
   return date.getTime() < new Date().setHours(0, 0, 0, 0); // 禁用今天之前的日期
+  // return date.getTime() <= new Date().setHours(0, 0, 0, 0); // 禁用今天之前的日期,包括今天
 };
 
 /** 打开弹窗 */
@@ -124,7 +125,7 @@ const submitForm = async () => {
       }
     }
     
-    message.success(t('common.operationSuccess'));
+    message.success(t('提交成功'));
     dialogVisible.value = false;
 
     // 发送操作成功的事件