flat: 添加微信分享卡片
This commit is contained in:
32
App.vue
32
App.vue
@@ -3,7 +3,9 @@ import { reactive, inject, onMounted } from 'vue';
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import useUserStore from './stores/useUserStore';
|
||||
import useDictStore from './stores/useDictStore';
|
||||
import { setupWechatShare, generateShareLink } from '@/utils/wechatShare.js';
|
||||
const { $api, navTo, appendScriptTagElement } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
|
||||
onLaunch((options) => {
|
||||
useDictStore().getDictData();
|
||||
@@ -26,15 +28,10 @@ onLaunch((options) => {
|
||||
|
||||
onMounted(() => {
|
||||
// #ifndef MP-WEIXIN
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
appendScriptTagElement('./static/js/jweixin-1.4.0.js').then(() => {
|
||||
console.log('✅ 微信 JSSDK 加载完成');
|
||||
});
|
||||
} else {
|
||||
appendScriptTagElement('/static/js/jweixin-1.4.0.js').then(() => {
|
||||
console.log('✅ 微信 JSSDK 加载完成');
|
||||
});
|
||||
}
|
||||
appendScriptTagElement('https://qd.zhaopinzao8dian.com/file/csn/jweixin-1.4.0.js').then(() => {
|
||||
console.log('✅ 微信 JSSDK 加载完成');
|
||||
signatureFn();
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
|
||||
@@ -45,6 +42,17 @@ onShow(() => {
|
||||
onHide(() => {
|
||||
console.log('App Hide');
|
||||
});
|
||||
|
||||
function signatureFn() {
|
||||
const link = generateShareLink();
|
||||
// console.log('首页link:', link);
|
||||
setupWechatShare({
|
||||
title: config.shareConfig.title,
|
||||
desc: config.shareConfig.desc,
|
||||
link: link,
|
||||
imgUrl: config.shareConfig.imgUrl,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -81,19 +89,19 @@ uni-modal,
|
||||
|
||||
@font-face {
|
||||
font-family: PingFangSC-Regular;
|
||||
src: url('/static/font/PingFangSC-Regular.woff2') format('woff2');
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/PingFangSC-Regular.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: PingFangSC-Medium;
|
||||
src: url('/static/font/PingFangSC-Medium.woff2') format('woff2');
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/PingFangSC-Medium.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: DIN-Medium;
|
||||
src: url('/static/font/DIN-Medium.woff2') format('woff2');
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/DIN-Medium.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
@@ -543,6 +543,7 @@ function isEmptyObject(obj) {
|
||||
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
|
||||
}
|
||||
|
||||
|
||||
export const $api = {
|
||||
msg,
|
||||
prePage,
|
||||
@@ -584,5 +585,5 @@ export default {
|
||||
appendScriptTagElement,
|
||||
insertSortData,
|
||||
isInWechatMiniProgramWebview,
|
||||
isEmptyObject
|
||||
isEmptyObject,
|
||||
}
|
@@ -63,5 +63,11 @@ export default {
|
||||
experience: 0.3, //经验
|
||||
salary: 0.5, // 薪资
|
||||
areas: 0.5 // 区域
|
||||
},
|
||||
shareConfig: {
|
||||
baseUrl: 'https://qd.zhaopinzao8dian.com',
|
||||
title: '找工作,用 AI 更高效|青岛市智能求职平台',
|
||||
desc: '融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!',
|
||||
imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg',
|
||||
}
|
||||
}
|
@@ -18,14 +18,14 @@
|
||||
</script>
|
||||
<title></title>
|
||||
<!-- vconsole -->
|
||||
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
vConsole.destroy();
|
||||
</script> -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
<!-- <body> -->
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
@@ -143,12 +143,16 @@ function expand() {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<AppLayout title="我的浏览" :show-bg-image="false" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
@@ -152,12 +152,16 @@ function getPreviousDay(dateStr) {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
@@ -101,12 +101,16 @@ function getDataList(type = 'add') {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
@@ -219,12 +219,16 @@ function getHoursBetween(startTimeStr, endTimeStr) {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
@@ -1,11 +1,14 @@
|
||||
<template>
|
||||
<AppLayout title="" backGorundColor="#F4F4F4">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<!-- <view class="btnshare">
|
||||
<image src="@/static/icon/share.png" @click="shareJob"></image>
|
||||
</view> -->
|
||||
<view class="btn mar_ri10">
|
||||
<image src="@/static/icon/collect3.png" v-if="!jobInfo.isCollection" @click="jobCollection"></image>
|
||||
<image src="@/static/icon/collect2.png" v-else @click="jobCollection"></image>
|
||||
@@ -137,10 +140,12 @@
|
||||
import point from '@/static/icon/point.png';
|
||||
import VideoPlayer from './component/videoPlayer.vue';
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { onLoad, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
const { $api, navTo, getLenPx, parseQueryParams, navBack, isEmptyObject } = inject('globalFunction');
|
||||
import RadarMap from './component/radarMap.vue';
|
||||
import { updateWechatShare, generateShareLink } from '@/utils/wechatShare.js';
|
||||
const { $api, navTo, getLenPx, parseQueryParams, navBack, isEmptyObject } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
const matchingDegree = ref(['一般', '良好', '优秀', '极好']);
|
||||
const currentStep = ref(1);
|
||||
const companyCount = ref(0);
|
||||
@@ -165,11 +170,31 @@ onShow(() => {
|
||||
}
|
||||
});
|
||||
|
||||
onHide(() => {
|
||||
const link = generateShareLink();
|
||||
// console.log('首页link:', link);
|
||||
updateWechatShare({
|
||||
title: config.shareConfig.title,
|
||||
desc: config.shareConfig.desc,
|
||||
link: link,
|
||||
imgUrl: config.shareConfig.imgUrl,
|
||||
});
|
||||
});
|
||||
|
||||
function initLoad(option) {
|
||||
const jobId = atob(option.jobId);
|
||||
if (jobId !== jobIdRef.value) {
|
||||
jobIdRef.value = jobId;
|
||||
getDetail(jobId);
|
||||
getDetail(jobId).then((data) => {
|
||||
const link = generateShareLink(btoa(data.jobId));
|
||||
// console.log('详情', link);
|
||||
updateWechatShare({
|
||||
title: '职位推荐:' + data.jobTitle,
|
||||
desc: data.description,
|
||||
link: link,
|
||||
imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,30 +207,33 @@ function seeExplain() {
|
||||
}
|
||||
|
||||
function getDetail(jobId) {
|
||||
$api.createRequest(`/app/job/${jobId}`).then((resData) => {
|
||||
const { latitude, longitude, companyName, companyId } = resData.data;
|
||||
jobInfo.value = resData.data;
|
||||
getCompanyIsAJobs(companyId);
|
||||
getCompetivetuveness(jobId);
|
||||
if (latitude && longitude) {
|
||||
mapCovers.value = [
|
||||
{
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
iconPath: point,
|
||||
label: {
|
||||
content: companyName,
|
||||
textAlign: 'center',
|
||||
padding: 3,
|
||||
fontSize: 12,
|
||||
bgColor: '#FFFFFF',
|
||||
anchorX: getTextWidth(companyName), // X 轴调整,负数向左
|
||||
borderRadius: 5,
|
||||
return new Promise((reslove, reject) => {
|
||||
$api.createRequest(`/app/job/${jobId}`).then((resData) => {
|
||||
const { latitude, longitude, companyName, companyId } = resData.data;
|
||||
jobInfo.value = resData.data;
|
||||
reslove(resData.data);
|
||||
getCompanyIsAJobs(companyId);
|
||||
getCompetivetuveness(jobId);
|
||||
if (latitude && longitude) {
|
||||
mapCovers.value = [
|
||||
{
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
iconPath: point,
|
||||
label: {
|
||||
content: companyName,
|
||||
textAlign: 'center',
|
||||
padding: 3,
|
||||
fontSize: 12,
|
||||
bgColor: '#FFFFFF',
|
||||
anchorX: getTextWidth(companyName), // X 轴调整,负数向左
|
||||
borderRadius: 5,
|
||||
},
|
||||
width: 34,
|
||||
},
|
||||
width: 34,
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -278,12 +306,21 @@ function getClass(index) {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
.btnshare {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 46rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<AppLayout title="附近" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
@@ -83,12 +83,16 @@ function handleTabChange(index) {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
|
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
BIN
static/font/.DS_Store
vendored
BIN
static/font/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
static/icon/share.png
Normal file
BIN
static/icon/share.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 350 B |
36
static/share.html
Normal file
36
static/share.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>找工作,用 AI 更高效|青岛市智能求职平台</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<!-- 微信分享卡片标签(动态填充) -->
|
||||
<meta property="og:title" content="找工作,用 AI 更高效|青岛市智能求职平台" />
|
||||
<meta property="og:description" content="融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!" />
|
||||
<meta property="og:image" content="https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg" />
|
||||
<meta property="og:url" content="https://qd.zhaopinzao8dian.com" />
|
||||
<meta name="description" content="融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!">
|
||||
|
||||
<script>
|
||||
const params = new URLSearchParams(location.search)
|
||||
const jobId = params.get('jobId')
|
||||
// document.querySelector('meta[property="og:url"]').setAttribute('content', location.href)
|
||||
|
||||
// 延迟跳转到 Vue 页面
|
||||
setTimeout(() => {
|
||||
if (jobId) {
|
||||
window.location.href = `/#/packageA/pages/post/post?jobId=${jobId}`
|
||||
} else {
|
||||
window.location.href = '/#/'
|
||||
}
|
||||
}, 300)
|
||||
// 测试使用 分享等形式打开
|
||||
// http://localhost:5173/app/static/share.html?jobId=MTE4MzQ4NTE4
|
||||
// http://localhost:5173/app/static/share.html?jobId=MTE4MzQ4NTE4&_t=1752221704007#/
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>正在加载中...</p>
|
||||
</body>
|
||||
</html>
|
BIN
unpackage/.DS_Store
vendored
BIN
unpackage/.DS_Store
vendored
Binary file not shown.
BIN
unpackage/dist/.DS_Store
vendored
BIN
unpackage/dist/.DS_Store
vendored
Binary file not shown.
BIN
unpackage/dist/build/.DS_Store
vendored
BIN
unpackage/dist/build/.DS_Store
vendored
Binary file not shown.
@@ -1,5 +1,7 @@
|
||||
import wx from 'weixin-js-sdk'
|
||||
import config from "@/config.js"
|
||||
import {
|
||||
$api
|
||||
} from '../common/globalFunction';
|
||||
|
||||
export function setupWechatShare({
|
||||
title,
|
||||
@@ -8,56 +10,72 @@ export function setupWechatShare({
|
||||
imgUrl
|
||||
}) {
|
||||
// 通过后端接口获取签名(必须)
|
||||
fetch(`${config.baseUrl}/wechat-signature?url=${encodeURIComponent(location.href.split('#')[0])}`)
|
||||
.then(res => res.json())
|
||||
.then(({
|
||||
$api.createRequest('/app/job/getWechatUrl', {
|
||||
imgUrl: location.href.split('#')[0]
|
||||
}, 'POST').then((resData) => {
|
||||
const {
|
||||
appId,
|
||||
timestamp,
|
||||
nonceStr,
|
||||
signature
|
||||
}) => {
|
||||
wx.config({
|
||||
debug: false,
|
||||
appId,
|
||||
timestamp,
|
||||
nonceStr,
|
||||
signature,
|
||||
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
|
||||
})
|
||||
} = resData.data
|
||||
|
||||
wx.ready(() => {
|
||||
// 分享给好友
|
||||
wx.updateAppMessageShareData({
|
||||
title,
|
||||
desc,
|
||||
link,
|
||||
imgUrl,
|
||||
success: () => {
|
||||
console.log('分享配置成功')
|
||||
}
|
||||
})
|
||||
|
||||
// 分享到朋友圈
|
||||
wx.updateTimelineShareData({
|
||||
title,
|
||||
link,
|
||||
imgUrl,
|
||||
success: () => {
|
||||
console.log('朋友圈分享配置成功')
|
||||
}
|
||||
})
|
||||
})
|
||||
wx.config({
|
||||
debug: false,
|
||||
appId,
|
||||
timestamp,
|
||||
nonceStr,
|
||||
signature,
|
||||
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
|
||||
})
|
||||
wx.ready(() => {
|
||||
// 分享给好友
|
||||
wx.updateAppMessageShareData({
|
||||
title,
|
||||
desc,
|
||||
link,
|
||||
imgUrl,
|
||||
success: () => {
|
||||
$api.msg('分享配置成功')
|
||||
}
|
||||
})
|
||||
// 分享到朋友圈
|
||||
wx.updateTimelineShareData({
|
||||
title,
|
||||
link,
|
||||
imgUrl,
|
||||
success: () => {
|
||||
$api.msg('朋友圈分享配置成功')
|
||||
}
|
||||
})
|
||||
}).catch((err) => {
|
||||
$api.msg('获取微信签名失败')
|
||||
console.error('获取微信签名失败:', err);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// 使用
|
||||
// import { setupWechatShare } from '@/utils/wechatShare.js'
|
||||
export function updateWechatShare({
|
||||
title,
|
||||
desc,
|
||||
link,
|
||||
imgUrl
|
||||
}) {
|
||||
if (!window.wx) return;
|
||||
wx.updateAppMessageShareData({
|
||||
title,
|
||||
desc,
|
||||
link,
|
||||
imgUrl,
|
||||
success: () => console.log('分享配置成功'),
|
||||
fail: (err) => console.warn('分享配置失败', err)
|
||||
});
|
||||
}
|
||||
|
||||
// onMounted(() => {
|
||||
// setupWechatShare({
|
||||
// title: '职位推荐:高级前端工程师',
|
||||
// desc: '某知名互联网公司,年薪40W,点击查看详情',
|
||||
// link: location.href,
|
||||
// imgUrl: 'https://yourcdn.com/job-thumbnail.png'
|
||||
// })
|
||||
// })
|
||||
|
||||
// tools
|
||||
export function generateShareLink(jobId) {
|
||||
const base = location.origin + '/app/static/share.html';
|
||||
const query = jobId ? `?jobId=${jobId}&_t=${Date.now()}` : `?_t=${Date.now()}`;
|
||||
return `${base}${query}`;
|
||||
}
|
Reference in New Issue
Block a user