diff --git a/packages/ui/src/main/utils/initPublicIpc.ts b/packages/ui/src/main/utils/initPublicIpc.ts
index 4d8ea11..0b7e254 100644
--- a/packages/ui/src/main/utils/initPublicIpc.ts
+++ b/packages/ui/src/main/utils/initPublicIpc.ts
@@ -1,4 +1,7 @@
import { BrowserWindow, ipcMain, shell } from 'electron'
+import gtag from './gtag'
+import buildInfo from '../../common/build-info.json'
+import os from 'node:os'
export default function initPublicIpc() {
ipcMain.on(
@@ -23,4 +26,33 @@ export default function initPublicIpc() {
activate: true
})
})
+ ipcMain.on('gtag', (ev, { name, params } = {}) => {
+ gtag(name, {
+ ...params,
+ electronLogSource: 'renderer'
+ })
+ })
+ ipcMain.on('send-feed-back-to-github-issue', (ev, payload) => {
+ const getIssueUrlWithBody = (issueBody: string = '') => {
+ const baseUrl = `https://github.com/geekgeekrun/geekgeekrun/issues/new`
+ issueBody = issueBody || ''
+ if (!issueBody || !issueBody.trim()) {
+ return baseUrl
+ }
+ const urlObj = new URL(baseUrl)
+ urlObj.searchParams.append('body', issueBody)
+
+ return urlObj.toString()
+ }
+
+ shell.openExternal(
+ getIssueUrlWithBody(`\n\n\n-----
+版本号:${buildInfo.version}(${buildInfo.buildVersion})
+提交:${buildInfo.buildHash.substring(0, 6)}
+操作系统信息: \`${os.type()}\` / \`${os.release()}\` / \`${os.arch()}\``),
+ {
+ activate: true
+ }
+ )
+ })
}
diff --git a/packages/ui/src/renderer/src/App.vue b/packages/ui/src/renderer/src/App.vue
index cb291fa..e804103 100644
--- a/packages/ui/src/renderer/src/App.vue
+++ b/packages/ui/src/renderer/src/App.vue
@@ -9,4 +9,11 @@
diff --git a/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue b/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue
index c42e141..d100754 100644
--- a/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue
+++ b/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue
@@ -26,6 +26,7 @@
import { useRouter } from 'vue-router'
import { onMounted, ref } from 'vue'
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
+import { gtagRenderer } from '@renderer/utils/gtag'
const router = useRouter()
@@ -33,10 +34,12 @@ const checkDependenciesResult = ref({})
const downloadProcessWaitee = ref(null)
onMounted(async () => {
+ gtagRenderer('bootstrap_mounted')
checkDependenciesResult.value = await electron.ipcRenderer.invoke('check-dependencies')
downloadProcessWaitee.value = Promise.withResolvers()
if (Object.values(checkDependenciesResult.value).includes(false)) {
+ gtagRenderer('dependencies_need_download')
router.replace('/downloadingDependencies')
} else {
downloadProcessWaitee.value!.resolve()
@@ -45,6 +48,7 @@ onMounted(async () => {
downloadProcessWaitee.value!.promise.then(async () => {
const isCookieFileValid = await electron.ipcRenderer.invoke('check-boss-zhipin-cookie-file')
if (!isCookieFileValid) {
+ gtagRenderer('found_cookie_invalid_when_bootstrap')
router.replace('/cookieAssistant')
} else {
await sleep(1000)
diff --git a/packages/ui/src/renderer/src/page/BootstrapSplash/page/DownloadingDependencies.vue b/packages/ui/src/renderer/src/page/BootstrapSplash/page/DownloadingDependencies.vue
index fbc663d..def3c45 100644
--- a/packages/ui/src/renderer/src/page/BootstrapSplash/page/DownloadingDependencies.vue
+++ b/packages/ui/src/renderer/src/page/BootstrapSplash/page/DownloadingDependencies.vue
@@ -13,6 +13,7 @@
diff --git a/packages/ui/src/renderer/src/page/MainLayout/JobLibrary.vue b/packages/ui/src/renderer/src/page/MainLayout/JobLibrary.vue
index 67f74fb..dabff25 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/JobLibrary.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/JobLibrary.vue
@@ -55,7 +55,17 @@
- 刷新
+ {
+ gtagRenderer('job_library_refresh_clicked')
+ getJobLibrary()
+ }
+ "
+ >刷新
{
+ gtagRenderer('job_info_snapshot_closed')
+ selectedJobInfoForViewSnapshot = null
+ }
+ "
/>
{
+ gtagRenderer('job_library_list_dialog_closed')
selectedJobInfoForViewHistory = null
selectedJobHistory = null
}
@@ -110,6 +126,7 @@ import { type JobInfoChangeLog } from '@geekgeekrun/sqlite-plugin/src/entity/Job
import { PageReq, PagedRes } from '../../../../common/types/pagination'
import JobInfoSnapshot from '../../features/JobInfoSnapshot/index.vue'
import JobInfoHistoryList from '../../features/JobInfoHistoryList/index.vue'
+import { gtagRenderer } from '@renderer/utils/gtag'
const tableData = ref([])
const pageSizeList = ref([100, 200, 300, 400])
@@ -122,6 +139,10 @@ const tableRef = ref>()
const isTableLoading = ref(false)
async function getJobLibrary() {
try {
+ gtagRenderer('job_library_request_sent', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
isTableLoading.value = true
const { data: res } = (await electron.ipcRenderer.invoke('get-job-library', {
pageNo: pagination.value.pageNo,
@@ -133,7 +154,16 @@ async function getJobLibrary() {
pageNo: res.pageNo,
pageSize: pagination.value.pageSize
}
+ gtagRenderer('job_library_request_success', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
} catch (err) {
+ gtagRenderer('job_library_request_error', {
+ err,
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
console.log(err)
tableData.value = []
} finally {
@@ -161,10 +191,12 @@ const drawVisibleModelValue = ref(false)
const selectedJobInfoForViewSnapshot = ref(null)
function handleViewJobSnapshotButtonClick(record: VChatStartupLog) {
+ gtagRenderer('view_job_snapshot_button_clicked')
selectedJobInfoForViewSnapshot.value = record
drawVisibleModelValue.value = true
}
async function handleViewJobOnlineButtonClick(encryptJobId: string) {
+ gtagRenderer('view_job_online_button_clicked')
return await electron.ipcRenderer.invoke('open-site-with-boss-cookie', {
url: `https://www.zhipin.com/job_detail/${encryptJobId}.html`
})
@@ -174,6 +206,7 @@ const historyDialogVisibleModelValue = ref(false)
const selectedJobInfoForViewHistory = ref(null)
const selectedJobHistory = ref(null)
async function handleViewJobHistoryButtonClick(record: VChatStartupLog) {
+ gtagRenderer('view_job_history_button_clicked')
let { data: historyList } = await electron.ipcRenderer.invoke(
'get-job-history-by-encrypt-id',
record.encryptJobId
@@ -228,12 +261,13 @@ async function handleViewJobHistoryButtonClick(record: VChatStartupLog) {
// })
if (!historyList.length) {
+ gtagRenderer('job_history_is_not_found')
ElMessage.warning({
message: '未找到与此条目相关的历史变更记录,再多投一投吧'
})
return
}
-
+ gtagRenderer('job_history_is_found')
historyDialogVisibleModelValue.value = true
selectedJobInfoForViewHistory.value = record
selectedJobHistory.value = historyList
diff --git a/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue b/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
index 76d9dfc..19918f3 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
@@ -72,7 +72,15 @@
- {
+ gtagRenderer('mark_as_not_suit_record_refresh_clicked')
+ getMarkAsNotSuitRecord()
+ }
+ "
>刷新
@@ -93,7 +101,12 @@
{
+ gtagRenderer('mark_as_not_suit_record_closed')
+ selectedJobInfoForViewSnapshot = null
+ }
+ "
/>
@@ -107,6 +120,7 @@ import { PageReq, PagedRes } from '../../../../common/types/pagination'
import JobInfoSnapshot from '../../features/JobInfoSnapshot/index.vue'
import { MarkAsNotSuitReason } from '@geekgeekrun/sqlite-plugin/src/enums'
import { transformUtcDateToLocalDate } from '@geekgeekrun/utils/date.mjs'
+import { gtagRenderer } from '@renderer/utils/gtag'
const tableData = ref([])
const pageSizeList = ref([100, 200, 300, 400])
@@ -122,6 +136,10 @@ const tableRef = ref>()
const isTableLoading = ref(false)
async function getMarkAsNotSuitRecord() {
try {
+ gtagRenderer('mark_as_not_suit_record_request_sent', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
isTableLoading.value = true
const { data: res } = (await electron.ipcRenderer.invoke('get-mark-as-not-suit-record', {
pageNo: pagination.value.pageNo,
@@ -133,7 +151,16 @@ async function getMarkAsNotSuitRecord() {
pageNo: res.pageNo,
pageSize: pagination.value.pageSize
}
+ gtagRenderer('mark_as_not_suit_record_request_success', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
} catch (err) {
+ gtagRenderer('mark_as_not_suit_record_request_error', {
+ err,
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
console.log(err)
tableData.value = []
} finally {
@@ -158,6 +185,7 @@ onMounted(() => {
})
async function handleViewJobOnlineButtonClick(encryptJobId: string) {
+ gtagRenderer('view_job_online_button_clicked')
return await electron.ipcRenderer.invoke('open-site-with-boss-cookie', {
url: `https://www.zhipin.com/job_detail/${encryptJobId}.html`
})
@@ -167,6 +195,7 @@ const drawVisibleModelValue = ref(false)
const selectedJobInfoForViewSnapshot = ref(null)
function handleViewJobSnapshotButtonClick(record: VMarkAsNotSuitLog) {
+ gtagRenderer('view_job_snapshot_button_clicked')
selectedJobInfoForViewSnapshot.value = record
drawVisibleModelValue.value = true
}
diff --git a/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue b/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue
index a17583a..2d209a9 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue
@@ -73,7 +73,16 @@
使用外部编辑器编辑提示词模板
-
+ {
+ gtagRenderer('reset_template_clicked_in_main_form')
+ restoreDefaultTemplate()
+ }
+ "
+ >
还原默认提示词模板
@@ -139,6 +148,8 @@ import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
import { dayjs, ElForm, ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import { RECHAT_CONTENT_SOURCE } from '../../../../common/enums/auto-start-chat'
+import { gtagRenderer } from '@renderer/utils/gtag'
+
const router = useRouter()
const formContent = ref({
autoReminder: {
@@ -155,8 +166,10 @@ const enableRechatLimit = computed({
},
set(val) {
if (!val) {
+ gtagRenderer('rechat_limit_disabled')
formContent.value.autoReminder.rechatLimitDay = 0
} else {
+ gtagRenderer('rechat_limit_enabled')
formContent.value.autoReminder.rechatLimitDay = 21
}
}
@@ -213,12 +226,17 @@ watch(
)
const handleSubmit = async () => {
+ gtagRenderer('save_config_clicked', {
+ ...formContent.value?.autoReminder
+ })
await formRef.value!.validate()
await electron.ipcRenderer.invoke('save-config-file-from-ui', JSON.stringify(formContent.value))
+ gtagRenderer('config_saved')
try {
await electron.ipcRenderer.invoke('check-if-auto-remind-prompt-valid')
} catch (err) {
if (err?.message?.includes(`RESUME_PLACEHOLDER_NOT_EXIST`)) {
+ gtagRenderer('cannot_launch_due_to_resume_placeholder_not_exist')
console.log(`提示词模板无效`, err)
ElMessageBox.confirm(
'提示词模板缺少简历内容占位符:
__REPLACE_REAL_RESUME_HERE__
您是否希望还原默认的提示词模板?',
@@ -232,10 +250,14 @@ const handleSubmit = async () => {
}
)
.then(async () => {
+ gtagRenderer('reset_template_clicked_in_invalid_tip_dialog')
await restoreDefaultTemplate()
})
- .catch(() => {})
+ .catch(() => {
+ gtagRenderer('close_invalid_tip_dialog')
+ })
} else {
+ gtagRenderer('cannot_launch_due_to_unknown_error', { err })
ElMessage({
type: 'error',
message: '用于生成自动提醒消息的提示词检查未通过,请重试'
@@ -243,6 +265,7 @@ const handleSubmit = async () => {
}
return
}
+ gtagRenderer('reminder_launched')
router.replace({
path: '/geekAutoStartChatWithBoss/prepareRun',
query: { flow: 'read-no-reply-reminder' }
@@ -287,6 +310,7 @@ const rechatLimitDateString = computed(() => {
})
const handleClickConfigLlm = async () => {
+ gtagRenderer('config_llm_clicked')
try {
await electron.ipcRenderer.invoke('llm-config')
} catch (err) {
@@ -295,6 +319,7 @@ const handleClickConfigLlm = async () => {
}
const handleClickEditResume = async () => {
+ gtagRenderer('edit_resume_clicked')
try {
await electron.ipcRenderer.invoke('resume-edit')
} catch (err) {
@@ -303,6 +328,7 @@ const handleClickEditResume = async () => {
}
const handleClickEditPrompt = async () => {
+ gtagRenderer('edit_prompt_clicked')
await electron.ipcRenderer.send('no-reply-reminder-prompt-edit')
}
diff --git a/packages/ui/src/renderer/src/page/MainLayout/StartChatRecord.vue b/packages/ui/src/renderer/src/page/MainLayout/StartChatRecord.vue
index 978d41d..d049ba7 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/StartChatRecord.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/StartChatRecord.vue
@@ -55,7 +55,15 @@
- {
+ gtagRenderer('start_chat_record_refresh_clicked')
+ getAutoStartChatRecord()
+ }
+ "
>刷新
@@ -76,7 +84,12 @@
{
+ gtagRenderer('start_chat_record_closed')
+ selectedJobInfoForViewSnapshot = null
+ }
+ "
/>
@@ -89,6 +102,7 @@ import { type VChatStartupLog } from '@geekgeekrun/sqlite-plugin/src/entity/VCha
import { transformUtcDateToLocalDate } from '@geekgeekrun/utils/date.mjs'
import { PageReq, PagedRes } from '../../../../common/types/pagination'
import JobInfoSnapshot from '../../features/JobInfoSnapshot/index.vue'
+import { gtagRenderer } from '@renderer/utils/gtag'
const tableData = ref([])
const pageSizeList = ref([100, 200, 300, 400])
@@ -104,6 +118,10 @@ const tableRef = ref>()
const isTableLoading = ref(false)
async function getAutoStartChatRecord() {
try {
+ gtagRenderer('start_chat_record_request_sent', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
isTableLoading.value = true
const { data: res } = (await electron.ipcRenderer.invoke('get-auto-start-chat-record', {
pageNo: pagination.value.pageNo,
@@ -115,7 +133,16 @@ async function getAutoStartChatRecord() {
pageNo: res.pageNo,
pageSize: pagination.value.pageSize
}
+ gtagRenderer('start_chat_record_request_success', {
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
} catch (err) {
+ gtagRenderer('start_chat_record_request_error', {
+ err,
+ page_no: pagination.value.pageNo,
+ page_size: pagination.value.pageSize,
+ })
console.log(err)
tableData.value = []
} finally {
diff --git a/packages/ui/src/renderer/src/page/MainLayout/index.vue b/packages/ui/src/renderer/src/page/MainLayout/index.vue
index d1a257b..6ab38e5 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/index.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/index.vue
@@ -41,6 +41,7 @@ import { ElIcon } from 'element-plus'
import { TopRight } from '@element-plus/icons-vue'
import useBuildInfo from '@renderer/hooks/useBuildInfo'
import { debounce } from 'lodash-es'
+import { gtagRenderer } from '@renderer/utils/gtag'
const router = useRouter()
const unmountedCbs: Array> = []
onUnmounted(() => {
@@ -76,31 +77,18 @@ onUnmounted(() => {
})()
const { buildInfo } = useBuildInfo()
-const getIssueUrlWithBody = (issueBody: string = '') => {
- const baseUrl = `https://github.com/geekgeekrun/geekgeekrun/issues/new`
- issueBody = issueBody || ''
- if (!issueBody || !issueBody.trim()) {
- return baseUrl
- }
- const urlObj = new URL(baseUrl)
- urlObj.searchParams.append('body', issueBody)
-
- return urlObj.toString()
-}
const handleFeedbackClick = () => {
- electron.ipcRenderer.send(
- 'open-external-link',
- getIssueUrlWithBody(`\n\n\n-----
-版本号:${buildInfo.value.version}(${buildInfo.value.buildVersion})
-提交:${buildInfo.value.buildHash.substring(0, 6)}`)
- )
+ gtagRenderer('goto_feedback_clicked')
+ electron.ipcRenderer.send('send-feed-back-to-github-issue')
}
const handleGotoProjectPageClick = () => {
+ gtagRenderer('goto_project_github_clicked')
electron.ipcRenderer.send('open-external-link', 'https://github.com/geekgeekrun/geekgeekrun')
}
const handleLaunchBossSite = debounce(
async () => {
+ gtagRenderer('launch-boss-site-clicked')
return await electron.ipcRenderer.invoke('open-site-with-boss-cookie', {
url: `https://www.zhipin.com/`
})
diff --git a/packages/ui/src/renderer/src/page/ResumeEditor/index.vue b/packages/ui/src/renderer/src/page/ResumeEditor/index.vue
index 5a26d13..ad41ad3 100644
--- a/packages/ui/src/renderer/src/page/ResumeEditor/index.vue
+++ b/packages/ui/src/renderer/src/page/ResumeEditor/index.vue
@@ -313,6 +313,7 @@
import { ElForm, ElButton, ElAlert } from 'element-plus'
import { ref, onMounted } from 'vue'
import { ArrowUp, ArrowDown, Delete, Plus } from '@element-plus/icons-vue'
+import { gtagRenderer } from '@renderer/utils/gtag'
interface ResumeContent {
name: string
@@ -360,10 +361,14 @@ const formContent = ref(getEmptyFormContent())
const formRules = {}
const handleCancel = () => {
+ gtagRenderer('cancel_clicked')
electron.ipcRenderer.send('close-resume-editor')
+ gtagRenderer('cancel_done')
}
const handleSubmit = async () => {
+ gtagRenderer('submit_clicked')
electron.ipcRenderer.invoke('save-resume-content', JSON.parse(JSON.stringify(formContent.value)))
+ gtagRenderer('submit_done')
}
onMounted(async () => {
@@ -410,12 +415,14 @@ function getNewWorkExpItem() {
}
function addWorkExp() {
formContent.value.geekWorkExpList.push(getNewWorkExpItem())
+ gtagRenderer('resume_work_exp_added')
}
function moveWorkExpUp(index) {
;[formContent.value.geekWorkExpList[index], formContent.value.geekWorkExpList[index - 1]] = [
formContent.value.geekWorkExpList[index - 1],
formContent.value.geekWorkExpList[index]
]
+ gtagRenderer('resume_work_exp_moved_up')
}
function moveWorkExpDown(index) {
@@ -423,10 +430,12 @@ function moveWorkExpDown(index) {
formContent.value.geekWorkExpList[index + 1],
formContent.value.geekWorkExpList[index]
]
+ gtagRenderer('resume_work_exp_moved_down')
}
function removeWorkExp(index) {
formContent.value.geekWorkExpList.splice(index, 1)
+ gtagRenderer('resume_work_exp_removed')
}
// #endregion
@@ -443,12 +452,14 @@ function getNewProjExpItem() {
}
function addProjExp() {
formContent.value.geekProjExpList.push(getNewProjExpItem())
+ gtagRenderer('resume_proj_exp_added')
}
function moveProjExpUp(index) {
;[formContent.value.geekProjExpList[index], formContent.value.geekProjExpList[index - 1]] = [
formContent.value.geekProjExpList[index - 1],
formContent.value.geekProjExpList[index]
]
+ gtagRenderer('resume_proj_exp_moved_up')
}
function moveProjExpDown(index) {
@@ -456,12 +467,18 @@ function moveProjExpDown(index) {
formContent.value.geekProjExpList[index + 1],
formContent.value.geekProjExpList[index]
]
+ gtagRenderer('resume_proj_exp_moved_down')
}
function removeProjExp(index) {
formContent.value.geekProjExpList.splice(index, 1)
+ gtagRenderer('resume_proj_exp_removed')
}
// #endregion
+
+onMounted(() => {
+ gtagRenderer('resume_editor_mounted')
+})