| | |
| | | const sideTheme = computed(() => settingsStore.sideTheme)
|
| | | const theme = computed(() => settingsStore.theme)
|
| | | const isCollapse = computed(() => !appStore.sidebar.opened)
|
| | | console.log(44444, settingsStore.isDark, sideTheme.value)
|
| | |
|
| | | // è·åèåèæ¯è²
|
| | | const getMenuBackground = computed(() => {
|
| | |
| | | </el-table-column> |
| | | <el-table-column label="æä½" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('holiday', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('holiday', scope.row)">å é¤</el-button> |
| | | <el-button type="primary" link @click="openDialog('holiday', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="deleteItem('holiday', scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="æä½" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('annual', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('annual', scope.row)">å é¤</el-button> |
| | | <el-button type="primary" link @click="openDialog('annual', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="deleteItem('annual', scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="æä½" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('overtime', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('overtime', scope.row)">å é¤</el-button> |
| | | <el-button type="primary" link @click="openDialog('overtime', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="deleteItem('overtime', scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="æä½" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('worktime', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('worktime', scope.row)">å é¤</el-button> |
| | | <el-button type="primary" link @click="openDialog('worktime', 'edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="deleteItem('worktime', scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | problem: "大é¢ååå®¡æ¹æµç¨å¤æï¼å®¡æ¹æ¶é´é¿ï¼å½±åä¸å¡è¿å±", |
| | | solution: "建ç«ç»¿è²ééï¼å¯¹ç¬¦åæ¡ä»¶çååéç¨ç®åå®¡æ¹æµç¨ï¼ç±é¨é¨è´è´£äººç´æ¥å®¡æ¹ï¼å¹³åå®¡æ¹æ¶é´ä»3天缩çè³1天", |
| | | keyPoints: "绿è²é鿡件,ç®åæµç¨,å®¡æ¹æé,æ¶é´æ§å¶", |
| | | creator: "å¼ ç»ç", |
| | | creator: "éå¿å¼º", |
| | | usageCount: 15, |
| | | createTime: "2024-01-15 10:30:00" |
| | | }, |
| | |
| | | problem: `å¨${randomScenario}è¿ç¨ä¸éå°çé®é¢æè¿°...`, |
| | | solution: `é对${randomScenario}çè§£å³æ¹æ¡åæä½æ¥éª¤...`, |
| | | keyPoints: "å
³é®è¦ç¹1,å
³é®è¦ç¹2,å
³é®è¦ç¹3,å
³é®è¦ç¹4", |
| | | creator: ["å¼ ç»ç", "æä¸»ç®¡", "çä¸å", "åæ»ç"][Math.floor(Math.random() * 4)], |
| | | creator: ["éå¿å¼º", "åé
å©·", "ç建å½", "赵丽å"][Math.floor(Math.random() * 4)], |
| | | usageCount: Math.floor(Math.random() * 20) + 1, |
| | | createTime: now.toLocaleString() |
| | | }; |
| | |
| | | startTime: '2024-01-15 09:00:00', |
| | | endTime: '2024-01-15 10:30:00', |
| | | location: 'ä¼è®®å®¤A', |
| | | host: 'å¼ ç»ç', |
| | | participants: ['å¼ ç»ç', 'æå·¥ç¨å¸', 'ç设计å¸', 'èµµæµè¯å'], |
| | | host: 'éå¿å¼º', |
| | | participants: ['éå¿å¼º', 'åé
å©·', 'ç建å½', '赵丽å'], |
| | | agenda: [ |
| | | { time: '09:00-09:15', content: 'ä¸å¨å·¥ä½æ»ç»', status: 'completed' }, |
| | | { time: '09:15-09:45', content: 'æ¬å¨å¼å计å', status: 'active' }, |
| | |
| | | startTime: '2024-01-15 14:00:00', |
| | | endTime: '2024-01-15 15:00:00', |
| | | location: '线ä¸ä¼è®®', |
| | | host: 'éæ»ç', |
| | | participants: ['éæ»ç', 'å产åç»ç', 'å客æ·ç»ç', '客æ·ä»£è¡¨'], |
| | | host: 'éå¿å¼º', |
| | | participants: ['éå¿å¼º', 'åé
å©·', 'åæå', '客æ·ä»£è¡¨'], |
| | | agenda: [ |
| | | { time: '14:00-14:20', content: 'éæ±èæ¯ä»ç»', status: 'pending' }, |
| | | { time: '14:20-14:40', content: 'åè½éæ±åæ', status: 'pending' }, |
| | |
| | | console.error('è·ååå·¥å表失败:', error); |
| | | // 妿æ¥å£é½å¤±è´¥ï¼ä½¿ç¨é»è®¤æ°æ® |
| | | employees.value = [ |
| | | { label: "å¼ ä¸", value: "001", dept: "ææ¯é¨", phone: "13800138001", email: "zhangsan@company.com", status: "0" }, |
| | | { label: "æå", value: "002", dept: "éå®é¨", phone: "13800138002", email: "lisi@company.com", status: "0" }, |
| | | { label: "çäº", value: "003", dept: "人äºé¨", phone: "13800138003", email: "wangwu@company.com", status: "0" } |
| | | { label: "éå¿å¼º", value: "001", dept: "ææ¯é¨", phone: "13800138001", email: "chenzhiqiang@company.com", status: "0" }, |
| | | { label: "åé
å©·", value: "002", dept: "éå®é¨", phone: "13800138002", email: "liuyating@company.com", status: "0" }, |
| | | { label: "ç建å½", value: "003", dept: "人äºé¨", phone: "13800138003", email: "wangjianguo@company.com", status: "0" } |
| | | ]; |
| | | } finally { |
| | | employeesLoading.value = false; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-card class="box-card"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>åå
¬ç©èµç³è¯·ç®¡ç</span> |
| | | <el-button type="primary" @click="showApplyDialog = true"> |
| | | <el-icon><Plus /></el-icon> |
| | | æ°å»ºç³è¯· |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- æç´¢åºå --> |
| | | <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> |
| | | <el-form-item label="ç³è¯·ç¼å·" prop="applyNo"> |
| | | <el-input |
| | | v-model="queryParams.applyNo" |
| | | placeholder="请è¾å
¥ç³è¯·ç¼å·" |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·äºº" prop="applicant"> |
| | | <el-input |
| | | v-model="queryParams.applicant" |
| | | placeholder="请è¾å
¥ç³è¯·äºº" |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="è¯·éæ©ç¶æ" clearable style="width: 200px"> |
| | | <el-option label="å¾
审æ¹" value="pending" /> |
| | | <el-option label="å·²éè¿" value="approved" /> |
| | | <el-option label="å·²æç»" value="rejected" /> |
| | | <el-option label="已忾" value="issued" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery"> |
| | | <el-icon><Search /></el-icon> |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button @click="resetQuery"> |
| | | <el-icon><Refresh /></el-icon> |
| | | éç½® |
| | | </el-button> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleExport"> |
| | | <el-icon><Download /></el-icon> |
| | | å¯¼åº |
| | | </el-button> |
| | | <el-button type="success" @click="handleBatchApprove" :disabled="multipleSelection.length === 0"> |
| | | <el-icon><Check /></el-icon> |
| | | æ¹éå®¡æ¹ |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- è¡¨æ ¼åºå --> |
| | | <el-table |
| | | v-loading="loading" |
| | | :data="suppliesList" |
| | | @selection-change="handleSelectionChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="ç³è¯·ç¼å·" align="center" prop="applyNo" width="180" /> |
| | | <el-table-column label="ç³è¯·äºº" align="center" prop="applicant" width="120" /> |
| | | <el-table-column label="é¨é¨" align="center" prop="department" width="120" /> |
| | | <el-table-column label="ç©èµç±»å" align="center" prop="supplyType" width="120" /> |
| | | <el-table-column label="ç³è¯·æ°é" align="center" prop="quantity" width="100" /> |
| | | <el-table-column label="ç³è¯·åå " align="center" prop="reason" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column label="ç³è¯·ç¶æ" align="center" prop="status" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStatusType(scope.row.status)"> |
| | | {{ getStatusText(scope.row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç³è¯·æ¶é´" align="center" prop="applyTime" width="180" /> |
| | | <el-table-column label="审æ¹äºº" align="center" prop="approver" width="120" /> |
| | | <el-table-column label="å®¡æ¹æ¶é´" align="center" prop="approveTime" width="180" /> |
| | | <el-table-column label="åæ¾æ¶é´" align="center" prop="issueTime" width="180" /> |
| | | <el-table-column label="æä½" align="center" fixed="right" class-name="small-padding fixed-width" width="200"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | v-if="scope.row.status === 'pending'" |
| | | type="primary" |
| | | link |
| | | @click="handleApprove(scope.row)" |
| | | > |
| | | å®¡æ¹ |
| | | </el-button> |
| | | <el-button |
| | | v-if="scope.row.status === 'approved'" |
| | | type="success" |
| | | link |
| | | @click="handleIssue(scope.row)" |
| | | > |
| | | åæ¾ |
| | | </el-button> |
| | | <el-button |
| | | type="info" |
| | | link |
| | | @click="handleDetail(scope.row)" |
| | | > |
| | | 详æ
|
| | | </el-button> |
| | | <el-button |
| | | v-if="scope.row.status === 'pending'" |
| | | type="danger" |
| | | link |
| | | @click="handleDelete(scope.row)" |
| | | > |
| | | å é¤ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | |
| | | <!-- ç³è¯·å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | v-model="showApplyDialog" |
| | | title="åå
¬ç©èµç³è¯·" |
| | | width="600px" |
| | | append-to-body |
| | | > |
| | | <el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="100px"> |
| | | <el-form-item label="ç©èµç±»å" prop="supplyType"> |
| | | <el-select v-model="applyForm.supplyType" placeholder="è¯·éæ©ç©èµç±»å" style="width: 100%"> |
| | | <el-option label="åå
¬ç¨å" value="office" /> |
| | | <el-option label="çµå设å¤" value="electronic" /> |
| | | <el-option label="æ¸
æ´ç¨å" value="cleaning" /> |
| | | <el-option label="å
¶ä»" value="other" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å
·ä½ç©å" prop="itemName"> |
| | | <el-input v-model="applyForm.itemName" placeholder="请è¾å
¥å
·ä½ç©ååç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·æ°é" prop="quantity"> |
| | | <el-input-number v-model="applyForm.quantity" :min="1" :max="999" style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·åå " prop="reason"> |
| | | <el-input |
| | | v-model="applyForm.reason" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥ç³è¯·åå " |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç´§æ¥ç¨åº¦" prop="urgency"> |
| | | <el-radio-group v-model="applyForm.urgency"> |
| | | <el-radio label="normal">æ®é</el-radio> |
| | | <el-radio label="urgent">ç´§æ¥</el-radio> |
| | | <el-radio label="very_urgent">é常紧æ¥</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="showApplyDialog = false">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitApply">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 审æ¹å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | v-model="showApproveDialog" |
| | | title="审æ¹ç³è¯·" |
| | | width="500px" |
| | | append-to-body |
| | | > |
| | | <el-form ref="approveFormRef" :model="approveForm" :rules="approveRules" label-width="100px"> |
| | | <el-form-item label="审æ¹ç»æ" prop="approveResult"> |
| | | <el-radio-group v-model="approveForm.approveResult"> |
| | | <el-radio label="approved">éè¿</el-radio> |
| | | <el-radio label="rejected">æç»</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="å®¡æ¹æè§" prop="approveComment"> |
| | | <el-input |
| | | v-model="approveForm.approveComment" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥å®¡æ¹æè§" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="showApproveDialog = false">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitApprove">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 详æ
å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | v-model="showDetailDialog" |
| | | title="ç³è¯·è¯¦æ
" |
| | | width="700px" |
| | | append-to-body |
| | | > |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="ç³è¯·ç¼å·">{{ currentDetail.applyNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·äºº">{{ currentDetail.applicant }}</el-descriptions-item> |
| | | <el-descriptions-item label="é¨é¨">{{ currentDetail.department }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç©èµç±»å">{{ currentDetail.supplyType }}</el-descriptions-item> |
| | | <el-descriptions-item label="å
·ä½ç©å">{{ currentDetail.itemName }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·æ°é">{{ currentDetail.quantity }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·åå " :span="2">{{ currentDetail.reason }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·ç¶æ"> |
| | | <el-tag :type="getStatusType(currentDetail.status)"> |
| | | {{ getStatusText(currentDetail.status) }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·æ¶é´">{{ currentDetail.applyTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="审æ¹äºº">{{ currentDetail.approver || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®¡æ¹æ¶é´">{{ currentDetail.approveTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®¡æ¹æè§" :span="2">{{ currentDetail.approveComment || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åæ¾æ¶é´">{{ currentDetail.issueTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åæ¾äºº">{{ currentDetail.issuer || '-' }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Plus, Search, Refresh, Download, Check } from '@element-plus/icons-vue' |
| | | |
| | | // ååºå¼æ°æ® |
| | | const loading = ref(false) |
| | | const showSearch = ref(true) |
| | | const showApplyDialog = ref(false) |
| | | const showApproveDialog = ref(false) |
| | | const showDetailDialog = ref(false) |
| | | const multipleSelection = ref([]) |
| | | const total = ref(0) |
| | | const suppliesList = ref([]) |
| | | const currentDetail = ref({}) |
| | | |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = reactive({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | applyNo: '', |
| | | applicant: '', |
| | | status: '' |
| | | }) |
| | | |
| | | // ç³è¯·è¡¨å |
| | | const applyForm = reactive({ |
| | | supplyType: '', |
| | | itemName: '', |
| | | quantity: 1, |
| | | reason: '', |
| | | urgency: 'normal' |
| | | }) |
| | | |
| | | // 审æ¹è¡¨å |
| | | const approveForm = reactive({ |
| | | approveResult: 'approved', |
| | | approveComment: '' |
| | | }) |
| | | |
| | | // è¡¨åæ ¡éªè§å |
| | | const applyRules = { |
| | | supplyType: [{ required: true, message: 'è¯·éæ©ç©èµç±»å', trigger: 'change' }], |
| | | itemName: [{ required: true, message: '请è¾å
¥å
·ä½ç©ååç§°', trigger: 'blur' }], |
| | | quantity: [{ required: true, message: '请è¾å
¥ç³è¯·æ°é', trigger: 'blur' }], |
| | | reason: [{ required: true, message: '请è¾å
¥ç³è¯·åå ', trigger: 'blur' }] |
| | | } |
| | | |
| | | const approveRules = { |
| | | approveResult: [{ required: true, message: 'è¯·éæ©å®¡æ¹ç»æ', trigger: 'change' }], |
| | | approveComment: [{ required: true, message: '请è¾å
¥å®¡æ¹æè§', trigger: 'blur' }] |
| | | } |
| | | |
| | | // åæ°æ® |
| | | const mockData = [ |
| | | { |
| | | id: 1, |
| | | applyNo: 'WS20241201001', |
| | | applicant: 'éå¿å¼º', |
| | | department: 'ææ¯é¨', |
| | | supplyType: 'åå
¬ç¨å', |
| | | itemName: 'A4æå°çº¸', |
| | | quantity: 10, |
| | | reason: 'æ¥å¸¸åå
¬æå°éè¦', |
| | | status: 'pending', |
| | | applyTime: '2024-12-01 09:30:00', |
| | | approver: '', |
| | | approveTime: '', |
| | | approveComment: '', |
| | | issueTime: '', |
| | | issuer: '' |
| | | }, |
| | | { |
| | | id: 2, |
| | | applyNo: 'WS20241201002', |
| | | applicant: 'åé
å©·', |
| | | department: '人äºé¨', |
| | | supplyType: 'çµå设å¤', |
| | | itemName: 'æ çº¿é¼ æ ', |
| | | quantity: 2, |
| | | reason: 'æ°åå·¥å
¥èé
å¤', |
| | | status: 'approved', |
| | | applyTime: '2024-12-01 10:15:00', |
| | | approver: 'ç建å½', |
| | | approveTime: '2024-12-01 14:20:00', |
| | | approveComment: 'åæç³è¯·ï¼è¯·åæ¶åæ¾', |
| | | issueTime: '', |
| | | issuer: '' |
| | | }, |
| | | { |
| | | id: 3, |
| | | applyNo: 'WS20241201003', |
| | | applicant: 'ç建å½', |
| | | department: 'è´¢å¡é¨', |
| | | supplyType: 'æ¸
æ´ç¨å', |
| | | itemName: 'æ´ææ¶²', |
| | | quantity: 5, |
| | | reason: 'åå
¬å®¤æ¸
æ´ç¨åè¡¥å
', |
| | | status: 'issued', |
| | | applyTime: '2024-12-01 11:00:00', |
| | | approver: 'åé
å©·', |
| | | approveTime: '2024-12-01 15:30:00', |
| | | approveComment: 'åæç³è¯·', |
| | | issueTime: '2024-12-01 16:00:00', |
| | | issuer: 'é±ä¼æ' |
| | | }, |
| | | { |
| | | id: 4, |
| | | applyNo: 'WS20241201004', |
| | | applicant: '赵丽å', |
| | | department: 'å¸åºé¨', |
| | | supplyType: 'å
¶ä»', |
| | | itemName: 'æä»¶å¤¹', |
| | | quantity: 20, |
| | | reason: '项ç®èµææ´çéè¦', |
| | | status: 'rejected', |
| | | applyTime: '2024-12-01 13:45:00', |
| | | approver: 'éå¿å¼º', |
| | | approveTime: '2024-12-01 17:00:00', |
| | | approveComment: 'æ°éè¿å¤ï¼å»ºè®®åå°å°10个', |
| | | issueTime: '', |
| | | issuer: '' |
| | | }, |
| | | { |
| | | id: 5, |
| | | applyNo: 'WS20241202001', |
| | | applicant: 'é±ä¼æ', |
| | | department: 'è¿è¥é¨', |
| | | supplyType: 'åå
¬ç¨å', |
| | | itemName: 'ç¾åç¬', |
| | | quantity: 50, |
| | | reason: 'é¨é¨æ¥å¸¸åå
¬ç¨åè¡¥å
', |
| | | status: 'pending', |
| | | applyTime: '2024-12-02 08:30:00', |
| | | approver: '', |
| | | approveTime: '', |
| | | approveComment: '', |
| | | issueTime: '', |
| | | issuer: '' |
| | | }, |
| | | { |
| | | id: 6, |
| | | applyNo: 'WS20241202002', |
| | | applicant: 'åæå', |
| | | department: 'ææ¯é¨', |
| | | supplyType: 'çµå设å¤', |
| | | itemName: 'é®ç', |
| | | quantity: 3, |
| | | reason: 'æ°å工设å¤é
å¤', |
| | | status: 'approved', |
| | | applyTime: '2024-12-02 14:20:00', |
| | | approver: 'éå¿å¼º', |
| | | approveTime: '2024-12-02 16:00:00', |
| | | approveComment: 'åæç³è¯·', |
| | | issueTime: '', |
| | | issuer: '' |
| | | }, |
| | | { |
| | | id: 7, |
| | | applyNo: 'WS20241203001', |
| | | applicant: 'å¨ç¾ç²', |
| | | department: '人äºé¨', |
| | | supplyType: 'æ¸
æ´ç¨å', |
| | | itemName: '纸巾', |
| | | quantity: 30, |
| | | reason: 'åå
¬åºåæ¸
æ´ç¨åè¡¥å
', |
| | | status: 'issued', |
| | | applyTime: '2024-12-03 09:15:00', |
| | | approver: '赵丽å', |
| | | approveTime: '2024-12-03 10:30:00', |
| | | approveComment: 'åæç³è¯·', |
| | | issueTime: '2024-12-03 11:00:00', |
| | | issuer: 'åæå' |
| | | }, |
| | | { |
| | | id: 8, |
| | | applyNo: 'WS20241203002', |
| | | applicant: 'å´å¿å¼º', |
| | | department: 'è´¢å¡é¨', |
| | | supplyType: 'å
¶ä»', |
| | | itemName: '计ç®å¨', |
| | | quantity: 2, |
| | | reason: 'è´¢å¡æ ¸ç®å·¥ä½éè¦', |
| | | status: 'rejected', |
| | | applyTime: '2024-12-03 15:45:00', |
| | | approver: 'ç建å½', |
| | | approveTime: '2024-12-03 17:20:00', |
| | | approveComment: 'å·²æè®¡ç®å¨ï¼æä¸éè¦', |
| | | issueTime: '', |
| | | issuer: '' |
| | | } |
| | | ] |
| | | |
| | | // è·ååè¡¨æ°æ® |
| | | const getList = () => { |
| | | loading.value = true |
| | | // 模æå¼æ¥è¯·æ± |
| | | setTimeout(() => { |
| | | let filteredData = [...mockData] |
| | | |
| | | // æ ¹æ®æ¥è¯¢æ¡ä»¶è¿æ»¤ |
| | | if (queryParams.applyNo) { |
| | | filteredData = filteredData.filter(item => |
| | | item.applyNo.toLowerCase().includes(queryParams.applyNo.toLowerCase()) |
| | | ) |
| | | } |
| | | if (queryParams.applicant) { |
| | | filteredData = filteredData.filter(item => |
| | | item.applicant.toLowerCase().includes(queryParams.applicant.toLowerCase()) |
| | | ) |
| | | } |
| | | if (queryParams.status) { |
| | | filteredData = filteredData.filter(item => |
| | | item.status === queryParams.status |
| | | ) |
| | | } |
| | | |
| | | // æç³è¯·æ¶é´ååºæå |
| | | filteredData.sort((a, b) => new Date(b.applyTime) - new Date(a.applyTime)) |
| | | |
| | | total.value = filteredData.length |
| | | suppliesList.value = filteredData.slice( |
| | | (queryParams.pageNum - 1) * queryParams.pageSize, |
| | | queryParams.pageNum * queryParams.pageSize |
| | | ) |
| | | loading.value = false |
| | | }, 500) |
| | | } |
| | | |
| | | // æ¥è¯¢ |
| | | const handleQuery = () => { |
| | | queryParams.pageNum = 1 |
| | | getList() |
| | | } |
| | | |
| | | // éç½®æ¥è¯¢ |
| | | const resetQuery = () => { |
| | | queryParams.applyNo = '' |
| | | queryParams.applicant = '' |
| | | queryParams.status = '' |
| | | handleQuery() |
| | | } |
| | | |
| | | // å¤é |
| | | const handleSelectionChange = (selection) => { |
| | | multipleSelection.value = selection |
| | | } |
| | | |
| | | // è·åç¶æç±»å |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | pending: 'warning', |
| | | approved: 'success', |
| | | rejected: 'danger', |
| | | issued: 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | // è·åç¶æææ¬ |
| | | const getStatusText = (status) => { |
| | | const statusMap = { |
| | | pending: 'å¾
审æ¹', |
| | | approved: 'å·²éè¿', |
| | | rejected: 'å·²æç»', |
| | | issued: '已忾' |
| | | } |
| | | return statusMap[status] || status |
| | | } |
| | | |
| | | // æäº¤ç³è¯· |
| | | const submitApply = () => { |
| | | const newApply = { |
| | | id: mockData.length + 1, |
| | | applyNo: `WS${new Date().getTime()}`, |
| | | applicant: 'å½åç¨æ·', |
| | | department: 'ææ¯é¨', |
| | | supplyType: applyForm.supplyType, |
| | | itemName: applyForm.itemName, |
| | | quantity: applyForm.quantity, |
| | | reason: applyForm.reason, |
| | | status: 'pending', |
| | | applyTime: new Date().toLocaleString(), |
| | | approver: '', |
| | | approveTime: '', |
| | | approveComment: '', |
| | | issueTime: '', |
| | | issuer: '' |
| | | } |
| | | |
| | | mockData.unshift(newApply) |
| | | showApplyDialog.value = false |
| | | ElMessage.success('ç³è¯·æäº¤æå') |
| | | getList() |
| | | |
| | | // é置表å |
| | | Object.assign(applyForm, { |
| | | supplyType: '', |
| | | itemName: '', |
| | | quantity: 1, |
| | | reason: '', |
| | | urgency: 'normal' |
| | | }) |
| | | } |
| | | |
| | | // å®¡æ¹ |
| | | const handleApprove = (row) => { |
| | | currentDetail.value = row |
| | | showApproveDialog.value = true |
| | | } |
| | | |
| | | // æäº¤å®¡æ¹ |
| | | const submitApprove = () => { |
| | | const index = mockData.findIndex(item => item.id === currentDetail.value.id) |
| | | if (index !== -1) { |
| | | mockData[index].status = approveForm.approveResult |
| | | mockData[index].approver = 'å½å审æ¹äºº' |
| | | mockData[index].approveTime = new Date().toLocaleString() |
| | | mockData[index].approveComment = approveForm.approveComment |
| | | } |
| | | |
| | | showApproveDialog.value = false |
| | | ElMessage.success('审æ¹å®æ') |
| | | getList() |
| | | |
| | | // é置表å |
| | | Object.assign(approveForm, { |
| | | approveResult: 'approved', |
| | | approveComment: '' |
| | | }) |
| | | } |
| | | |
| | | // åæ¾ |
| | | const handleIssue = (row) => { |
| | | const index = mockData.findIndex(item => item.id === row.id) |
| | | if (index !== -1) { |
| | | mockData[index].status = 'issued' |
| | | mockData[index].issueTime = new Date().toLocaleString() |
| | | mockData[index].issuer = 'å½ååæ¾äºº' |
| | | } |
| | | |
| | | ElMessage.success('忾宿') |
| | | getList() |
| | | } |
| | | |
| | | // æ¥ç详æ
|
| | | const handleDetail = (row) => { |
| | | currentDetail.value = row |
| | | showDetailDialog.value = true |
| | | } |
| | | |
| | | // å é¤ |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm('确认å é¤è¯¥ç³è¯·åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id) |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1) |
| | | } |
| | | ElMessage.success('å 餿å') |
| | | getList() |
| | | }) |
| | | } |
| | | |
| | | // æ¹éå®¡æ¹ |
| | | const handleBatchApprove = () => { |
| | | if (multipleSelection.value.length === 0) { |
| | | ElMessage.warning('è¯·éæ©è¦å®¡æ¹çè®°å½') |
| | | return |
| | | } |
| | | |
| | | ElMessageBox.confirm(`确认æ¹é审æ¹éä¸ç ${multipleSelection.value.length} æ¡è®°å½åï¼`, 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | multipleSelection.value.forEach(row => { |
| | | const index = mockData.findIndex(item => item.id === row.id) |
| | | if (index !== -1) { |
| | | mockData[index].status = 'approved' |
| | | mockData[index].approver = 'å½å审æ¹äºº' |
| | | mockData[index].approveTime = new Date().toLocaleString() |
| | | mockData[index].approveComment = 'æ¹é审æ¹éè¿' |
| | | } |
| | | }) |
| | | ElMessage.success('æ¹é审æ¹å®æ') |
| | | getList() |
| | | }) |
| | | } |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | ElMessage.success('导åºåè½å¼åä¸...') |
| | | } |
| | | |
| | | // 页é¢å è½½æ¶è·åæ°æ® |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .mb8 { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | :deep(.el-descriptions__label) { |
| | | width: 120px; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 顶鍿使 --> |
| | | <div class="header-actions"> |
| | | <div class="left-actions"> |
| | | <el-select v-model="currentLevel" placeholder="éæ©è®¡å级å«" style="width: 150px" @change="handleLevelChange"> |
| | | <el-option label="个人计å" value="personal" /> |
| | | <el-option label="å°ç»è®¡å" value="group" /> |
| | | <el-option label="é¨é¨è®¡å" value="department" /> |
| | | <el-option label="å
¬å¸è®¡å" value="company" /> |
| | | </el-select> |
| | | <el-select v-model="currentPeriod" placeholder="éæ©æ¶é´å¨æ" style="width: 120px; margin-left: 10px" @change="handlePeriodChange"> |
| | | <el-option label="å¨è®¡å" value="week" /> |
| | | <el-option label="æè®¡å" value="month" /> |
| | | <el-option label="年计å" value="year" /> |
| | | </el-select> |
| | | <el-date-picker |
| | | v-model="currentDate" |
| | | :type="datePickerType" |
| | | placeholder="éæ©æ¥æ" |
| | | style="width: 180px; margin-left: 10px" |
| | | @change="handleDateChange" |
| | | /> |
| | | </div> |
| | | <div class="right-actions"> |
| | | <el-button type="primary" @click="handleAddPlan">æ°å¢è®¡å</el-button> |
| | | <el-button @click="handleExport">导åºè®¡å</el-button> |
| | | <el-button @click="handleShare">å
±äº«è®¡å</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- è®¡åæ¦è§å¡ç --> |
| | | <div class="overview-cards"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <el-card class="overview-card"> |
| | | <div class="card-content"> |
| | | <div class="card-icon personal"> |
| | | <el-icon><User /></el-icon> |
| | | </div> |
| | | <div class="card-info"> |
| | | <div class="card-title">个人计å</div> |
| | | <div class="card-number">{{ overviewData.personal.total }}</div> |
| | | <div class="card-progress"> |
| | | <el-progress :percentage="overviewData.personal.completion" :stroke-width="6" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="overview-card"> |
| | | <div class="card-content"> |
| | | <div class="card-icon group"> |
| | | <el-icon><UserFilled /></el-icon> |
| | | </div> |
| | | <div class="card-info"> |
| | | <div class="card-title">å°ç»è®¡å</div> |
| | | <div class="card-number">{{ overviewData.group.total }}</div> |
| | | <div class="card-progress"> |
| | | <el-progress :percentage="overviewData.group.completion" :stroke-width="6" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="overview-card"> |
| | | <div class="card-content"> |
| | | <div class="card-icon department"> |
| | | <el-icon><OfficeBuilding /></el-icon> |
| | | </div> |
| | | <div class="card-info"> |
| | | <div class="card-title">é¨é¨è®¡å</div> |
| | | <div class="card-number">{{ overviewData.department.total }}</div> |
| | | <div class="card-progress"> |
| | | <el-progress :percentage="overviewData.department.completion" :stroke-width="6" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="overview-card"> |
| | | <div class="card-content"> |
| | | <div class="card-icon company"> |
| | | <el-icon><House /></el-icon> |
| | | </div> |
| | | <div class="card-info"> |
| | | <div class="card-title">å
¬å¸è®¡å</div> |
| | | <div class="card-number">{{ overviewData.company.total }}</div> |
| | | <div class="card-progress"> |
| | | <el-progress :percentage="overviewData.company.completion" :stroke-width="6" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <!-- 计åå表 --> |
| | | <div class="plan-content"> |
| | | <el-card> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>{{ getCurrentLevelText() }} - {{ getCurrentPeriodText() }}</span> |
| | | <div> |
| | | <el-button size="small" @click="handleRefresh">å·æ°</el-button> |
| | | <el-button size="small" @click="handleFilter">çé</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <div class="plan-list"> |
| | | <div v-for="plan in planList" :key="plan.id" class="plan-item"> |
| | | <div class="plan-header"> |
| | | <div class="plan-title"> |
| | | <el-tag :type="getPriorityType(plan.priority)" size="small">{{ getPriorityText(plan.priority) }}</el-tag> |
| | | <span class="title-text">{{ plan.title }}</span> |
| | | </div> |
| | | <div class="plan-actions"> |
| | | <el-button size="small" @click="handleEditPlan(plan)">ç¼è¾</el-button> |
| | | <el-button size="small" @click="handleViewDetail(plan)">详æ
</el-button> |
| | | <el-dropdown @command="handleMoreAction"> |
| | | <el-button size="small"> |
| | | æ´å¤<el-icon class="el-icon--right"><ArrowDown /></el-icon> |
| | | </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="share">å
񄧮</el-dropdown-item> |
| | | <el-dropdown-item command="copy">å¤å¶</el-dropdown-item> |
| | | <el-dropdown-item command="delete" divided>å é¤</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="plan-content"> |
| | | <div class="plan-description">{{ plan.description }}</div> |
| | | <div class="plan-meta"> |
| | | <div class="meta-item"> |
| | | <el-icon><Calendar /></el-icon> |
| | | <span>{{ plan.startDate }} - {{ plan.endDate }}</span> |
| | | </div> |
| | | <div class="meta-item"> |
| | | <el-icon><User /></el-icon> |
| | | <span>{{ plan.assignee }}</span> |
| | | </div> |
| | | <div class="meta-item"> |
| | | <el-icon><Clock /></el-icon> |
| | | <span>è¿åº¦: {{ plan.progress }}%</span> |
| | | </div> |
| | | <div class="meta-item"> |
| | | <el-icon><Flag /></el-icon> |
| | | <span>{{ getStatusText(plan.status) }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="plan-progress"> |
| | | <el-progress |
| | | :percentage="plan.progress" |
| | | :color="getProgressColor(plan.progress)" |
| | | :stroke-width="8" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="plan-tags"> |
| | | <el-tag v-for="tag in plan.tags" :key="tag" size="small" style="margin-right: 5px"> |
| | | {{ tag }} |
| | | </el-tag> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | |
| | | <!-- æ°å¢/ç¼è¾è®¡åå¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | v-model="planDialogVisible" |
| | | :title="dialogTitle" |
| | | width="600px" |
| | | @close="handleDialogClose" |
| | | > |
| | | <el-form :model="planForm" :rules="planRules" ref="planFormRef" label-width="100px"> |
| | | <el-form-item label="è®¡åæ é¢" prop="title"> |
| | | <el-input v-model="planForm.title" placeholder="请è¾å
¥è®¡åæ é¢" /> |
| | | </el-form-item> |
| | | <el-form-item label="计åæè¿°" prop="description"> |
| | | <el-input |
| | | v-model="planForm.description" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥è®¡åæè¿°" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="计å级å«" prop="level"> |
| | | <el-select v-model="planForm.level" placeholder="éæ©è®¡å级å«" style="width: 100%"> |
| | | <el-option label="个人计å" value="personal" /> |
| | | <el-option label="å°ç»è®¡å" value="group" /> |
| | | <el-option label="é¨é¨è®¡å" value="department" /> |
| | | <el-option label="å
¬å¸è®¡å" value="company" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¶é´å¨æ" prop="period"> |
| | | <el-select v-model="planForm.period" placeholder="éæ©æ¶é´å¨æ" style="width: 100%"> |
| | | <el-option label="å¨è®¡å" value="week" /> |
| | | <el-option label="æè®¡å" value="month" /> |
| | | <el-option label="年计å" value="year" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å¼å§æ¶é´" prop="startDate"> |
| | | <el-date-picker |
| | | v-model="planForm.startDate" |
| | | type="date" |
| | | placeholder="éæ©å¼å§æ¶é´" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç»ææ¶é´" prop="endDate"> |
| | | <el-date-picker |
| | | v-model="planForm.endDate" |
| | | type="date" |
| | | placeholder="éæ©ç»ææ¶é´" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="è´è´£äºº" prop="assignee"> |
| | | <el-input v-model="planForm.assignee" placeholder="请è¾å
¥è´è´£äºº" /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼å
级" prop="priority"> |
| | | <el-select v-model="planForm.priority" placeholder="éæ©ä¼å
级" style="width: 100%"> |
| | | <el-option label="é«" value="high" /> |
| | | <el-option label="ä¸" value="medium" /> |
| | | <el-option label="ä½" value="low" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ ç¾"> |
| | | <el-input v-model="planForm.tags" placeholder="请è¾å
¥æ ç¾ï¼ç¨éå·åé" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="planDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleSavePlan">ä¿å</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { |
| | | User, |
| | | UserFilled, |
| | | OfficeBuilding, |
| | | House, |
| | | Calendar, |
| | | Clock, |
| | | Flag, |
| | | ArrowDown |
| | | } from '@element-plus/icons-vue' |
| | | |
| | | // ååºå¼æ°æ® |
| | | const currentLevel = ref('personal') |
| | | const currentPeriod = ref('week') |
| | | const currentDate = ref(new Date()) |
| | | const planDialogVisible = ref(false) |
| | | const dialogTitle = ref('æ°å¢è®¡å') |
| | | const planFormRef = ref() |
| | | |
| | | // è¡¨åæ°æ® |
| | | const planForm = reactive({ |
| | | title: '', |
| | | description: '', |
| | | level: 'personal', |
| | | period: 'week', |
| | | startDate: '', |
| | | endDate: '', |
| | | assignee: '', |
| | | priority: 'medium', |
| | | tags: '' |
| | | }) |
| | | |
| | | // 表åéªè¯è§å |
| | | const planRules = { |
| | | title: [{ required: true, message: '请è¾å
¥è®¡åæ é¢', trigger: 'blur' }], |
| | | description: [{ required: true, message: '请è¾å
¥è®¡åæè¿°', trigger: 'blur' }], |
| | | level: [{ required: true, message: 'è¯·éæ©è®¡å级å«', trigger: 'change' }], |
| | | period: [{ required: true, message: 'è¯·éæ©æ¶é´å¨æ', trigger: 'change' }], |
| | | startDate: [{ required: true, message: 'è¯·éæ©å¼å§æ¶é´', trigger: 'change' }], |
| | | endDate: [{ required: true, message: 'è¯·éæ©ç»ææ¶é´', trigger: 'change' }], |
| | | assignee: [{ required: true, message: '请è¾å
¥è´è´£äºº', trigger: 'blur' }], |
| | | priority: [{ required: true, message: 'è¯·éæ©ä¼å
级', trigger: 'change' }] |
| | | } |
| | | |
| | | // æ¦è§æ°æ® |
| | | const overviewData = reactive({ |
| | | personal: { total: 12, completion: 75 }, |
| | | group: { total: 8, completion: 60 }, |
| | | department: { total: 15, completion: 45 }, |
| | | company: { total: 6, completion: 30 } |
| | | }) |
| | | |
| | | // 计ååè¡¨æ°æ® |
| | | const planList = ref([ |
| | | { |
| | | id: 1, |
| | | title: '产åéæ±åæ', |
| | | description: '对æ°äº§åè¿è¡è¯¦ç»çéæ±åæåå¸åºè°ç ï¼å¶å®äº§åè§åæ¹æ¡', |
| | | level: 'personal', |
| | | period: 'week', |
| | | startDate: '2024-01-15', |
| | | endDate: '2024-01-21', |
| | | assignee: 'éå¿å¼º', |
| | | priority: 'high', |
| | | status: 'in_progress', |
| | | progress: 80, |
| | | tags: ['产å', 'åæ', 'è°ç '] |
| | | }, |
| | | { |
| | | id: 2, |
| | | title: 'ææ¯æ¶æè®¾è®¡', |
| | | description: 'è®¾è®¡ç³»ç»ææ¯æ¶æï¼å
æ¬æ°æ®åºè®¾è®¡ãæ¥å£è®¾è®¡ç', |
| | | level: 'group', |
| | | period: 'month', |
| | | startDate: '2024-01-01', |
| | | endDate: '2024-01-31', |
| | | assignee: 'åé
å©·', |
| | | priority: 'high', |
| | | status: 'completed', |
| | | progress: 100, |
| | | tags: ['ææ¯', 'æ¶æ', '设计'] |
| | | }, |
| | | { |
| | | id: 3, |
| | | title: 'å¸åºæ¨å¹¿è®¡å', |
| | | description: 'å¶å®å¹´åº¦å¸åºæ¨å¹¿çç¥åè¥é计å', |
| | | level: 'department', |
| | | period: 'year', |
| | | startDate: '2024-01-01', |
| | | endDate: '2024-12-31', |
| | | assignee: 'ç建å½', |
| | | priority: 'medium', |
| | | status: 'not_started', |
| | | progress: 0, |
| | | tags: ['å¸åº', 'æ¨å¹¿', 'è¥é'] |
| | | }, |
| | | { |
| | | id: 4, |
| | | title: 'å¢é建设活å¨', |
| | | description: 'ç»ç»å¢é建设活å¨ï¼æåå¢éåèååå使ç', |
| | | level: 'company', |
| | | period: 'month', |
| | | startDate: '2024-01-15', |
| | | endDate: '2024-02-15', |
| | | assignee: '赵丽å', |
| | | priority: 'low', |
| | | status: 'in_progress', |
| | | progress: 30, |
| | | tags: ['å¢é', '建设', 'æ´»å¨'] |
| | | } |
| | | ]) |
| | | |
| | | // 计ç®å±æ§ |
| | | const datePickerType = computed(() => { |
| | | switch (currentPeriod.value) { |
| | | case 'week': |
| | | return 'week' |
| | | case 'month': |
| | | return 'month' |
| | | case 'year': |
| | | return 'year' |
| | | default: |
| | | return 'date' |
| | | } |
| | | }) |
| | | |
| | | // æ¹æ³ |
| | | const handleLevelChange = (value) => { |
| | | console.log('计å级å«åæ´:', value) |
| | | // è¿éå¯ä»¥æ ¹æ®çº§å«çéæ°æ® |
| | | } |
| | | |
| | | const handlePeriodChange = (value) => { |
| | | console.log('æ¶é´å¨æåæ´:', value) |
| | | // è¿éå¯ä»¥æ ¹æ®å¨æçéæ°æ® |
| | | } |
| | | |
| | | const handleDateChange = (value) => { |
| | | console.log('æ¥æåæ´:', value) |
| | | // è¿éå¯ä»¥æ ¹æ®æ¥æçéæ°æ® |
| | | } |
| | | |
| | | const handleAddPlan = () => { |
| | | dialogTitle.value = 'æ°å¢è®¡å' |
| | | planDialogVisible.value = true |
| | | // é置表å |
| | | Object.keys(planForm).forEach(key => { |
| | | planForm[key] = '' |
| | | }) |
| | | planForm.level = 'personal' |
| | | planForm.period = 'week' |
| | | planForm.priority = 'medium' |
| | | } |
| | | |
| | | const handleEditPlan = (plan) => { |
| | | dialogTitle.value = 'ç¼è¾è®¡å' |
| | | planDialogVisible.value = true |
| | | // å¡«å
è¡¨åæ°æ® |
| | | Object.keys(planForm).forEach(key => { |
| | | if (key === 'tags') { |
| | | planForm[key] = plan[key].join(', ') |
| | | } else { |
| | | planForm[key] = plan[key] |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const handleViewDetail = (plan) => { |
| | | ElMessage.info(`æ¥ç计å详æ
: ${plan.title}`) |
| | | } |
| | | |
| | | const handleMoreAction = (command) => { |
| | | switch (command) { |
| | | case 'share': |
| | | ElMessage.success('计åå·²å
񄧮') |
| | | break |
| | | case 'copy': |
| | | ElMessage.success('计åå·²å¤å¶') |
| | | break |
| | | case 'delete': |
| | | ElMessageBox.confirm('ç¡®å®è¦å é¤è¿ä¸ªè®¡ååï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | ElMessage.success('计åå·²å é¤') |
| | | }) |
| | | break |
| | | } |
| | | } |
| | | |
| | | const handleSavePlan = async () => { |
| | | try { |
| | | await planFormRef.value.validate() |
| | | ElMessage.success('计åä¿åæå') |
| | | planDialogVisible.value = false |
| | | } catch (error) { |
| | | console.log('表åéªè¯å¤±è´¥:', error) |
| | | } |
| | | } |
| | | |
| | | const handleDialogClose = () => { |
| | | planFormRef.value?.resetFields() |
| | | } |
| | | |
| | | const handleRefresh = () => { |
| | | ElMessage.success('æ°æ®å·²å·æ°') |
| | | } |
| | | |
| | | const handleFilter = () => { |
| | | ElMessage.info('æå¼çé颿¿') |
| | | } |
| | | |
| | | const handleExport = () => { |
| | | ElMessage.success('计å已导åº') |
| | | } |
| | | |
| | | const handleShare = () => { |
| | | ElMessage.success('计åå·²å
񄧮') |
| | | } |
| | | |
| | | const getCurrentLevelText = () => { |
| | | const levelMap = { |
| | | personal: '个人计å', |
| | | group: 'å°ç»è®¡å', |
| | | department: 'é¨é¨è®¡å', |
| | | company: 'å
¬å¸è®¡å' |
| | | } |
| | | return levelMap[currentLevel.value] || '个人计å' |
| | | } |
| | | |
| | | const getCurrentPeriodText = () => { |
| | | const periodMap = { |
| | | week: 'å¨è®¡å', |
| | | month: 'æè®¡å', |
| | | year: '年计å' |
| | | } |
| | | return periodMap[currentPeriod.value] || 'å¨è®¡å' |
| | | } |
| | | |
| | | const getPriorityType = (priority) => { |
| | | const typeMap = { |
| | | high: 'danger', |
| | | medium: 'warning', |
| | | low: 'info' |
| | | } |
| | | return typeMap[priority] || 'info' |
| | | } |
| | | |
| | | const getPriorityText = (priority) => { |
| | | const textMap = { |
| | | high: 'é«', |
| | | medium: 'ä¸', |
| | | low: 'ä½' |
| | | } |
| | | return textMap[priority] || 'ä¸' |
| | | } |
| | | |
| | | const getStatusText = (status) => { |
| | | const statusMap = { |
| | | not_started: 'æªå¼å§', |
| | | in_progress: 'è¿è¡ä¸', |
| | | completed: '已宿', |
| | | paused: 'å·²æå' |
| | | } |
| | | return statusMap[status] || 'æªç¥' |
| | | } |
| | | |
| | | const getProgressColor = (progress) => { |
| | | if (progress >= 80) return '#67C23A' |
| | | if (progress >= 50) return '#E6A23C' |
| | | return '#F56C6C' |
| | | } |
| | | |
| | | onMounted(() => { |
| | | console.log('å¤çº§è®¡å模æ¿é¡µé¢å·²å è½½') |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .header-actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | background: white; |
| | | padding: 20px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .left-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .right-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .overview-cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .overview-card { |
| | | height: 120px; |
| | | } |
| | | |
| | | .card-content { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100%; |
| | | } |
| | | |
| | | .card-icon { |
| | | width: 60px; |
| | | height: 60px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 15px; |
| | | font-size: 24px; |
| | | color: white; |
| | | } |
| | | |
| | | .card-icon.personal { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | } |
| | | |
| | | .card-icon.group { |
| | | background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
| | | } |
| | | |
| | | .card-icon.department { |
| | | background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
| | | } |
| | | |
| | | .card-icon.company { |
| | | background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); |
| | | } |
| | | |
| | | .card-info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 14px; |
| | | color: #666; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .card-number { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .card-progress { |
| | | width: 100%; |
| | | } |
| | | |
| | | .plan-content { |
| | | background: white; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .header-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .plan-list { |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .plan-item { |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 8px; |
| | | margin-bottom: 15px; |
| | | padding: 20px; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .plan-item:hover { |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .plan-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .plan-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .title-text { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .plan-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .plan-content { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .plan-description { |
| | | color: #666; |
| | | margin-bottom: 15px; |
| | | line-height: 1.6; |
| | | } |
| | | |
| | | .plan-meta { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20px; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .meta-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 5px; |
| | | color: #666; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .plan-progress { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .plan-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 5px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | } |
| | | |
| | | /* ååºå¼è®¾è®¡ */ |
| | | @media (max-width: 768px) { |
| | | .header-actions { |
| | | flex-direction: column; |
| | | gap: 15px; |
| | | } |
| | | |
| | | .left-actions { |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .plan-meta { |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .plan-header { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 10px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | { |
| | | id: 'SEAL001', |
| | | title: 'ååç¨å°ç³è¯·', |
| | | applicant: 'å¼ ä¸', |
| | | applicant: 'éå¿å¼º', |
| | | department: 'éå®é¨', |
| | | sealType: 'ååä¸ç¨ç« ', |
| | | applyTime: '2024-01-15 10:30:00', |
| | |
| | | { |
| | | id: 'SEAL002', |
| | | title: 'è´¢å¡æ¥åç¨å°', |
| | | applicant: 'çäº', |
| | | applicant: 'ç建å½', |
| | | department: 'è´¢å¡é¨', |
| | | sealType: 'è´¢å¡ä¸ç¨ç« ', |
| | | applyTime: '2024-01-14 14:20:00', |
| | |
| | | { |
| | | id: 'SEAL003', |
| | | title: 'å
¬å¸ç« ç¨ç¨å°', |
| | | applicant: 'åä¸', |
| | | applicant: 'åæå', |
| | | department: 'æ³å¡é¨', |
| | | sealType: 'å
¬ç« ', |
| | | applyTime: '2024-01-13 09:15:00', |
| | |
| | | ]) |
| | | |
| | | const readStatusList = ref([ |
| | | { employee: 'å¼ ä¸', department: 'éå®é¨', readTime: '2024-01-11 10:30:00', confirmTime: '2024-01-11 10:35:00', status: 'confirmed' }, |
| | | { employee: 'æå', department: 'ææ¯é¨', readTime: '2024-01-11 14:20:00', confirmTime: '', status: 'unconfirmed' }, |
| | | { employee: 'çäº', department: 'è´¢å¡é¨', readTime: '2024-01-12 09:15:00', confirmTime: '2024-01-12 09:20:00', status: 'confirmed' } |
| | | { employee: 'éå¿å¼º', department: 'éå®é¨', readTime: '2024-01-11 10:30:00', confirmTime: '2024-01-11 10:35:00', status: 'confirmed' }, |
| | | { employee: 'åé
å©·', department: 'ææ¯é¨', readTime: '2024-01-11 14:20:00', confirmTime: '', status: 'unconfirmed' }, |
| | | { employee: 'ç建å½', department: 'è´¢å¡é¨', readTime: '2024-01-12 09:15:00', confirmTime: '2024-01-12 09:20:00', status: 'confirmed' } |
| | | ]) |
| | | |
| | | // æ¹æ³ |
| | |
| | | levelText: '红è²é¢è¦', |
| | | status: 'pending', |
| | | statusText: 'å¾
å¤ç', |
| | | responsible: 'å¼ ç»ç', |
| | | responsible: 'éå¿å¼º', |
| | | description: 'A项ç®é¢ç®æ§è¡ç已达95%ï¼é¢è®¡å°è¶
åºé¢ç®èå´ã', |
| | | impact: 'å½±åé¡¹ç®æ´ä½è´¢å¡ææ ï¼å¯è½å¯¼è´é¡¹ç®äºæ', |
| | | suggestions: 'æåéå¿
è¦æ¯åºï¼ä¼åèµæºé
ç½®ï¼ç³è¯·é¢ç®è°æ´' |
| | |
| | | levelText: '红è²é¢è¦', |
| | | status: 'pending', |
| | | statusText: 'å¾
å¤ç', |
| | | responsible: 'éæ»ç', |
| | | responsible: 'éå¿å¼º', |
| | | description: '产åDå¨å®¢æ·ç°åºåºç°è´¨éé®é¢ã', |
| | | impact: 'å½±åå®¢æ·æ»¡æåº¦ï¼å¯è½é æç»æµæå¤±', |
| | | suggestions: 'ç«å³å¬åé®é¢äº§åï¼åæåå ï¼å¶å®æ¹è¿æªæ½' |
| | |
| | | qualifiedQuantity: 240, |
| | | unqualifiedQuantity: 10, |
| | | inspectionTime: '2024-12-01 16:30:00', |
| | | inspector: 'å¼ ä¸', |
| | | inspector: 'éå¿å¼º', |
| | | remark: 'è´¨æ£å®æ' |
| | | } |
| | | ] |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´è´£ä¸å¡å" prop="salesperson"> |
| | | <el-select v-model="form.salesperson" placeholder="è¯·éæ©ä¸å¡å" style="width: 100%"> |
| | | <el-option label="å¼ ä¸" value="å¼ ä¸"></el-option> |
| | | <el-option label="æå" value="æå"></el-option> |
| | | <el-option label="çäº" value="çäº"></el-option> |
| | | <el-option label="éå¿å¼º" value="éå¿å¼º"></el-option> |
| | | <el-option label="åé
å©·" value="åé
å©·"></el-option> |
| | | <el-option label="ç建å½" value="ç建å½"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="éæ°åé
"> |
| | | <el-select v-model="newSalesperson" placeholder="è¯·éæ©æ°ä¸å¡å" style="width: 100%"> |
| | | <el-option label="å¼ ä¸" value="å¼ ä¸"></el-option> |
| | | <el-option label="æå" value="æå"></el-option> |
| | | <el-option label="çäº" value="çäº"></el-option> |
| | | <el-option label="éå¿å¼º" value="éå¿å¼º"></el-option> |
| | | <el-option label="åé
å©·" value="åé
å©·"></el-option> |
| | | <el-option label="ç建å½" value="ç建å½"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="åé
åå "> |
| | |
| | | { |
| | | id: 1, |
| | | name: '䏿µ·ç§ææéå
¬å¸', |
| | | contactPerson: 'å¼ ç»ç', |
| | | contactPerson: 'éå¿å¼º', |
| | | phone: '021-12345678', |
| | | email: 'zhang@shanghai-tech.com', |
| | | region: 'åä¸åº', |
| | | level: 'VIP客æ·', |
| | | salesperson: 'å¼ ä¸', |
| | | salesperson: 'éå¿å¼º', |
| | | status: 'æ´»è·' |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'æ·±å³çµåæéå
¬å¸', |
| | | contactPerson: 'ææ»', |
| | | contactPerson: 'åé
å©·', |
| | | phone: '0755-87654321', |
| | | email: 'li@shenzhen-elec.com', |
| | | region: 'åååº', |
| | | level: 'éè¦å®¢æ·', |
| | | salesperson: 'æå', |
| | | salesperson: 'åé
å©·', |
| | | status: 'æ´»è·' |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: 'å京贸æå
¬å¸', |
| | | contactPerson: 'çç»ç', |
| | | contactPerson: 'ç建å½', |
| | | phone: '010-11223344', |
| | | email: 'wang@beijing-trade.com', |
| | | region: 'åååº', |
| | | level: 'æ®é客æ·', |
| | | salesperson: 'çäº', |
| | | salesperson: 'ç建å½', |
| | | status: 'æ½å¨' |
| | | } |
| | | ]) |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸å¡å" prop="salesperson"> |
| | | <el-select v-model="form.salesperson" placeholder="è¯·éæ©ä¸å¡å" style="width: 100%"> |
| | | <el-option label="å¼ ä¸" value="å¼ ä¸"></el-option> |
| | | <el-option label="æå" value="æå"></el-option> |
| | | <el-option label="çäº" value="çäº"></el-option> |
| | | <el-option label="éå¿å¼º" value="éå¿å¼º"></el-option> |
| | | <el-option label="åé
å©·" value="åé
å©·"></el-option> |
| | | <el-option label="ç建å½" value="ç建å½"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="转åç»" prop="newSalesperson"> |
| | | <el-select v-model="newSalesperson" placeholder="è¯·éæ©æ°ä¸å¡å" style="width: 100%"> |
| | | <el-option label="å¼ ä¸" value="å¼ ä¸"></el-option> |
| | | <el-option label="æå" value="æå"></el-option> |
| | | <el-option label="çäº" value="çäº"></el-option> |
| | | <el-option label="éå¿å¼º" value="éå¿å¼º"></el-option> |
| | | <el-option label="åé
å©·" value="åé
å©·"></el-option> |
| | | <el-option label="ç建å½" value="ç建å½"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="转ååå " prop="transferReason"> |
| | |
| | | id: 1, |
| | | orderNo: 'ORD202312001', |
| | | customer: '䏿µ·ç§ææéå
¬å¸', |
| | | salesperson: 'å¼ ä¸', |
| | | salesperson: 'éå¿å¼º', |
| | | orderDate: '2023-12-01', |
| | | amount: 50000.00, |
| | | paymentMethod: 'å
¨æ¬¾å°ä»', |
| | |
| | | id: 2, |
| | | orderNo: 'ORD202312002', |
| | | customer: 'æ·±å³çµåæéå
¬å¸', |
| | | salesperson: 'æå', |
| | | salesperson: 'åé
å©·', |
| | | orderDate: '2023-12-02', |
| | | amount: 35000.00, |
| | | paymentMethod: 'åæä»æ¬¾', |
| | |
| | | id: 3, |
| | | orderNo: 'ORD202312003', |
| | | customer: 'å京贸æå
¬å¸', |
| | | salesperson: 'çäº', |
| | | salesperson: 'ç建å½', |
| | | orderDate: '2023-12-03', |
| | | amount: 28000.00, |
| | | paymentMethod: 'æç»', |
| | |
| | | const salespersonList = ref([ |
| | | { |
| | | id: 1, |
| | | name: 'å¼ ä¸', |
| | | name: 'éå¿å¼º', |
| | | phone: '13800138001', |
| | | email: 'zhangsan@company.com', |
| | | email: 'chenzhiqiang@company.com', |
| | | department: 'éå®é¨', |
| | | position: 'éå®ç»ç', |
| | | hireDate: '2023-01-15', |
| | |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'æå', |
| | | name: 'åé
å©·', |
| | | phone: '13800138002', |
| | | email: 'lisi@company.com', |
| | | email: 'liuyating@company.com', |
| | | department: 'å¸åºé¨', |
| | | position: 'å¸åºä¸å', |
| | | hireDate: '2023-03-20', |
| | |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: 'çäº', |
| | | name: 'ç建å½', |
| | | phone: '13800138003', |
| | | email: 'wangwu@company.com', |
| | | email: 'wangjianguo@company.com', |
| | | department: '客æé¨', |
| | | position: '客æä¸»ç®¡', |
| | | hireDate: '2022-11-10', |
| | |
| | | </template> |
| | | <div class="demo-content"> |
| | | <p>çæå
å«è系信æ¯çäºç»´ç </p> |
| | | <p class="demo-text">å§åï¼å¼ ä¸<br>çµè¯ï¼13800138000</p> |
| | | <p class="demo-text">å§åï¼éå¿å¼º<br>çµè¯ï¼13800138000</p> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | |
| | | typeName = 'ç½åäºç»´ç ' |
| | | break |
| | | case 'contact': |
| | | content = 'BEGIN:VCARD\nVERSION:3.0\nFN:å¼ ä¸\nTEL:13800138000\nEND:VCARD' |
| | | content = 'BEGIN:VCARD\nVERSION:3.0\nFN:éå¿å¼º\nTEL:13800138000\nEND:VCARD' |
| | | typeName = 'èç³»æ¹å¼äºç»´ç ' |
| | | break |
| | | case 'product': |