|
|
@@ -33,15 +33,38 @@
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
<view class="footer-btn">
|
|
|
- <fileSelector title="上传简历" allowType=".doc,.docx,.xls,.xlsx,.pdf" @fileSelected="uploadResumes"
|
|
|
+ <view class="white-btn" @click="handlUploadFile">附件简历一键识别</view>
|
|
|
+ <fileSelector title="简历上传" allowType=".doc,.docx,.xls,.xlsx,.pdf" @fileSelected="uploadResumes"
|
|
|
@filesChanged="onFilesChanged" />
|
|
|
</view>
|
|
|
+ <!-- 简历解析加载 -->
|
|
|
+ <view class="load-container" v-if="showLoadCard">
|
|
|
+ <image src="@/static/loading.gif" class="loading-image" mode="aspectFit"></image>
|
|
|
+ </view>
|
|
|
<!-- 权限说明弹窗 -->
|
|
|
<u-popup mode="top" ref="permission">
|
|
|
<view class="popup-content">
|
|
|
<view class="popup-text-permission">选择/拍摄照片需要相机/相册权限,用于上传用户头像</view>
|
|
|
</view>
|
|
|
</u-popup>
|
|
|
+ <!-- 同步解析简历数据 -->
|
|
|
+ <u-popup v-model="showResumesAnalysis" mode="bottom" border-radius="14" :mask-close-able="false">
|
|
|
+ <view class="resume-popup">
|
|
|
+ <view class="close-button flex align-center justify-center" @click="showResumesAnalysis = false">
|
|
|
+ <u-icon name="close" color="#fff" size="22" />
|
|
|
+ </view>
|
|
|
+ <view class="title">从附件简历中解析出<text>{{ validInfoCount }}段</text>有效信息</view>
|
|
|
+ <view class="tip">无需手动填写,可直接添加到在线简历中</view>
|
|
|
+ <view class="info-list">
|
|
|
+ <view class="info-item flex align-center" v-for="(item, index) in analysisList" :key="index">
|
|
|
+ <view class="label">{{ item.title }}</view>
|
|
|
+ <view class="border"></view>
|
|
|
+ <view class="content">{{ item.value }}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="button" @click="handleSync">立即同步</view>
|
|
|
+ </view>
|
|
|
+ </u-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -51,6 +74,10 @@ import navBar from "@/components/nav-bar/index.vue";
|
|
|
// 引入组件
|
|
|
import fileSelector from '@/uni_modules/zhouquan-fileSelector/components/zhouquan-fileSelector/file-selector.vue';
|
|
|
import empty from '../../components/empty.vue'
|
|
|
+// #ifdef APP-PLUS
|
|
|
+import { chooseFileFromModule } from '@/uni_modules/sr-file-choose'
|
|
|
+// #endif
|
|
|
+let AIResumeData = {}
|
|
|
export default {
|
|
|
components: {
|
|
|
navBar,
|
|
|
@@ -81,7 +108,29 @@ export default {
|
|
|
zhiFuBaoName: '',
|
|
|
sex: 1,
|
|
|
age: 0,
|
|
|
- content: []
|
|
|
+ content: [],
|
|
|
+ showLoadCard: false,
|
|
|
+ showResumesAnalysis: false,
|
|
|
+ validInfoCount: 0, // 有效信息数量
|
|
|
+ analysisList: [
|
|
|
+ {
|
|
|
+ title: '基本信息',
|
|
|
+ value: '',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '工作经历',
|
|
|
+ value: '',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '教育经历',
|
|
|
+ value: '',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '个人优势',
|
|
|
+ value: '',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ loading: false
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -130,7 +179,7 @@ export default {
|
|
|
let that = this;
|
|
|
let token = uni.getStorageSync('token');
|
|
|
uni.uploadFile({
|
|
|
- url: that.config("APIHOST1") +
|
|
|
+ url: this.$Request.config("APIHOST1") +
|
|
|
'/alioss/upload', //真实的接口地址
|
|
|
filePath: e.detail.avatarUrl,
|
|
|
header: {
|
|
|
@@ -150,95 +199,95 @@ export default {
|
|
|
url: '../jifen/myaddress'
|
|
|
});
|
|
|
},
|
|
|
- uploadImg() {
|
|
|
- let token = uni.getStorageSync('token')
|
|
|
-
|
|
|
- if (!token) {
|
|
|
- this.goLoginInfo();
|
|
|
- return;
|
|
|
- }
|
|
|
- let that = this;
|
|
|
- var url = null;
|
|
|
- uni.showActionSheet({
|
|
|
- // itemList按钮的文字接受的是数组
|
|
|
- itemList: ["查看头像", "从相册选择图片"],
|
|
|
- async success(e) {
|
|
|
- var index = e.tapIndex
|
|
|
- if (index === 0) {
|
|
|
- // 用户点击了预览当前图片
|
|
|
- // 可以自己实现当前头像链接的读取
|
|
|
- let url = that.avatar;
|
|
|
- let arr = []
|
|
|
- arr.push(url)
|
|
|
- uni.previewImage({
|
|
|
- // 预览功能图片也必须是数组的
|
|
|
- urls: arr
|
|
|
- })
|
|
|
- } else if (index === 1) {
|
|
|
- // 1. 检查权限状态
|
|
|
- const hasPermission = await this.$queue.checkPermission(
|
|
|
- 'camera',
|
|
|
- '选择/拍摄照片需要相机/相册权限,用于上传用户头像',
|
|
|
- this
|
|
|
- );
|
|
|
-
|
|
|
- // 2. 如果未授权或者用户拒绝,显示提示
|
|
|
- if (!hasPermission) {
|
|
|
- return;
|
|
|
- }
|
|
|
- uni.chooseImage({
|
|
|
- count: 1, //默认9
|
|
|
- sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
|
|
- sourceType: ['album'], //从相册选择
|
|
|
- success: function (res) {
|
|
|
- uni.showLoading({
|
|
|
- title: '上传中...'
|
|
|
- });
|
|
|
- let token = uni.getStorageSync('token');
|
|
|
- let userId = uni.getStorageSync('userId');
|
|
|
- uni.uploadFile({
|
|
|
- url: that.config("APIHOST1") +
|
|
|
- '/alioss/upload', //真实的接口地址
|
|
|
-
|
|
|
- filePath: res.tempFilePaths[0],
|
|
|
- header: {
|
|
|
- token: token
|
|
|
- },
|
|
|
- name: 'file',
|
|
|
- success: uploadFileRes => {
|
|
|
- url = JSON.parse(uploadFileRes.data);
|
|
|
- that.avatar = url.data
|
|
|
- uni.hideLoading();
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- },
|
|
|
- config: function (name) {
|
|
|
- var info = null;
|
|
|
- if (name) {
|
|
|
- var name2 = name.split("."); //字符分割
|
|
|
- if (name2.length > 1) {
|
|
|
- info = configdata[name2[0]][name2[1]] || null;
|
|
|
- } else {
|
|
|
- info = configdata[name] || null;
|
|
|
- }
|
|
|
- if (info == null) {
|
|
|
- let web_config = cache.get("web_config");
|
|
|
- if (web_config) {
|
|
|
- if (name2.length > 1) {
|
|
|
- info = web_config[name2[0]][name2[1]] || null;
|
|
|
- } else {
|
|
|
- info = web_config[name] || null;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return info;
|
|
|
- },
|
|
|
+ // uploadImg() {
|
|
|
+ // let token = uni.getStorageSync('token')
|
|
|
+
|
|
|
+ // if (!token) {
|
|
|
+ // this.goLoginInfo();
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // let that = this;
|
|
|
+ // var url = null;
|
|
|
+ // uni.showActionSheet({
|
|
|
+ // // itemList按钮的文字接受的是数组
|
|
|
+ // itemList: ["查看头像", "从相册选择图片"],
|
|
|
+ // async success(e) {
|
|
|
+ // var index = e.tapIndex
|
|
|
+ // if (index === 0) {
|
|
|
+ // // 用户点击了预览当前图片
|
|
|
+ // // 可以自己实现当前头像链接的读取
|
|
|
+ // let url = that.avatar;
|
|
|
+ // let arr = []
|
|
|
+ // arr.push(url)
|
|
|
+ // uni.previewImage({
|
|
|
+ // // 预览功能图片也必须是数组的
|
|
|
+ // urls: arr
|
|
|
+ // })
|
|
|
+ // } else if (index === 1) {
|
|
|
+ // // 1. 检查权限状态
|
|
|
+ // const hasPermission = await this.$queue.checkPermission(
|
|
|
+ // 'camera',
|
|
|
+ // '选择/拍摄照片需要相机/相册权限,用于上传用户头像',
|
|
|
+ // this
|
|
|
+ // );
|
|
|
+
|
|
|
+ // // 2. 如果未授权或者用户拒绝,显示提示
|
|
|
+ // if (!hasPermission) {
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // uni.chooseImage({
|
|
|
+ // count: 1, //默认9
|
|
|
+ // sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
|
|
+ // sourceType: ['album'], //从相册选择
|
|
|
+ // success: function (res) {
|
|
|
+ // uni.showLoading({
|
|
|
+ // title: '上传中...'
|
|
|
+ // });
|
|
|
+ // let token = uni.getStorageSync('token');
|
|
|
+ // let userId = uni.getStorageSync('userId');
|
|
|
+ // uni.uploadFile({
|
|
|
+ // url: this.$Request.config("APIHOST1") +
|
|
|
+ // '/alioss/upload', //真实的接口地址
|
|
|
+
|
|
|
+ // filePath: res.tempFilePaths[0],
|
|
|
+ // header: {
|
|
|
+ // token: token
|
|
|
+ // },
|
|
|
+ // name: 'file',
|
|
|
+ // success: uploadFileRes => {
|
|
|
+ // url = JSON.parse(uploadFileRes.data);
|
|
|
+ // that.avatar = url.data
|
|
|
+ // uni.hideLoading();
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ // },
|
|
|
+ // config: function (name) {
|
|
|
+ // var info = null;
|
|
|
+ // if (name) {
|
|
|
+ // var name2 = name.split("."); //字符分割
|
|
|
+ // if (name2.length > 1) {
|
|
|
+ // info = configdata[name2[0]][name2[1]] || null;
|
|
|
+ // } else {
|
|
|
+ // info = configdata[name] || null;
|
|
|
+ // }
|
|
|
+ // if (info == null) {
|
|
|
+ // let web_config = cache.get("web_config");
|
|
|
+ // if (web_config) {
|
|
|
+ // if (name2.length > 1) {
|
|
|
+ // info = web_config[name2[0]][name2[1]] || null;
|
|
|
+ // } else {
|
|
|
+ // info = web_config[name] || null;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // return info;
|
|
|
+ // },
|
|
|
getUserInfo() {
|
|
|
this.$Request.get("/app/resumes/getAttachment").then(res => {
|
|
|
if (res.code == 0) {
|
|
|
@@ -362,6 +411,173 @@ export default {
|
|
|
uni.navigateTo({
|
|
|
url: '/pages/index/webView?url=' + it.attachmentAddress + '&title=' + it.attachmentName
|
|
|
});
|
|
|
+ },
|
|
|
+ // 附件一键识别
|
|
|
+ handlUploadFile() {
|
|
|
+ if (this.content.length >= 3) {
|
|
|
+ this.$queue.showToast('最多保存三张附件简历,请删除后再试')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // #ifdef APP-PLUS
|
|
|
+ chooseFileFromModule({
|
|
|
+ complete: res => {
|
|
|
+ let path = res.path
|
|
|
+ let name = res.name
|
|
|
+ let fileType = ''
|
|
|
+ // 如果没有name,默认为:截取最后一个/之后的内容
|
|
|
+ if (!name) {
|
|
|
+ let lastIndex = path.lastIndexOf('/');
|
|
|
+ if (lastIndex !== -1) {
|
|
|
+ name = path.substring(lastIndex + 1);
|
|
|
+ } else {
|
|
|
+ name = Math.random().toString(36).substr(2) + Date.now();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 使用 lastIndexOf 方法找到最后一个 . 的位置
|
|
|
+ let lastDotIndex = name.lastIndexOf('.');
|
|
|
+ if (lastDotIndex !== -1) {
|
|
|
+ fileType = name.substring(lastDotIndex + 1);
|
|
|
+ } else {
|
|
|
+ console.log('文件路径中没有 .');
|
|
|
+ }
|
|
|
+ let file = {
|
|
|
+ size: res.size,
|
|
|
+ path,
|
|
|
+ fileType,
|
|
|
+ name
|
|
|
+ }
|
|
|
+ this.uploadFile(file)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // #endif
|
|
|
+ // #ifdef H5
|
|
|
+ uni.chooseFile({
|
|
|
+ count: 1,
|
|
|
+ success: res => {
|
|
|
+ this.uploadFile({
|
|
|
+ path: res.tempFilePaths[0],
|
|
|
+ name: 'file'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // #endif
|
|
|
+ },
|
|
|
+ // 上传文件
|
|
|
+ uploadFile(file) {
|
|
|
+ this.$queue.uploadFiles({
|
|
|
+ url: '/app/resumes/aiResumesUpload',
|
|
|
+ path: file.path,
|
|
|
+ name: 'file'
|
|
|
+ }, (res) => {
|
|
|
+ if (res && res.code === 0) {
|
|
|
+ const id = res.data?.id
|
|
|
+ const resumesAttachmentId = res.data?.resumesAttachmentId || ''
|
|
|
+ if (id) {
|
|
|
+ this.getAiResumesAnalysis(id, resumesAttachmentId)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传成功,获取简历列表数据
|
|
|
+ this.getUserInfo()
|
|
|
+ } else {
|
|
|
+ this.$queue.showToast(res ? res.msg : '文件上传失败')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 获取简历解析数据
|
|
|
+ getAiResumesAnalysis(fileId, resumesAttachmentId) {
|
|
|
+ this.showLoadCard = true
|
|
|
+ uni.request({
|
|
|
+ url: this.$Request.config('APIHOST') + '/app/resumes/aiResumesAnalysis',
|
|
|
+ header: {
|
|
|
+ 'content-type': 'application/x-www-form-urlencoded', // 模拟 form-data
|
|
|
+ token: uni.getStorageSync('token'),
|
|
|
+ },
|
|
|
+ method: 'post',
|
|
|
+ data: {
|
|
|
+ workflowId: '7594327567932309547',
|
|
|
+ fileId,
|
|
|
+ resumesAttachmentId
|
|
|
+ },
|
|
|
+ timeout: 180000,
|
|
|
+ success: (res) => {
|
|
|
+ this.stopLoadStatus()
|
|
|
+
|
|
|
+ if (res.data?.code == 0) {
|
|
|
+ const data = res.data.data.data
|
|
|
+ this.setAiResumesAnalysis(data.output)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ this.$queue.showToast('解析失败,请稍后重试')
|
|
|
+ this.stopLoadStatus()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ stopLoadStatus() {
|
|
|
+ this.showLoadCard = false
|
|
|
+ },
|
|
|
+ // 获取简历解析数据
|
|
|
+ setAiResumesAnalysis(data) {
|
|
|
+ AIResumeData = data || {}
|
|
|
+ if (data) {
|
|
|
+ this.showResumesAnalysis = true
|
|
|
+ // 基本信息
|
|
|
+ if (data.name || data.age || data.email) {
|
|
|
+ this.validInfoCount++
|
|
|
+ let dataArray = []
|
|
|
+ if (data.name) {
|
|
|
+ dataArray.push(data.name)
|
|
|
+ }
|
|
|
+ if (data.age) {
|
|
|
+ dataArray.push(data.age)
|
|
|
+ }
|
|
|
+ if (data.email) {
|
|
|
+ dataArray.push(data.email)
|
|
|
+ }
|
|
|
+ this.analysisList[0].value = dataArray.join('、')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 工作经历
|
|
|
+ if (data.workExperience?.length) {
|
|
|
+ this.validInfoCount++
|
|
|
+ let dataArray = data.workExperience.map(item => item.company)
|
|
|
+ this.analysisList[1].value = dataArray.join('、')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 教育经历
|
|
|
+ if (data.education?.length) {
|
|
|
+ this.validInfoCount++
|
|
|
+ let dataArray = data.education.map(item => item.school)
|
|
|
+ this.analysisList[2].value = dataArray.join('、')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 个人优势
|
|
|
+ if (data.selfEvaluation) {
|
|
|
+ this.validInfoCount++
|
|
|
+ this.analysisList[3].value = data.selfEvaluation
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 同步简历数据
|
|
|
+ handleSync() {
|
|
|
+ if (this.loading) return
|
|
|
+
|
|
|
+ uni.showLoading({ title: '同步中' })
|
|
|
+ this.loading = true
|
|
|
+ this.$Request
|
|
|
+ .postJson('/app/resumes/syncResumess', AIResumeData)
|
|
|
+ .then(res => {
|
|
|
+ if (res.code === 0) {
|
|
|
+ this.showResumesAnalysis = false
|
|
|
+ this.$queue.showToast('同步成功')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ this.loading = false
|
|
|
+ uni.hideLoading()
|
|
|
+ })
|
|
|
}
|
|
|
},
|
|
|
// userphone(){
|
|
|
@@ -616,10 +832,6 @@ button {
|
|
|
border: none;
|
|
|
}
|
|
|
|
|
|
-.footer-btn {
|
|
|
- margin-top: 40rpx;
|
|
|
-}
|
|
|
-
|
|
|
.footer-btn .usermain-btn {
|
|
|
color: rgba(255, 255, 255, 1);
|
|
|
background: rgba(1, 107, 246, 1);
|
|
|
@@ -674,4 +886,103 @@ button {
|
|
|
background: #f5f7fa !important;
|
|
|
transform: scale(0.99);
|
|
|
}
|
|
|
+
|
|
|
+.white-btn {
|
|
|
+ width: 600rpx;
|
|
|
+ font-size: 32rpx;
|
|
|
+ text-align: center;
|
|
|
+ color: #016bf6;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 88rpx;
|
|
|
+ margin: 32rpx auto 0;
|
|
|
+}
|
|
|
+
|
|
|
+.load-container {
|
|
|
+ position: fixed;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: rgba(0, 0, 0, 1);
|
|
|
+ .loading-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+// 解析简历popup
|
|
|
+.resume-popup {
|
|
|
+ position: relative;
|
|
|
+ padding: 70rpx 40rpx 40rpx;
|
|
|
+ .title {
|
|
|
+ font-size: 40rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 52rpx;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ text {
|
|
|
+ color: #016bf6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tip {
|
|
|
+ font-size: 28rpx;
|
|
|
+ line-height: 36rpx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ .info-list {
|
|
|
+ .info-item {
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: 1px solid rgba(242, 242, 242, 1);
|
|
|
+ border-radius: 6px;
|
|
|
+ background: rgba(250, 250, 250, 1);
|
|
|
+ padding: 26rpx 24rpx;
|
|
|
+ margin-top: 40rpx;
|
|
|
+ .label {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 1;
|
|
|
+ color: rgba(51, 51, 51, 1);
|
|
|
+ }
|
|
|
+ .border {
|
|
|
+ width: 1px;
|
|
|
+ height: 20rpx;
|
|
|
+ margin: 0 20rpx;
|
|
|
+ background: rgba(234, 234, 234, 1);
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ flex: 1;
|
|
|
+ width: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ color: rgba(153, 153, 153, 1);
|
|
|
+ font-size: 28rpx;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .button {
|
|
|
+ width: 600rpx;
|
|
|
+ height: 88rpx;
|
|
|
+ border-radius: 88rpx;
|
|
|
+ background: linear-gradient(90.00deg, rgba(13, 39, 247, 1),rgba(19, 193, 234, 1));
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 88rpx;
|
|
|
+ text-align: center;
|
|
|
+ color: #fff;
|
|
|
+ margin: 60rpx auto 0;
|
|
|
+ }
|
|
|
+ .close-button {
|
|
|
+ position: absolute;
|
|
|
+ top: 30rpx;
|
|
|
+ right: 40rpx;
|
|
|
+ width: 40rpx;
|
|
|
+ height: 40rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ background: rgba(230, 230, 230, 1);
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|