2025-03-28 15:19:42 +08:00
|
|
|
|
import {
|
|
|
|
|
defineStore
|
|
|
|
|
} from 'pinia';
|
|
|
|
|
import {
|
|
|
|
|
ref
|
|
|
|
|
} from 'vue'
|
|
|
|
|
import useDictStore from '@/stores/useDictStore';
|
|
|
|
|
import jobAnalyzer from '@/utils/jobAnalyzer';
|
|
|
|
|
import {
|
|
|
|
|
msg
|
|
|
|
|
} from '@/common/globalFunction.js'
|
|
|
|
|
import baseDB from './BaseDBStore';
|
2025-06-20 10:10:46 +08:00
|
|
|
|
import config from '../config';
|
2025-03-28 15:19:42 +08:00
|
|
|
|
|
|
|
|
|
class JobRecommendation {
|
|
|
|
|
constructor() {
|
|
|
|
|
this.conditions = {}; // 存储最新的条件及其出现次数
|
|
|
|
|
this.askHistory = new Map(); // 记录每个条件的最后询问时间
|
|
|
|
|
this.cooldown = 5 * 60 * 1000; // 冷却时间(单位:毫秒)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateConditions(newConditions) {
|
|
|
|
|
this.conditions = newConditions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getCurrentTime() {
|
|
|
|
|
return Date.now();
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-13 11:10:38 +08:00
|
|
|
|
deleteHostiry(name) {
|
|
|
|
|
for (const [key, value] of Object.entries(this.conditions)) {
|
|
|
|
|
if (key === name) {
|
|
|
|
|
delete this.conditions[key]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.askHistory.delete(name)
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-28 15:19:42 +08:00
|
|
|
|
/**
|
|
|
|
|
* 获取下一个符合条件的推荐问题
|
|
|
|
|
* @returns {string|null} 返回推荐的问题,或 null(无可询问的)
|
|
|
|
|
*/
|
|
|
|
|
getNextQuestion() {
|
|
|
|
|
const now = this.getCurrentTime();
|
|
|
|
|
|
|
|
|
|
// 按照出现次数降序排序
|
|
|
|
|
const sortedConditions = Object.entries(this.conditions)
|
|
|
|
|
.sort((a, b) => b[1] - a[1]); // 按出现次数降序排序
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const [condition, count] of sortedConditions) {
|
|
|
|
|
const lastAskedTime = this.askHistory.get(condition);
|
|
|
|
|
|
|
|
|
|
if (!lastAskedTime || now - lastAskedTime >= this.cooldown) {
|
|
|
|
|
this.askHistory.set(condition, now);
|
|
|
|
|
|
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null; // 没有可询问的
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 10:10:46 +08:00
|
|
|
|
/**
|
|
|
|
|
* 计算加权用户行为偏好
|
|
|
|
|
* @param {Object} data - 用户行为数据,包括 categories、experience、areas、salary 等
|
|
|
|
|
* @param {Object} weights - 每一类行为的权重
|
|
|
|
|
* @returns {Object} 加权合并后的结果(key 为行为项,value 为权重后的分值)
|
|
|
|
|
*/
|
|
|
|
|
function applyWeightsToUserData(data, weights) {
|
|
|
|
|
const result = {}
|
|
|
|
|
|
|
|
|
|
for (const key in data) {
|
|
|
|
|
if (key === 'salary') {
|
|
|
|
|
result.salary = weights.salary
|
|
|
|
|
} else if (typeof data[key] === 'object') {
|
|
|
|
|
result[key] = {}
|
|
|
|
|
for (const itemKey in data[key]) {
|
|
|
|
|
const rawValue = data[key][itemKey]
|
|
|
|
|
result[key][itemKey] = parseFloat((rawValue * weights[key]).toFixed(2))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-28 15:19:42 +08:00
|
|
|
|
// **🔹 创建推荐系统**
|
|
|
|
|
export const jobRecommender = new JobRecommendation();
|
|
|
|
|
|
|
|
|
|
export const useRecommedIndexedDBStore = defineStore("indexedDB", () => {
|
|
|
|
|
const tableName = ref('record')
|
|
|
|
|
const total = ref(200) // 记录多少条数据
|
|
|
|
|
|
|
|
|
|
// 插入数据
|
|
|
|
|
async function addRecord(payload) {
|
|
|
|
|
const totalRecords = await baseDB.db.getRecordCount(tableName.value);
|
|
|
|
|
if (totalRecords >= total.value) {
|
|
|
|
|
console.log(`⚠数据超过 ${total.value} 条,删除最早的一条...`);
|
|
|
|
|
await baseDB.db.deleteOldestRecord(tableName.value);
|
|
|
|
|
}
|
|
|
|
|
if (!baseDB.isDBReady) await baseDB.initDB();
|
|
|
|
|
return await baseDB.db.add(tableName.value, payload);
|
|
|
|
|
}
|
2025-05-13 11:10:38 +08:00
|
|
|
|
// 清除数据 1、清除数据库数据
|
|
|
|
|
async function deleteRecords(payload) {
|
|
|
|
|
if (!baseDB.isDBReady) await baseDB.initDB();
|
|
|
|
|
try {
|
|
|
|
|
const jobstr = payload.jobCategory
|
|
|
|
|
const jobsObj = {
|
|
|
|
|
'地区': 'jobLocationAreaCodeLabel',
|
|
|
|
|
'岗位': 'jobCategory',
|
|
|
|
|
'经验': 'experIenceLabel',
|
|
|
|
|
}
|
|
|
|
|
const [name, value] = jobstr.split(':')
|
|
|
|
|
const nameAttr = jobsObj[name]
|
|
|
|
|
jobRecommender.deleteHostiry(jobstr)
|
|
|
|
|
return await baseDB.db.deleteByCondition(tableName.value, (record) => record[nameAttr] ===
|
|
|
|
|
value);
|
|
|
|
|
} catch {}
|
|
|
|
|
}
|
2025-03-28 15:19:42 +08:00
|
|
|
|
|
|
|
|
|
// 获取所有数据
|
|
|
|
|
async function getRecord() {
|
|
|
|
|
if (!baseDB.isDBReady) await baseDB.initDB();
|
|
|
|
|
return await baseDB.db.getAll(tableName.value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 格式化浏览数据岗位数据
|
|
|
|
|
function JobParameter(job) {
|
|
|
|
|
const experIenceLabel = useDictStore().dictLabel('experience', job.experience)
|
|
|
|
|
const jobLocationAreaCodeLabel = useDictStore().dictLabel('area', job.jobLocationAreaCode)
|
|
|
|
|
return {
|
|
|
|
|
jobCategory: job.jobCategory,
|
|
|
|
|
jobTitle: job.jobTitle,
|
|
|
|
|
minSalary: job.minSalary,
|
|
|
|
|
maxSalary: job.maxSalary,
|
|
|
|
|
experience: job.experience,
|
|
|
|
|
experIenceLabel,
|
|
|
|
|
jobLocationAreaCode: job.jobLocationAreaCode,
|
|
|
|
|
jobLocationAreaCodeLabel,
|
|
|
|
|
createTime: Date.now()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function analyzer(jobsData) {
|
2025-06-20 10:10:46 +08:00
|
|
|
|
const result = jobAnalyzer.analyze(jobsData) // 转换格式化
|
|
|
|
|
const result2 = applyWeightsToUserData(result, config.weights) // 添加权重
|
|
|
|
|
const sort = jobAnalyzer.printUnifiedResults(result2) // 转换格式化
|
2025-03-28 15:19:42 +08:00
|
|
|
|
return {
|
|
|
|
|
result,
|
|
|
|
|
sort
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
addRecord,
|
|
|
|
|
getRecord,
|
|
|
|
|
JobParameter,
|
2025-05-13 11:10:38 +08:00
|
|
|
|
analyzer,
|
|
|
|
|
deleteRecords
|
2025-03-28 15:19:42 +08:00
|
|
|
|
};
|
|
|
|
|
});
|