|
@@ -1,343 +1,10 @@
|
|
<template>
|
|
<template>
|
|
- <m-dialog title="名片解析" v-model:visible="show" :showDrawer="id !== null" :footer="false" @close="handleClose">
|
|
|
|
- <div class="fullBox box-1" :class="{ 'box-2': id }">
|
|
|
|
- <v-card class="upload-card d-flex flex-column align-center justify-center overflow-hidden" elevation="5">
|
|
|
|
- <template v-if="file">
|
|
|
|
- <div class="fullBox overflow-auto text-center">
|
|
|
|
- <div class="change d-flex align-center justify-end pr-3 pt-3" v-if="!id">
|
|
|
|
- <UploadBtn
|
|
|
|
- :loading="loading"
|
|
|
|
- :disabled="loading"
|
|
|
|
- color="primary"
|
|
|
|
- class="white--text"
|
|
|
|
- @change="handleImport"
|
|
|
|
- >
|
|
|
|
- <v-icon left dark>mdi-cloud-upload</v-icon>
|
|
|
|
- 更换名片
|
|
|
|
- </UploadBtn>
|
|
|
|
- <v-btn color="primary" rounded class="buttons white--text ml-2" @click="handleAnalysis">
|
|
|
|
- <v-icon left dark>mdi-file-arrow-left-right</v-icon>
|
|
|
|
- 解析
|
|
|
|
- </v-btn>
|
|
|
|
- </div>
|
|
|
|
- <img width="100%" :src="previewUrl" style="max-width: 700px;" />
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template v-else>
|
|
|
|
- <div>
|
|
|
|
- <UploadBtn
|
|
|
|
- :loading="loading"
|
|
|
|
- :disabled="loading"
|
|
|
|
- color="primary"
|
|
|
|
- class="ma-2 white--text"
|
|
|
|
- @change="handleImport"
|
|
|
|
- >
|
|
|
|
- <v-icon left dark>
|
|
|
|
- mdi-cloud-upload
|
|
|
|
- </v-icon>
|
|
|
|
- 点击上传
|
|
|
|
- </UploadBtn>
|
|
|
|
- </div>
|
|
|
|
- <div>
|
|
|
|
- <v-chip>请选择文件解析</v-chip>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- </v-card>
|
|
|
|
- <MCard v-if="id" class="show-card d-flex flex-column" title="名片解析" v-loading="loading">
|
|
|
|
- <template #title>
|
|
|
|
- <v-btn color="primary" class="buttons" rounded @click="handleUpdate">
|
|
|
|
- <v-icon left>mdi-update</v-icon>
|
|
|
|
- 更新
|
|
|
|
- </v-btn>
|
|
|
|
- </template>
|
|
|
|
- <div class="fullBox overflow-auto">
|
|
|
|
- <MForm class="mt-3" :items="formItems" v-model="formQuery">
|
|
|
|
- <template #baseInfo>
|
|
|
|
- <div>
|
|
|
|
- <v-subheader>基础信息</v-subheader>
|
|
|
|
- <!-- <v-menu
|
|
|
|
- attach
|
|
|
|
- :nudge-width="200"
|
|
|
|
- offset-x
|
|
|
|
- >
|
|
|
|
- <template v-slot:activator="{ on, attrs }">
|
|
|
|
- <v-avatar
|
|
|
|
- class="ma-3"
|
|
|
|
- v-bind="attrs"
|
|
|
|
- v-on="on">
|
|
|
|
- <img
|
|
|
|
- src="https://cdn.vuetifyjs.com/images/john.jpg"
|
|
|
|
- alt="John"
|
|
|
|
- >
|
|
|
|
- </v-avatar>
|
|
|
|
- </template>
|
|
|
|
-
|
|
|
|
- <v-card>
|
|
|
|
- <img
|
|
|
|
- style="display: block;"
|
|
|
|
- src="https://cdn.vuetifyjs.com/images/john.jpg"
|
|
|
|
- width="300"
|
|
|
|
- alt="John"
|
|
|
|
- >
|
|
|
|
- </v-card>
|
|
|
|
- </v-menu> -->
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template #companyInfo>
|
|
|
|
- <v-subheader>公司/酒店信息</v-subheader>
|
|
|
|
- </template>
|
|
|
|
- <template #relationship>
|
|
|
|
- <v-subheader>联系方式</v-subheader>
|
|
|
|
- </template>
|
|
|
|
- <template #addressInfo>
|
|
|
|
- <v-subheader>地址信息</v-subheader>
|
|
|
|
- </template>
|
|
|
|
- <template #career_path="{ item }">
|
|
|
|
- <div class="flex-grow-1 flex-shrink-1">
|
|
|
|
- <v-subheader>职业轨迹</v-subheader>
|
|
|
|
- <div>
|
|
|
|
- <v-row v-for="(path, index) in formQuery[item.key]" :key="index">
|
|
|
|
- <v-col :cols="4"><v-text-field hide-details v-model="path.company_name" outlined dense label="酒店名称"/></v-col>
|
|
|
|
- <v-col :cols="1" class="d-flex align-center justify-center">
|
|
|
|
- <v-icon>mdi-minus</v-icon>
|
|
|
|
- </v-col>
|
|
|
|
- <v-col :cols="4"><v-text-field hide-details v-model="path.position" outlined dense label="职位名称"/></v-col>
|
|
|
|
- <v-col :cols="3">
|
|
|
|
- <v-btn color="primary" @click="addCareerPath(index)">添加</v-btn>
|
|
|
|
- <v-btn v-if="formQuery[item.key]?.length > 1" class="ml-2" color="error" @click="removeCareerPath(index)">删除</v-btn>
|
|
|
|
- </v-col>
|
|
|
|
- </v-row>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template #systemInfo>
|
|
|
|
- <div class="pb-3">
|
|
|
|
- <v-subheader>系统信息</v-subheader>
|
|
|
|
- <div class="px-3 infoBox">
|
|
|
|
- <div class="mb-3">
|
|
|
|
- <span class="label">状态</span>
|
|
|
|
- <v-chip small :color="itemData.status === 'active' ? 'success' : 'error'">
|
|
|
|
- {{ itemData.status === 'active' ? '已启用' : '已禁用' }}
|
|
|
|
- </v-chip>
|
|
|
|
- </div>
|
|
|
|
- <div class="mb-3">
|
|
|
|
- <span class="label">创建时间</span>
|
|
|
|
- <v-chip small color="default">{{ itemData.created_at }}</v-chip>
|
|
|
|
- </div>
|
|
|
|
- <div class="mb-3">
|
|
|
|
- <span class="label">更新时间</span>
|
|
|
|
- <v-chip small color="default">{{ itemData.updated_at }}</v-chip>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- </MForm>
|
|
|
|
- </div>
|
|
|
|
- </MCard>
|
|
|
|
- </div>
|
|
|
|
- <Linear text="解析中..." v-model:visible="linearLoading"/>
|
|
|
|
- </m-dialog>
|
|
|
|
|
|
+ <div>
|
|
|
|
+ </div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
-<script>
|
|
|
|
-import Linear from '@/components/Progress/linear.vue'
|
|
|
|
-import UploadBtn from '@/components/UploadBtn'
|
|
|
|
-import MDialog from '@/components/Dialog'
|
|
|
|
-import MCard from '@/components/MCard'
|
|
|
|
-import MForm from '@/components/MForm'
|
|
|
|
-// import { toBase64 } from '@/utils/file'
|
|
|
|
-import {
|
|
|
|
- businessCardParse,
|
|
|
|
- getBusinessCardImage,
|
|
|
|
- updateBusinessCard
|
|
|
|
-} from '@/api/dataOrigin'
|
|
|
|
-export default {
|
|
|
|
- name: 'ImageImportEdit',
|
|
|
|
- components: {
|
|
|
|
- MDialog,
|
|
|
|
- MCard,
|
|
|
|
- UploadBtn,
|
|
|
|
- Linear,
|
|
|
|
- MForm
|
|
|
|
- },
|
|
|
|
- data () {
|
|
|
|
- return {
|
|
|
|
- linearLoading: false,
|
|
|
|
- loading: false,
|
|
|
|
- show: false,
|
|
|
|
- file: null,
|
|
|
|
- previewUrl: null,
|
|
|
|
- formItems: [
|
|
|
|
- { slotName: 'baseInfo' },
|
|
|
|
- { label: '中文姓名', key: 'name_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文姓名', key: 'name_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '中文职位/头衔', key: 'title_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文职位/头衔', key: 'title_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { slotName: 'relationship' },
|
|
|
|
- { label: '手机号码', key: 'mobile', type: 'text', outlined: true, dense: true, col: 4 },
|
|
|
|
- { label: '固定电话', key: 'phone', type: 'text', outlined: true, dense: true, col: 4 },
|
|
|
|
- { label: '电子邮箱', key: 'email', type: 'text', outlined: true, dense: true, col: 4 },
|
|
|
|
- { slotName: 'companyInfo' },
|
|
|
|
- { label: '中文酒店/公司名称', key: 'hotel_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文酒店/公司名称', key: 'hotel_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '中文品牌名称', key: 'brand_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文品牌名称', key: 'brand_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '中文隶属关系', key: 'affiliation_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文隶属关系', key: 'affiliation_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '品牌组合', key: 'brand_group', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { slotName: 'career_path', key: 'career_path' },
|
|
|
|
- { slotName: 'addressInfo' },
|
|
|
|
- { label: '中文地址', key: 'address_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文地址', key: 'address_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '中文邮政编码', key: 'postal_code_zh', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { label: '英文邮政编码', key: 'postal_code_en', type: 'text', outlined: true, dense: true, col: 6 },
|
|
|
|
- { slotName: 'systemInfo' }
|
|
|
|
- ],
|
|
|
|
- formQuery: {},
|
|
|
|
- id: null,
|
|
|
|
- itemData: null
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- methods: {
|
|
|
|
- async open (item) {
|
|
|
|
- this.show = true
|
|
|
|
- this.loading = false
|
|
|
|
- this.itemData = null
|
|
|
|
- const defaultCareer = {
|
|
|
|
- company_name: null,
|
|
|
|
- position: null
|
|
|
|
- }
|
|
|
|
- this.formQuery = this.formItems.reduce((res, val) => {
|
|
|
|
- if (val.key) {
|
|
|
|
- res[val.key] = val.key === 'career_path' ? [defaultCareer] : null
|
|
|
|
- }
|
|
|
|
- return res
|
|
|
|
- }, {})
|
|
|
|
- if (!item) {
|
|
|
|
- this.file = null
|
|
|
|
- this.previewUrl = null
|
|
|
|
- this.id = null
|
|
|
|
- this.formQuery.career_path = [defaultCareer]
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- this.id = item.id
|
|
|
|
- this.itemData = { ...item }
|
|
|
|
- Object.keys(this.formQuery).forEach(key => {
|
|
|
|
- this.formQuery[key] = item[key] || (key === 'career_path' ? [defaultCareer] : null)
|
|
|
|
- })
|
|
|
|
- // 获取文件内容
|
|
|
|
- if (!item.image_path) {
|
|
|
|
- this.file = null
|
|
|
|
- this.previewUrl = null
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- try {
|
|
|
|
- const { data } = await getBusinessCardImage(item.image_path)
|
|
|
|
- this.file = new File([data], item.image_path, { type: data.type })
|
|
|
|
- this.previewUrl = URL.createObjectURL(data)
|
|
|
|
- } catch (error) {
|
|
|
|
- this.$snackbar.error(error)
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- async handleImport (file) {
|
|
|
|
- this.loading = true
|
|
|
|
- this.file = file
|
|
|
|
- this.handlePreview(file, () => {
|
|
|
|
- this.loading = false
|
|
|
|
- })
|
|
|
|
- },
|
|
|
|
- handlePreview (file, cb) {
|
|
|
|
- // 创建预览
|
|
|
|
- const reader = new FileReader()
|
|
|
|
- reader.onload = (e) => {
|
|
|
|
- this.previewUrl = e.target.result
|
|
|
|
- cb()
|
|
|
|
- }
|
|
|
|
- reader.readAsDataURL(file)
|
|
|
|
- },
|
|
|
|
- async handleAnalysis () {
|
|
|
|
- this.linearLoading = true
|
|
|
|
- const query = new FormData()
|
|
|
|
- query.append('image', this.file)
|
|
|
|
- try {
|
|
|
|
- const { data } = await businessCardParse(query)
|
|
|
|
- this.id = data.id
|
|
|
|
- this.itemData = { ...data }
|
|
|
|
- Object.keys(this.formQuery).forEach(key => {
|
|
|
|
- this.formQuery[key] = data[key] || null
|
|
|
|
- })
|
|
|
|
- this.$snackbar.success('名片解析成功')
|
|
|
|
- } catch (error) {
|
|
|
|
- this.$snackbar.error(error)
|
|
|
|
- } finally {
|
|
|
|
- this.linearLoading = false
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- addCareerPath () {
|
|
|
|
- this.formQuery.career_path = this.formQuery.career_path || []
|
|
|
|
- this.formQuery.career_path.push({
|
|
|
|
- company_name: null,
|
|
|
|
- position: null
|
|
|
|
- })
|
|
|
|
- },
|
|
|
|
- removeCareerPath (index) {
|
|
|
|
- if (this.formQuery.career_path && this.formQuery.career_path.length > index) {
|
|
|
|
- this.formQuery.career_path.splice(index, 1)
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- async handleUpdate () {
|
|
|
|
- if (!this.id) {
|
|
|
|
- this.$snackbar.error('ID获取异常')
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- Object.assign(this.itemData, this.formQuery)
|
|
|
|
- try {
|
|
|
|
- await updateBusinessCard(this.itemData, this.id)
|
|
|
|
- this.$snackbar.success('更新成功')
|
|
|
|
- } catch (error) {
|
|
|
|
- this.$snackbar.error(error)
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- handleClose () {
|
|
|
|
- if (!this.id) {
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- this.$emit('refresh')
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-</script>
|
|
|
|
-
|
|
|
|
-<style lang="scss" scoped>
|
|
|
|
-.fullBox {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
- min-height: 400px;
|
|
|
|
-}
|
|
|
|
-.upload-card {
|
|
|
|
- // position: relative;
|
|
|
|
- .change {
|
|
|
|
- position: sticky;
|
|
|
|
- top: 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-.box-1 {
|
|
|
|
- display: grid;
|
|
|
|
- grid-template-columns: 1fr;
|
|
|
|
- &.box-2 {
|
|
|
|
- grid-template-columns: 1fr 1fr;
|
|
|
|
- grid-gap: 15px;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+<script setup>
|
|
|
|
+defineOptions({ name: 'ImageImportEdit' })
|
|
|
|
|
|
-.infoBox {
|
|
|
|
- .label {
|
|
|
|
- width: 100px;
|
|
|
|
- display: inline-block;
|
|
|
|
- text-align: right;
|
|
|
|
- margin-right: 10px;
|
|
|
|
- color: #666;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-</style>
|
|
|
|
|
|
+const activeName = ref('resume')
|
|
|
|
+</script>
|