add gtag for renderer

This commit is contained in:
geekgeekrun
2025-04-13 18:55:19 +08:00
parent 3c951407ce
commit 4208996a83
18 changed files with 361 additions and 43 deletions

View File

@@ -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
}
)
})
}

View File

@@ -9,4 +9,11 @@
<script setup lang="ts">
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import { onMounted } from 'vue'
import { gtagRenderer } from './utils/gtag'
gtagRenderer('app_component_before_create')
onMounted(() => {
gtagRenderer('app_component_mounted')
})
</script>

View File

@@ -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)

View File

@@ -13,6 +13,7 @@
<script lang="ts" setup>
import { ref, onUnmounted, PropType } from 'vue'
import { ElMessageBox } from 'element-plus'
import { gtagRenderer } from '@renderer/utils/gtag'
const props = defineProps({
dependenciesStatus: {
@@ -47,9 +48,11 @@ const processDownloadBrowser = async () => {
const promiseList: Array<Promise<void>> = []
const processTasks = async () => {
if (!props.dependenciesStatus.puppeteerExecutableAvailable) {
gtagRenderer('start_download_puppeteer')
const p = processDownloadBrowser()
promiseList.push(p)
p.then(() => {
gtagRenderer('puppeteer_download_success')
props.dependenciesStatus.puppeteerExecutableAvailable = true
})
}
@@ -64,6 +67,7 @@ const processTasks = async () => {
})
await p
} catch {
gtagRenderer('encounter_error_when_downloading_dependencies')
await ElMessageBox.confirm('需要重试吗?', '核心组件下载失败', {
closeOnClickModal: false,
closeOnPressEscape: false,
@@ -72,9 +76,11 @@ const processTasks = async () => {
cancelButtonText: '退出程序'
})
.then(() => {
gtagRenderer('start_retry_download_dependencies')
processTasks()
})
.catch(() => {
gtagRenderer('cancel_download_dependencies_and_exit')
promiseList.length = 0
electron.ipcRenderer.invoke('exit-app-immediately')
})

View File

@@ -1,6 +1,6 @@
<template>
<div class="cookie-assistant-page">
<div ml1em mt1em mb1em >Cookie 助手</div>
<div ml1em mt1em mb1em font-size-16px>Cookie 助手</div>
<el-alert
v-if="cookieInvalid"
type="warning"
@@ -11,11 +11,11 @@
</el-alert>
<div ml1em mt1em line-height-normal>
如果您了解如何获取Cookie了解有效的Cookie格式可以直接在下方输入框中进行编辑由于手动编辑较为麻烦建议您打开已登录过Boss直聘的浏览器使用<a
color-blue
decoration-none
class="color-blue! decoration-none"
href="javascript:void(0)"
@click.prevent="handleEditThisCookieExtensionStoreLinkClick"
>EditThisCookie 扩展程序</a
>
EditThisCookie 扩展程序 </a
>复制Cookie然后粘贴在下方输入框中文本格式为被序列化为JSON的数组不含两侧引号
</div>
<br />
@@ -85,7 +85,12 @@
size="small"
type="primary"
font-size-inherit
@click="fillCollectedCookie"
@click="
() => {
gtagRenderer('replace_inputted_cookie_by_collected_cookie')
fillCollectedCookie()
}
"
>使用获取到的Cookie</el-button
></template
></el-alert
@@ -103,7 +108,8 @@
import { ElForm, ElMessage } from 'element-plus'
import { ref, onUnmounted, onMounted } from 'vue'
import { checkCookieListFormat } from '../../../../common/utils/cookie'
import { useRouter } from 'vue-router';
import { useRouter } from 'vue-router'
import { gtagRenderer } from '@renderer/utils/gtag'
const router = useRouter()
const cookieInvalid = ref(false)
@@ -138,11 +144,13 @@ const formRules = {
`JSON格式无效 - 存在语法错误: ${err.message}建议使用EditThisCookie扩展程序进行复制。`
)
)
gtagRenderer('wrong_cookie_format_for_json_syntax-error')
return
}
if (!checkCookieListFormat(JSON.parse(formContent.value.collectedCookies))) {
cb(new Error(`Cookie格式无效 - 部分字段缺失建议使用EditThisCookie扩展程序进行复制。`))
gtagRenderer('wrong_cookie_format_for_field_loss')
return
}
cb()
@@ -158,6 +166,9 @@ const handleCookieCollected = (_, payload) => {
collectedCookie.value = payload.cookies
if (!hasUserMutateInput.value) {
fillCollectedCookie()
gtagRenderer('cookie_collected_and_auto_filled')
} else {
gtagRenderer('cookie_collected_but_user_has_changed_input')
}
}
const fillCollectedCookie = () => {
@@ -169,27 +180,32 @@ const fillCollectedCookie = () => {
}
const handleClickLaunchLogin = () => {
gtagRenderer('launch_login_button_clicked')
electron.ipcRenderer.send('launch-bosszhipin-login-page-with-preload-extension')
loginCookieWaitingStatus.value = LOGIN_COOKIE_WAITING_STATUS.WAITING_FOR_LOGIN
}
const handleEditThisCookieExtensionStoreLinkClick = () => {
gtagRenderer('etc_extension_link_clicked')
electron.ipcRenderer.send(
'open-external-link',
'https://chromewebstore.google.com/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg'
'https://chromewebstore.google.com/detail/editthiscookie-v3/ojfebgpkimhlhcblbalbfjblapadhbol'
)
}
const handleCancel = () => {
gtagRenderer('cancel_clicked')
router.replace('/main-layout')
}
const handleSubmit = async () => {
gtagRenderer('save_clicked')
await formRef.value!.validate()
await electron.ipcRenderer.invoke('write-storage-file', {
fileName: 'boss-cookies.json',
data: formContent.value.collectedCookies
})
ElMessage.success('Boss直聘 Cookie 保存成功')
gtagRenderer('save_cookie_done')
router.replace('/main-layout')
}
@@ -199,6 +215,9 @@ const handleBossZhipinLoginPageClosed = () => {
}
}
onMounted(() => {
gtagRenderer('cookie_assistant_mounted')
})
onMounted(async () => {
electron.ipcRenderer.once('BOSS_ZHIPIN_COOKIE_COLLECTED', handleCookieCollected)
electron.ipcRenderer.on('BOSS_ZHIPIN_LOGIN_PAGE_CLOSED', handleBossZhipinLoginPageClosed)
@@ -226,6 +245,7 @@ onUnmounted(() => {
.cookie-assistant-page {
max-width: 640px;
margin: 0 auto;
font-size: 14px;
}
</style>

View File

@@ -87,6 +87,8 @@
<script lang="ts" setup>
import { ElCheckbox, ElCheckboxGroup, ElMessage } from 'element-plus'
import { ref, onMounted, onBeforeMount } from 'vue';
import { gtagRenderer } from '@renderer/utils/gtag'
const electron = window.electron
const readmeItemCheckStatusList = ref<number[]>([])
@@ -97,8 +99,10 @@ const handleCancel = () => {
const unreadItemsAfterClickSubmit = ref<Record<number, true>>({})
const handleSubmit = () => {
gtagRenderer('submit_clicked')
const COUNT = 9
if (readmeItemCheckStatusList.value.length !== COUNT) {
gtagRenderer('agreement_not_finish_read_tip_displayed')
ElMessage.warning(
`您还有${COUNT - readmeItemCheckStatusList.value.length}条没有读完,读完就打勾标记一下吧`
)
@@ -111,6 +115,7 @@ const handleSubmit = () => {
return
}
electron.ipcRenderer.invoke('first-launch-notice-approve')
gtagRenderer('submit_done')
}
const handleReadmeItemCheckStatusListChange = (value: number[]) => {
value.forEach((it) => {

View File

@@ -5,7 +5,16 @@
<div class="mt1em mb1em">
<div class="flex flex-items-center flex-justify-between">
<div>大语言模型设置</div>
<el-dropdown @command="(item) => openExternalLink(item.url)">
<el-dropdown
@command="
(item) => {
gtagRenderer('provider_url_for_secret_clicked', {
name: item.name
})
openExternalLink(item.url)
}
"
>
<el-button size="small"
>申请 API Secret <el-icon class="el-icon--right"><arrow-down /></el-icon
></el-button>
@@ -28,7 +37,12 @@
}"
href="javascript:void(0)"
@click.prevent="
openExternalLink('https://api-docs.deepseek.com/zh-cn/api/create-chat-completion')
() => {
gtagRenderer('chat_completion_intro_doc_link_clicked')
openExternalLink(
'https://api-docs.deepseek.com/zh-cn/api/create-chat-completion'
)
}
"
>对话补全</a
>且兼容
@@ -37,7 +51,12 @@
color: 'var(--el-color-primary)'
}"
href="javascript:void(0)"
@click.prevent="openExternalLink('https://www.npmjs.com/package/openai')"
@click.prevent="
() => {
gtagRenderer('openai_sdk_intro_doc_link_clicked')
openExternalLink('https://www.npmjs.com/package/openai')
}
"
>OpenAI SDK</a
>
</li>
@@ -158,6 +177,11 @@
maxRows: 10
}"
font-size-12px
@click="
nextTick(() =>
gtagRenderer('model_enable_status_changed', { enabled: conf.enabled })
)
"
></el-checkbox>
</el-form-item>
<el-form-item prop="serveWeight" class="ml40px">
@@ -175,6 +199,11 @@
:precision="0"
font-size-12px
placeholder="0 ~ 100"
@change="
(new_val, old_val) => {
gtagRenderer('serve_weight_changed', { new_val, old_val })
}
"
></el-input-number>
</el-form-item>
</div>
@@ -222,6 +251,7 @@ import {
} from 'element-plus'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
import { ref, onMounted, watch, nextTick } from 'vue'
import { gtagRenderer } from '@renderer/utils/gtag'
interface LlmConfigItem {
providerCompleteApiUrl: string
@@ -246,10 +276,14 @@ const formContent = ref<LlmConfigItem[]>([getNewConfigItem()])
const formRules = {}
const handleCancel = () => {
gtagRenderer('cancel_clicked')
electron.ipcRenderer.send('close-llm-config')
gtagRenderer('cancel_done')
}
const handleSubmit = async () => {
gtagRenderer('submit_clicked', { llm_config_length: formContent.value.length })
electron.ipcRenderer.invoke('save-llm-config', JSON.parse(JSON.stringify(formContent.value)))
gtagRenderer('submit_done')
}
onMounted(async () => {
@@ -359,6 +393,9 @@ const providerList: Array<{ name: string; url: string }> = [
]
function handlePresetClick(selected: (typeof llmPresetList)[number], index) {
gtagRenderer('model_preset_clicked', {
name: selected.name
})
for (const k of Object.keys(formContent.value[index])) {
formContent.value[index][k] = selected.config[k]
}
@@ -370,12 +407,14 @@ function addConfig() {
nextTick(() => {
firstInputRefList.value[firstInputRefList.value.length - 1]?.focus()
})
gtagRenderer('new_config_item_added')
}
function moveConfigUp(index) {
;[formContent.value[index], formContent.value[index - 1]] = [
formContent.value[index - 1],
formContent.value[index]
]
gtagRenderer('config_item_moved_up')
}
function moveConfigDown(index) {
@@ -383,10 +422,12 @@ function moveConfigDown(index) {
formContent.value[index + 1],
formContent.value[index]
]
gtagRenderer('config_item_moved_down')
}
function removeConfig(index) {
formContent.value.splice(index, 1)
gtagRenderer('config_item_removed')
}
watch(

View File

@@ -19,7 +19,17 @@
</div>
<div class="flex flex-0 flex-justify-between pt10px pb10px">
<div class="w100px">
<el-button :loading="isTableLoading" size="small" @click="getBossLibrary">刷新</el-button>
<el-button
:loading="isTableLoading"
size="small"
@click="
() => {
gtagRenderer('boss_library_refresh_clicked')
getBossLibrary()
}
"
>刷新</el-button
>
</div>
<ElPagination
v-model:current-page="pagination.pageNo"
@@ -42,6 +52,7 @@ import { ref, onMounted, onBeforeUnmount } from 'vue'
import { ElTable, ElTableColumn, ElButton, ElPagination } from 'element-plus'
import { type VChatStartupLog } from '@geekgeekrun/sqlite-plugin/src/entity/VChatStartupLog'
import { PageReq, PagedRes } from '../../../../common/types/pagination'
import { gtagRenderer } from '@renderer/utils/gtag'
const tableData = ref<VChatStartupLog[]>([])
const pageSizeList = ref<number[]>([100, 200, 300, 400])
@@ -54,6 +65,10 @@ const tableRef = ref<InstanceType<typeof ElTable>>()
const isTableLoading = ref(false)
async function getBossLibrary() {
try {
gtagRenderer('boss_library_request_sent', {
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
isTableLoading.value = true
const { data: res } = (await electron.ipcRenderer.invoke('get-boss-library', {
pageNo: pagination.value.pageNo,
@@ -65,7 +80,16 @@ async function getBossLibrary() {
pageNo: res.pageNo,
pageSize: pagination.value.pageSize
}
gtagRenderer('boss_library_request_success', {
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
} catch (err) {
gtagRenderer('boss_library_request_error', {
err,
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
console.log(err)
tableData.value = []
} finally {

View File

@@ -23,7 +23,15 @@
</div>
<div class="flex flex-0 flex-justify-between pt10px pb10px">
<div class="w100px">
<el-button :loading="isTableLoading" size="small" @click="getCompanyLibrary"
<el-button
:loading="isTableLoading"
size="small"
@click="
() => {
gtagRenderer('company_library_refresh_clicked')
getCompanyLibrary()
}
"
>刷新</el-button
>
</div>
@@ -49,6 +57,7 @@ import { ElTable, ElTableColumn, ElButton, ElPagination } from 'element-plus'
import { type VChatStartupLog } from '@geekgeekrun/sqlite-plugin/src/entity/VChatStartupLog'
import { PageReq, PagedRes } from '../../../../common/types/pagination'
import { formatCompanyScale } from '@geekgeekrun/sqlite-plugin/src/utils/parser'
import { gtagRenderer } from '@renderer/utils/gtag'
const tableData = ref<VChatStartupLog[]>([])
const pageSizeList = ref<number[]>([100, 200, 300, 400])
@@ -64,6 +73,10 @@ const tableRef = ref<InstanceType<typeof ElTable>>()
const isTableLoading = ref(false)
async function getCompanyLibrary() {
try {
gtagRenderer('company_library_request_sent', {
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
isTableLoading.value = true
const { data: res } = (await electron.ipcRenderer.invoke('get-company-library', {
pageNo: pagination.value.pageNo,
@@ -75,7 +88,16 @@ async function getCompanyLibrary() {
pageNo: res.pageNo,
pageSize: pagination.value.pageSize
}
gtagRenderer('company_library_request_success', {
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
} catch (err) {
gtagRenderer('company_library_request_error', {
err,
page_no: pagination.value.pageNo,
page_size: pagination.value.pageSize,
})
console.log(err)
tableData.value = []
} finally {

View File

@@ -66,6 +66,7 @@ import { ElForm, ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import AnyCombineBossRecommendFilter from '@renderer/features/AnyCombineBossRecommendFilter/index.vue'
import { calculateTotalCombinations } from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs'
import { gtagRenderer } from '@renderer/utils/gtag'
const router = useRouter()
const formContent = ref({
@@ -99,13 +100,16 @@ const formRules = {
validator(_, value, cb) {
if (!value) {
cb()
gtagRenderer('empty_reg_exp_for_expect_job')
return
}
try {
new RegExp(value, 'ig')
gtagRenderer('valid_reg_exp_for_expect_job')
cb()
} catch (err) {
cb(new Error(`正则无效:${err.message}`))
cb(new Error(`正则无效:${err?.message}`))
gtagRenderer('invalid_reg_exp_for_expect_job')
}
}
}
@@ -113,20 +117,29 @@ const formRules = {
const formRef = ref<InstanceType<typeof ElForm>>()
const handleSubmit = async () => {
gtagRenderer('save_config_and_launch_clicked', {
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken
})
formContent.value.expectJobRegExpStr = (formContent.value.expectJobRegExpStr || '').trim()
await formRef.value!.validate()
await electron.ipcRenderer.invoke('save-config-file-from-ui', JSON.stringify(formContent.value))
router.replace({
path: '/geekAutoStartChatWithBoss/prepareRun',
query: { flow: 'geek-auto-start-chat-with-boss' }
})
gtagRenderer('config_saved_and_will_launch_auto_start_chat', {
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken
})
}
const handleSave = async () => {
gtagRenderer('save_config_clicked', {
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken
})
normalizeExpectCompanies()
await formRef.value!.validate()
await electron.ipcRenderer.invoke('save-config-file-from-ui', JSON.stringify(formContent.value))
ElMessage.success('Configuration saved.')
ElMessage.success('配置保存成功')
gtagRenderer('config_saved')
}
const normalizeExpectCompanies = () => {
@@ -138,6 +151,7 @@ const normalizeExpectCompanies = () => {
}
const handleClickLaunchLogin = () => {
gtagRenderer('launch_login_clicked')
router.replace('/cookieAssistant')
}
</script>

View File

@@ -55,7 +55,17 @@
</div>
<div class="flex flex-0 flex-justify-between pt10px pb10px">
<div class="w100px">
<el-button :loading="isTableLoading" size="small" @click="getJobLibrary">刷新</el-button>
<el-button
:loading="isTableLoading"
size="small"
@click="
() => {
gtagRenderer('job_library_refresh_clicked')
getJobLibrary()
}
"
>刷新</el-button
>
</div>
<ElPagination
v-model:current-page="pagination.pageNo"
@@ -75,7 +85,12 @@
v-if="selectedJobInfoForViewSnapshot"
:job-info="selectedJobInfoForViewSnapshot"
scene="jobLibrary"
@closed="selectedJobInfoForViewSnapshot = null"
@closed="
() => {
gtagRenderer('job_info_snapshot_closed')
selectedJobInfoForViewSnapshot = null
}
"
/>
</ElDrawer>
<ElDialog
@@ -93,6 +108,7 @@
:job-info-history-list="selectedJobHistory ?? []"
@closed="
() => {
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<VChatStartupLog[]>([])
const pageSizeList = ref<number[]>([100, 200, 300, 400])
@@ -122,6 +139,10 @@ const tableRef = ref<InstanceType<typeof ElTable>>()
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<VChatStartupLog | null>(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<VChatStartupLog | null>(null)
const selectedJobHistory = ref<null | JobInfoChangeLog[]>(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

View File

@@ -72,7 +72,15 @@
</div>
<div class="flex flex-0 flex-justify-between pt10px pb10px">
<div class="w100px">
<el-button :loading="isTableLoading" size="small" @click="getMarkAsNotSuitRecord"
<el-button
:loading="isTableLoading"
size="small"
@click="
() => {
gtagRenderer('mark_as_not_suit_record_refresh_clicked')
getMarkAsNotSuitRecord()
}
"
>刷新</el-button
>
</div>
@@ -93,7 +101,12 @@
<JobInfoSnapshot
v-if="selectedJobInfoForViewSnapshot"
:job-info="selectedJobInfoForViewSnapshot"
@closed="selectedJobInfoForViewSnapshot = null"
@closed="
() => {
gtagRenderer('mark_as_not_suit_record_closed')
selectedJobInfoForViewSnapshot = null
}
"
/>
</ElDrawer>
</div>
@@ -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<VMarkAsNotSuitLog[]>([])
const pageSizeList = ref<number[]>([100, 200, 300, 400])
@@ -122,6 +136,10 @@ const tableRef = ref<InstanceType<typeof ElTable>>()
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<VMarkAsNotSuitLog | null>(null)
function handleViewJobSnapshotButtonClick(record: VMarkAsNotSuitLog) {
gtagRenderer('view_job_snapshot_button_clicked')
selectedJobInfoForViewSnapshot.value = record
drawVisibleModelValue.value = true
}

View File

@@ -73,7 +73,16 @@
<el-button size="small" type="primary" @click="handleClickEditPrompt">
使用外部编辑器编辑提示词模板
</el-button>
<el-button size="small" type="primary" @click="restoreDefaultTemplate">
<el-button
size="small"
type="primary"
@click="
() => {
gtagRenderer('reset_template_clicked_in_main_form')
restoreDefaultTemplate()
}
"
>
还原默认提示词模板
</el-button>
</div>
@@ -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(
'提示词模板缺少简历内容占位符:<br /><b>__REPLACE_REAL_RESUME_HERE__</b><br /><br />您是否希望还原默认的提示词模板?',
@@ -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')
}
</script>

View File

@@ -55,7 +55,15 @@
</div>
<div class="flex flex-0 flex-justify-between pt10px pb10px">
<div class="w100px">
<el-button :loading="isTableLoading" size="small" @click="getAutoStartChatRecord"
<el-button
:loading="isTableLoading"
size="small"
@click="
() => {
gtagRenderer('start_chat_record_refresh_clicked')
getAutoStartChatRecord()
}
"
>刷新</el-button
>
</div>
@@ -76,7 +84,12 @@
<JobInfoSnapshot
v-if="selectedJobInfoForViewSnapshot"
:job-info="selectedJobInfoForViewSnapshot"
@closed="selectedJobInfoForViewSnapshot = null"
@closed="
() => {
gtagRenderer('start_chat_record_closed')
selectedJobInfoForViewSnapshot = null
}
"
/>
</ElDrawer>
</div>
@@ -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<VChatStartupLog[]>([])
const pageSizeList = ref<number[]>([100, 200, 300, 400])
@@ -104,6 +118,10 @@ const tableRef = ref<InstanceType<typeof ElTable>>()
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 {

View File

@@ -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<InstanceType<typeof Function>> = []
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/`
})

View File

@@ -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<ResumeContent>(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')
})
</script>
<style lang="scss" scoped>

View File

@@ -1,5 +1,6 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import BootstrapSplash from '@renderer/page/BootstrapSplash/index.vue'
import { gtagRenderer } from '@renderer/utils/gtag'
const routes: Array<RouteRecordRaw> = [
{
@@ -128,7 +129,7 @@ const routes: Array<RouteRecordRaw> = [
component: () => import('@renderer/page/BootstrapSplash/page/DownloadingDependencies.vue'),
meta: {
title: '正在下载核心组件'
},
}
}
]
}
@@ -139,12 +140,16 @@ const router = createRouter({
routes
})
router.afterEach((to) => {
router.afterEach((to, from) => {
if (to.meta?.title) {
document.title = `${to.meta.title} - GeekGeekRun`
} else {
document.title = `GeekGeekRun`
}
gtagRenderer('router_path_changed', {
from_path: from.fullPath,
to_path: to.fullPath
})
})
export default router

View File

@@ -0,0 +1,17 @@
export function gtagRenderer(name, params: any = null) {
try {
electron.ipcRenderer.send('gtag', {
name,
params: {
...(params ?? {}),
user_agent: navigator.userAgent,
current_href: location.href,
screen_w: window.screen?.width ?? null,
screen_h: window.screen?.height ?? null,
screen_dpr: window.devicePixelRatio
}
})
} catch (err) {
console.log('gtag error', err)
}
}