From 42a1a434f77154746038c476ef70ca9be0b8e4e0 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期一, 19 一月 2026 18:02:46 +0800
Subject: [PATCH] fix: 完成资金管理,财务对账

---
 src/views/collaborativeApproval/enterpriseBook/index.vue |  798 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 798 insertions(+), 0 deletions(-)

diff --git a/src/views/collaborativeApproval/enterpriseBook/index.vue b/src/views/collaborativeApproval/enterpriseBook/index.vue
new file mode 100644
index 0000000..0b33a32
--- /dev/null
+++ b/src/views/collaborativeApproval/enterpriseBook/index.vue
@@ -0,0 +1,798 @@
+<template>
+  <div class="app-container">
+    <!-- 澶撮儴瀵艰埅 -->
+    <!-- <div class="header">
+      <h2>浼佷笟閫氳褰曠鐞�</h2>
+      <p>绠$悊涓汉銆佸叕鍏卞拰鍗曚綅鐨勮仈绯绘柟寮�</p>
+    </div> -->
+
+    <!-- 鏍囩椤靛垏鎹� -->
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange" type="border-card">
+      <el-tab-pane label="涓汉閫氳褰�" name="personal">
+        <div class="tab-content">
+          <!-- 鎼滅储妗� -->
+          <el-input
+            v-model="personalSearch.staffName" 
+            placeholder="鎼滅储鑱旂郴浜�"
+            clearable
+            prefix-icon="Search"
+            class="search-input"
+            @keyup.enter="getPersonalContactsList"
+          />
+          <el-button style="margin: 0 0 20px 20px;" type="primary" @click="showAddContactDialog=true">娣诲姞鑱旂郴浜�</el-button>
+          <!-- 鑱旂郴浜哄垪琛� -->
+          <div class="contact-list">
+            <div 
+              v-for="contact in personalContacts" 
+              :key="contact.id"
+              class="contact-card"
+              @click="showContactDetail(contact)"
+            >
+              <div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
+              <div class="contact-info">
+                <h4>{{ contact.staffName }}</h4>
+                <p>{{ contact.profession }} - {{ contact.postJob }}</p>
+                <div class="contact-phone">{{ contact.phone }}</div>
+              </div>
+              <div class="contact-actions">
+                <!-- <el-button 
+                  type="text" 
+                  icon="Phone"
+                  @click.stop="callContact(contact)"
+                ></el-button> -->
+                <el-button 
+                  type="text" 
+                  icon="Message"
+                  @click.stop="messageContact(contact)"
+                ></el-button>
+                <el-button 
+                  type="text" 
+                  icon="Delete"
+                  @click.stop="removeFromPersonalContacts(contact.id)"
+                ></el-button>
+              </div>
+            </div>
+            
+            <!-- 绌虹姸鎬�
+            <div v-if="personalContacts.length === 0 && !loading" class="empty-state">
+              <el-empty description="鏆傛棤鑱旂郴浜�" />
+              <el-button type="primary" @click="showAddContactDialog=true">娣诲姞鑱旂郴浜�</el-button>
+            </div> -->
+          </div>
+        </div>
+      </el-tab-pane>
+      
+      <el-tab-pane label="鍏叡閫氳褰�" name="public">
+        <div class="tab-content">
+          <!-- 鎼滅储妗� -->
+          <el-input
+            v-model="publicSearch.staffName" 
+            placeholder="鎼滅储鍏叡鑱旂郴浜�"
+            clearable
+            prefix-icon="Search"
+            class="search-input"
+            @keyup.enter="getPublicContactsList"
+          />
+          
+          <!-- 鑱旂郴浜哄垪琛� publicContacts-->
+          <div class="contact-list">
+            <div 
+              v-for="contact in EmployeeList" 
+              :key="contact.id"
+              class="contact-card"
+              @click="showContactDetail(contact)"
+            >
+              <div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
+              <div class="contact-info">
+                <h4>{{ contact.staffName }}</h4>
+                <p>{{ contact.postJob }} - {{ contact.profession }}</p>
+                <div class="contact-phone">{{ contact.phone }}</div>
+              </div>
+              <div class="contact-actions">
+                <!-- <el-button 
+                  type="text" 
+                  icon="Phone"
+                  @click.stop="callContact(contact)"
+                ></el-button> -->
+                <el-button 
+                  type="text" 
+                  icon="Message"
+                  @click.stop="messageContact(contact)"
+                ></el-button>
+                <el-button 
+                  type="text" 
+                  icon="Delete"
+                  :type="isInPersonalContacts(contact.id) ? 'primary' : ''"
+                  @click.stop="togglePersonalContact(contact)"
+                ></el-button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-tab-pane>
+      
+      <el-tab-pane label="鍗曚綅閫氳褰�" name="company">
+        <div class="tab-content">
+          <div class="company-contacts-layout">
+            <!-- 宸︿晶閮ㄩ棬鏍� -->
+            <div class="department-tree">
+              <!-- <h3>閮ㄩ棬缁撴瀯</h3>
+              <el-tree
+                :data="departmentTree"
+                :props="{ label: 'deptName', children: 'children' }"
+                node-key="deptId"
+                ref="departmentTreeRef"
+                highlight-current
+                default-expand-all
+                @node-click="handleDepartmentClick"
+              /> -->
+              <el-col >
+                <div class="head-container">
+                  <el-input
+                    v-model="deptName"
+                    placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+                    clearable
+                    prefix-icon="Search"
+                    style="margin-bottom: 20px"
+                  />
+                </div>
+                <div class="head-container">
+                  <el-tree
+                    :data="departmentTree"
+                    :props="{ label: 'label', children: 'children' }"
+                    :expand-on-click-node="false"
+                    :filter-node-method="filterNode"
+                    ref="deptTreeRef"
+                    node-key="id"
+                    highlight-current
+                    default-expand-all
+                    @node-click="handleDepartmentClick"
+                  />
+                </div>
+              </el-col>
+            </div>
+            
+            <!-- 鍙充晶閮ㄩ棬鎴愬憳 -->
+            <div class="department-members">
+              <h3>{{ currentDepartment?.label || '鍏ㄩ儴鎴愬憳' }}</h3>
+              <el-input
+                v-model="companySearch.staffName" 
+                placeholder="鎼滅储閮ㄩ棬鎴愬憳"
+                clearable
+                prefix-icon="Search"
+                class="search-input"
+                @keyup.enter="getCompanyContactsList"
+              />
+              
+              <div class="contact-list">
+                <div 
+                  v-for="contact in companyContacts" 
+                  :key="contact.id"
+                  class="contact-card"
+                  @click="showContactDetail(contact)"
+                >
+                  <div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
+                  <div class="contact-info">
+                    <h4>{{ contact.staffName }}</h4>
+                    <p>{{ contact.profession }}</p>
+                    <div class="contact-phone">{{ contact.phone }}</div>
+                  </div>
+                  <div class="contact-actions">
+                    
+                    <el-button 
+                      type="text" 
+                      icon="Message"
+                      @click.stop="messageContact(contact)"
+                    ></el-button>
+                    <el-button 
+                      type="text" 
+                      icon="Delete"
+                      :type="isInPersonalContacts(contact.id) ? 'primary' : ''"
+                      @click.stop="togglePersonalContact(contact)"
+                    ></el-button>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+    
+    <!-- 鑱旂郴浜鸿鎯呭脊绐� -->
+    <el-dialog 
+      v-model="showDetailDialog" 
+      title="鑱旂郴浜鸿鎯�"
+      width="400px"
+    >
+      <div v-if="selectedContact" class="contact-detail">
+        <div class="detail-avatar">{{ selectedContact.staffName?.charAt(0) }}</div>
+        <h3>{{ selectedContact.staffName }}</h3>
+        <p class="detail-position">{{ selectedContact.profession }} - {{ selectedContact.postJob }}</p>
+        
+        <div class="detail-info">
+          <div class="info-item">
+            <span class="label">缂栧彿锛�</span>
+            <span class="value">{{ selectedContact.staffNo }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鎵嬫満鍙风爜锛�</span>
+            <span class="value">{{ selectedContact.phone }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">閭锛�</span>
+            <span class="value">{{ selectedContact.sex }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">浣忓潃锛�</span>
+            <span class="value">{{ selectedContact.adress || '鏆傛棤' }}</span>
+          </div>
+        </div>
+      </div>
+      <template #footer>
+        <el-button @click="showDetailDialog = false">鍏抽棴</el-button>
+        <el-button 
+          type="primary" 
+          v-if="activeTab !== 'personal'"
+          @click="togglePersonalContact(selectedContact); showDetailDialog = false"
+        >
+          {{ isInPersonalContacts(selectedContact?.id) ? '浠庝釜浜洪�氳褰曠Щ闄�' : '娣诲姞鍒颁釜浜洪�氳褰�' }}
+        </el-button>
+      </template>
+    </el-dialog>
+    
+    <!-- 娣诲姞鑱旂郴浜哄脊绐� -->
+    <el-dialog 
+      v-model="showAddContactDialog"
+      title="娣诲姞鑱旂郴浜�"
+      width="500px"
+    >
+      <el-form :model="addContactForm" ref="addContactFormRef" label-width="80px">
+        <!-- <el-form-item label="濮撳悕" prop="name">
+          <el-input v-model="addContactForm.name" placeholder="璇疯緭鍏ュ鍚�" />
+        </el-form-item>
+        <el-form-item label="鎵嬫満鍙风爜" prop="phone">
+          <el-input v-model="addContactForm.phone" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" />
+        </el-form-item>
+        <el-form-item label="閭" prop="email">
+          <el-input v-model="addContactForm.email" placeholder="璇疯緭鍏ラ偖绠�" />
+        </el-form-item>
+        <el-form-item label="閮ㄩ棬" prop="department">
+          <el-input v-model="addContactForm.department" placeholder="璇疯緭鍏ラ儴闂�" />
+        </el-form-item> -->
+        <el-form-item label="濮撳悕" prop="name">
+          <!-- <select v-model="addContactForm.contactId">
+            <option v-for="item in EmployeeList" :key="item.id" :value="item.id">{{ item.staffName }}</option> 
+          </select> -->
+          <el-select v-model="addContactForm.contactId" placeholder="璇烽�夋嫨" style="width: 100%">
+            <el-option
+              v-for="option in EmployeeList"
+              :key="option.id"
+              :label="option.staffName"
+              :value="option.id"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="showAddContactDialog = false">鍙栨秷</el-button>
+        <el-button type="primary" @click="addContact">纭畾</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import {
+  getPersonalContacts,
+  addPersonalContact,
+  removePersonalContact,
+  getPublicContacts,
+  getCompanyContacts,
+  getDepartmentTree,
+  getEmployeeDetail
+} from '@/api/collaborativeApproval/enterpriseBook.js'
+import { getUserProfile } from '@/api/system/user.js'
+import {staffJoinListPage} from "@/api/personnelManagement/onboarding.js";
+import {
+  changeUserStatus,
+  listUser,
+  resetUserPwd,
+  delUser,
+  getUser,
+  updateUser,
+  addUser,
+  deptTreeSelect,
+} from "@/api/system/user";
+
+// 鏍囩椤电姸鎬�
+const activeTab = ref('personal')
+const loading = ref(false)
+const EmployeeList = ref([])
+const page = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+})
+// 涓汉閫氳褰曟暟鎹�
+const personalContacts = ref([])
+const personalSearch = ref({
+  staffName: '',
+})
+
+// 鍏叡閫氳褰曟暟鎹�
+const publicContacts = ref([])
+const publicSearch = ref({
+  staffName: '',
+  staffState: 1
+})
+
+// 鍗曚綅閫氳褰曟暟鎹�
+const companyContacts = ref([])
+const companySearch = ref({
+  staffName: '',
+  staffState: 1
+})
+const departmentTree = ref([])
+const departmentTreeRef = ref(null)
+const currentDepartment = ref(null)
+
+// 寮圭獥鐘舵��
+const showDetailDialog = ref(false)
+const showAddContactDialog = ref(false)
+const selectedContact = ref(null)
+
+// 娣诲姞鑱旂郴浜鸿〃鍗�
+const addContactForm = reactive({
+  contactId: '',
+  name: '',
+  phone: '',
+  email: '',
+  department: '',
+  position: ''
+})
+const addContactFormRef = ref(null)
+
+// 鍒濆鍖栨暟鎹�
+onMounted(() => {
+  getEmployeeList()
+  getPersonalContactsList()
+  if (activeTab.value === 'public') {
+    getPublicContactsList()
+  } else if (activeTab.value === 'company') {
+    getDepartmentTreeData()
+    getCompanyContactsList()
+  }
+})
+
+// 澶勭悊鏍囩椤靛垏鎹�
+const handleTabChange = (tabName) => {
+  if (tabName === 'public') {
+    getPublicContactsList()
+  } else if (tabName === 'company') {
+    getDepartmentTreeData()
+    getCompanyContactsList()
+  }
+}
+
+// 鑾峰彇涓汉閫氳褰曞垪琛�
+const getPersonalContactsList = async () => {
+  loading.value = true
+  getPersonalContacts(page,personalSearch.value).then(res => {
+    personalContacts.value = res.data.records
+  })
+  loading.value = false
+}
+
+// 鑾峰彇鍏叡閫氳褰曞垪琛�
+const getPublicContactsList = async () => {
+  loading.value = true
+  getEmployeeList()
+  // publicContacts.value = generateMockPublicContacts()
+  loading.value = false
+}
+  //鑾峰彇鍛樺伐鍒楄〃
+const getEmployeeList = async () => {
+  staffJoinListPage(publicSearch.value).then(res => {
+    console.log(res.data.records)
+      EmployeeList.value = res.data.records
+    }).catch(err => {})
+}
+// 鑾峰彇鍗曚綅閫氳褰曞垪琛�
+const getCompanyContactsList = async () => {
+  loading.value = true
+    staffJoinListPage(companySearch.value).then(res => {
+    // console.log(res.data.records)
+      companyContacts.value = res.data.records
+    }).catch(err => {})
+
+  loading.value = false
+ loading.value = false
+  // }
+}
+
+// 鑾峰彇閮ㄩ棬鏍戠粨鏋�
+const getDepartmentTreeData = async () => {
+    deptTreeSelect().then((response) => {
+    // console.log("Tree",response.data)
+    departmentTree.value = response.data;
+    // enabledDeptOptions.value = filterDisabledDept(
+    //   JSON.parse(JSON.stringify(response.data))
+    // );
+  });
+}
+// /** 杩囨护绂佺敤鐨勯儴闂� */
+// function filterDisabledDept(deptList) {
+//   return deptList.filter((dept) => {
+//     if (dept.disabled) {
+//       return false;
+//     }
+//     if (dept.children && dept.children.length) {
+//       dept.children = filterDisabledDept(dept.children);
+//     }
+//     return true;
+//   });
+// }
+// 澶勭悊閮ㄩ棬鐐瑰嚮
+const handleDepartmentClick = (data) => {
+  // console.log("鐐瑰嚮",data)
+  companySearch.value = {
+    ...companySearch.value,
+    deptId: data.id,
+  }
+  // currentDepartment.value = data.id
+  // 鑾峰彇璇ラ儴闂ㄧ殑鎴愬憳鍒楄〃
+
+  getCompanyContactsList()
+}
+
+// 鏄剧ず鑱旂郴浜鸿鎯�
+const showContactDetail = async (contact) => {
+  selectedContact.value = contact
+  showDetailDialog.value = true
+}
+
+// 鎷ㄦ墦鐢佃瘽
+const callContact = (contact) => {
+  ElMessage.info(`姝e湪鎷ㄦ墦 ${contact.name} 鐨勭數璇�: ${contact.phone}`)
+}
+
+// 鍙戦�佹秷鎭�
+const messageContact = (contact) => {
+  ElMessage.info(`姝e湪鍙戦�佹秷鎭粰 ${contact.name}`)
+}
+
+
+// 娣诲姞鑱旂郴浜�
+const addContact = async () => {
+  
+  try {
+    // 琛ㄥ崟楠岃瘉
+    // if (!addContactForm.name || !addContactForm.phone) {
+    //   ElMessage.warning('璇峰~鍐欏鍚嶅拰鎵嬫満鍙风爜')
+    //   return
+    // }
+    
+    const res = await addPersonalContact(addContactForm)
+    if (res.code === 200) {
+      ElMessage.success('娣诲姞鎴愬姛')
+      showAddContactDialog.value = false
+      getPersonalContactsList()
+      // 閲嶇疆琛ㄥ崟
+      Object.keys(addContactForm).forEach(key => {
+        addContactForm[key] = ''
+      })
+    }
+  } catch (error) {
+    ElMessage.error('娣诲姞澶辫触')
+    // 妯℃嫙娣诲姞鎴愬姛
+    personalContacts.value.push({
+      ...addContactForm,
+      id: Date.now(),
+      createTime: new Date().toISOString()
+    })
+    ElMessage.success('娣诲姞鎴愬姛')
+    showAddContactDialog.value = false
+    // 閲嶇疆琛ㄥ崟
+    Object.keys(addContactForm).forEach(key => {
+      addContactForm[key] = ''
+    })
+  }
+}
+
+// 浠庝釜浜洪�氳褰曠Щ闄�
+const removeFromPersonalContacts = async (contactId) => {
+  ElMessageBox.confirm(
+    '纭畾瑕佷粠涓汉閫氳褰曚腑绉婚櫎璇ヨ仈绯讳汉鍚楋紵',
+    '鎻愮ず',
+    {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    }
+  ).then(async () => {
+    try {
+      const res = await removePersonalContact(contactId)
+      if (res.code === 200) {
+        ElMessage.success('绉婚櫎鎴愬姛')
+        getPersonalContactsList()
+      }
+    } catch (error) {
+      ElMessage.error('绉婚櫎澶辫触')
+      // 妯℃嫙绉婚櫎鎴愬姛
+      // personalContacts.value = personalContacts.value.filter(item => item.id !== contactId)
+      ElMessage.success('绉婚櫎鎴愬姛')
+    }
+  })
+}
+
+// 鍒囨崲涓汉閫氳褰�
+const togglePersonalContact = async (contact) => {
+  const isInPersonal = isInPersonalContacts(contact.id)
+  const contactId = contact.id
+  if (isInPersonal) {
+    // 浠庝釜浜洪�氳褰曠Щ闄�
+    //鏍规嵁contactId鏌ユ壘personalContacts涓搴旂殑椤癸紝鐒跺悗鍒犻櫎璇ラ」
+    const index = personalContacts.value.findIndex(item => item.contactId === contactId)
+    const personId = personalContacts.value[index].id
+    // console.log(personId)
+    await removeFromPersonalContacts(personId)
+  } else {
+    // 娣诲姞鍒颁釜浜洪�氳褰�
+    try {
+      const res = await addPersonalContact({contactId: contactId})
+      if (res.code === 200) {
+        ElMessage.success('娣诲姞鎴愬姛')
+        getPersonalContactsList()
+      }
+    } catch (error) {
+      ElMessage.error('娣诲姞澶辫触')
+      // 妯℃嫙娣诲姞鎴愬姛
+      // personalContacts.value.push({
+      //   ...contact,
+      //   id: contact.id || Date.now(),
+      //   createTime: new Date().toISOString()
+      // })
+      // ElMessage.success('娣诲姞鎴愬姛')
+    }
+  }
+}
+
+// 妫�鏌ユ槸鍚﹀湪涓汉閫氳褰曚腑
+const isInPersonalContacts = (contactId) => {
+  return personalContacts.value.some(item => item.contactId === contactId)
+}
+
+// 鐢熸垚妯℃嫙閮ㄩ棬鏍戞暟鎹�
+const generateMockDepartmentTree = () => {
+  return [
+    {
+      deptId: 1,
+      deptName: '鎶�鏈儴',
+      children: [
+        {
+          deptId: 101,
+          deptName: '鍓嶇缁�'
+        },
+        {
+          deptId: 102,
+          deptName: '鍚庣缁�'
+        },
+        {
+          deptId: 103,
+          deptName: '娴嬭瘯缁�'
+        }
+      ]
+    },
+    {
+      deptId: 2,
+      deptName: '浜у搧閮�'
+    },
+    {
+      deptId: 3,
+      deptName: '浜轰簨閮�'
+    },
+    {
+      deptId: 4,
+      deptName: '璐㈠姟閮�'
+    }
+  ]
+}
+
+// 鐢熸垚妯℃嫙鍗曚綅閫氳褰曟暟鎹�
+// const generateMockCompanyContacts = (deptName) => {
+//   const allContacts = getEmployeeList()
+  
+//   if (deptName) {
+//     return allContacts.filter(contact => contact.postJob === deptName)
+//   }
+//   return allContacts
+// }
+
+</script>
+
+<style scoped>
+.header {
+  margin-bottom: 20px;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 8px;
+}
+
+.header h2 {
+  margin: 0 0 5px 0;
+  color: #303133;
+}
+
+.header p {
+  margin: 0;
+  color: #909399;
+  font-size: 14px;
+}
+
+.tab-content {
+  padding: 15px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+}
+
+.search-input {
+  margin-bottom: 20px;
+  width: 300px;
+}
+
+.contact-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 15px;
+}
+
+.contact-card {
+  display: flex;
+  align-items: center;
+  padding: 15px;
+  width: 500px;
+  background: #f8f9fa;
+  border-radius: 8px;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.contact-card:hover {
+  background: #e9ecef;
+  transform: translateY(-2px);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.contact-avatar {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 48px;
+  height: 48px;
+  background: #409eff;
+  color: #fff;
+  font-size: 20px;
+  font-weight: bold;
+  border-radius: 50%;
+  margin-right: 15px;
+}
+
+.contact-info {
+  flex: 1;
+}
+
+.contact-info h4 {
+  margin: 0 0 5px 0;
+  color: #303133;
+  font-size: 16px;
+}
+
+.contact-info p {
+  margin: 0 0 5px 0;
+  color: #606266;
+  font-size: 14px;
+}
+
+.contact-phone {
+  color: #409eff;
+  font-size: 14px;
+}
+
+.contact-actions {
+  display: flex;
+  gap: 5px;
+}
+
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 60px 20px;
+  color: #909399;
+}
+
+.company-contacts-layout {
+  display: flex;
+  gap: 20px;
+}
+
+.department-tree {
+  width: 250px;
+  padding: 15px;
+  background: #f8f9fa;
+  border-radius: 8px;
+}
+
+.department-tree h3 {
+  margin: 0 0 15px 0;
+  padding-bottom: 10px;
+  border-bottom: 1px solid #e4e7ed;
+  color: #303133;
+  font-size: 16px;
+}
+
+.department-members {
+  flex: 1;
+}
+
+.department-members h3 {
+  margin: 0 0 15px 0;
+  color: #303133;
+  font-size: 16px;
+}
+
+.contact-detail {
+  text-align: center;
+}
+
+.detail-avatar {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 80px;
+  height: 80px;
+  background: #409eff;
+  color: #fff;
+  font-size: 32px;
+  font-weight: bold;
+  border-radius: 50%;
+  margin: 0 auto 20px;
+}
+
+.contact-detail h3 {
+  margin: 0 0 10px 0;
+  color: #303133;
+  font-size: 20px;
+}
+
+.detail-position {
+  margin: 0 0 30px 0;
+  color: #606266;
+  font-size: 14px;
+}
+
+.detail-info {
+  text-align: left;
+}
+
+.info-item {
+  margin-bottom: 15px;
+}
+
+.info-item .label {
+  display: inline-block;
+  width: 100px;
+  color: #909399;
+  font-size: 14px;
+}
+
+.info-item .value {
+  color: #303133;
+  font-size: 14px;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3