Commit 2e9fd981 authored by “yiyousong”'s avatar “yiyousong”

feat:添加数据埋点

parent d173528e
......@@ -22,6 +22,7 @@
"element-ui": "^2.15.10",
"file-saver": "^2.0.2",
"hammerjs": "^2.0.8",
"html2canvas": "^1.4.1",
"moment": "^2.29.4",
"npm": "^6.13.7",
"secure-ls": "^1.2.6",
......
......@@ -70,6 +70,7 @@ export default {
// devicenum: "B8-13-32-86-9F-04",
};
local.setLocal("devicenum", obj.devicenum);
local.setLocal("deviceInfo", obj.deviceInfo);
this.SET_deviceCode(obj.devicenum);
this.WebSocketMq(obj);
}
......@@ -113,9 +114,10 @@ export default {
getInfo() {
let routeQuery = this.urlGet();
if (JSON.stringify(routeQuery) !== "{}") {
let { devicenum } = routeQuery;
let { devicenum, deviceInfo } = routeQuery;
this.devicenum = devicenum;
local.setLocal("devicenum", devicenum);
local.setLocal("deviceInfo", deviceInfo);
this.SET_deviceCode(devicenum);
}
},
......@@ -144,7 +146,7 @@ export default {
if (this.linkDom) {
this.linkDom.remove();
}
if (data[0].cssFilePath) {
if (data.length && data[0].cssFilePath) {
let link = document.createElement("link");
this.linkDom = link;
link.rel = "stylesheet";
......
......@@ -137,3 +137,39 @@ export const getDeviceList = (data) => {
},
});
};
//热力图背景图上传
export function screenSave(params = {}) {
let deviceInfo = {};
try {
let { productId, productName } = local.getLocal("deviceInfo");
deviceInfo = { productId, productName };
} catch (error) {}
let javaBase = local.getLocal("serverUrl");
params["deviceNum"] = local.getLocal("devicenum");
return request({
url: `${javaBase}basics_api/zwfw/page/bury/screen/save`,
method: "post",
data: {
...deviceInfo,
...params,
},
});
}
//java数据埋点
export function burySave(params = {}) {
let deviceInfo = {};
try {
let { productId, productName } = local.getLocal("deviceInfo");
deviceInfo = { productId, productName };
} catch (error) {}
let javaBase = local.getLocal("serverUrl");
params["deviceNum"] = local.getLocal("devicenum");
return request({
url: `${javaBase}basics_api/zwfw/page/bury/save`,
method: "post",
data: {
...deviceInfo,
...params,
},
});
}
......@@ -7,7 +7,17 @@
<div></div>
</slot>
<div class="right-box flex aic">
<div class="back-one flex aic jcc pointer" @click="handleBack">
<div
class="back-one flex aic jcc pointer"
@click="handleBack"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'back',
businessName: '返回',
routers: $route,
}"
>
<span class="back-text">返回</span>
</div>
<slot name="right"><div></div></slot>
......
......@@ -23,6 +23,13 @@
v-for="v in matterInfo.matterDatumList"
:key="v.id"
@click="handleCheck(v)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'check_materials',
businessName: '查看表单',
routers: $route,
}"
>
<div class="pic-box">
<div class="pic-img-box">
......
......@@ -5,6 +5,13 @@
:value="value"
@keyup.native.enter="handleSearch"
@input="changeInput"
v-onEvent="{
eventName: '输入',
eventCode: 'Put',
businessCode: 'SEARCH',
businessName: '搜索',
routers: $route,
}"
>
<i
v-show="value"
......@@ -13,7 +20,17 @@
@click="handleClose"
></i>
</el-input>
<el-button class="search-btn" @click="handleSearch">
<el-button
class="search-btn"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'SEARCH',
businessName: '搜索',
routers: $route,
}"
@click="handleSearch"
>
<span class="flex aic jcc">
<img class="mr10" src="../assets/img/sousuo.png" /> 搜索
</span>
......@@ -101,4 +118,4 @@ export default {
border-color: var(--main-theme-color);
}
}
</style>
\ No newline at end of file
</style>
......@@ -31,6 +31,9 @@ Vue.use(scroll);
import format from "vue-text-format";
Vue.use(format);
// 引入数据埋点
import vueStatistics from "@/utils/vue-statistics";
Vue.use(vueStatistics, { router });
// 中央事件
Vue.prototype.$bus = new Vue();
......
......@@ -36,6 +36,13 @@
v-model="search"
placeholder="输入事项表单关键词或排队编号查询"
@keyup.native.enter="handleSearch"
v-onEvent="{
eventName: '输入',
eventCode: 'Put',
businessCode: 'HOMESEARCH',
businessName: '首页搜索',
routers: $route,
}"
>
<i
v-show="search"
......@@ -44,7 +51,17 @@
@click="handleClose"
></i>
</el-input>
<el-button class="search-btn" @click="handleSearch">
<el-button
class="search-btn"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'HOMESEARCH',
businessName: '首页搜索',
routers: $route,
}"
@click="handleSearch"
>
<span class="flex aic jcc">
<img class="mr10" src="../../assets/img/sousuo.png" /> 搜索
</span>
......@@ -55,7 +72,16 @@
<img src="../../assets/img/icon_hot.png" />
<span>热门词汇:</span>
</div>
<div @click="handleClick($event)">
<div
@click="handleClick($event)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'hot_words',
businessName: '热门词汇',
routers: $route,
}"
>
<vue-seamless-scroll
:data="homeInfo.hotWords"
:class-option="optionLeft"
......@@ -104,7 +130,18 @@
<img v-if="i < 3" :src="checkTopImg(i)" />
<span v-else>{{ i + 1 }}.</span>
</div>
<p class="flex1" v-ellipsis @click="checkMaterial(v)">
<p
class="flex1"
v-ellipsis
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'hot_materials',
businessName: '热门表单',
routers: $route,
}"
@click="checkMaterial(v)"
>
{{ v.materialName ? v.materialName : v.materiaFullName }}
</p>
</div>
......@@ -114,7 +151,16 @@
</div>
<div class="right flex flexc aic jcb">
<div class="right-top flex aic jcb">
<router-link to="/matterList">
<router-link
to="/matterList"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'speed_check',
businessName: '快速查看',
routers: $route,
}"
>
<div class="fill-btn flex aic jcc pointer main-ksck-img">
<span class="fill-btn-text1"></span>
<span class="fill-btn-text2"></span>
......@@ -145,7 +191,18 @@
<img v-if="i < 3" :src="checkTopImg(i)" />
<span v-else>{{ i + 1 }}.</span>
</div>
<p class="flex1" v-ellipsis @click="checkMatter(v)">
<p
class="flex1"
v-ellipsis
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'hot_matter',
businessName: '热门事项',
routers: $route,
}"
@click="checkMatter(v)"
>
{{ v.matterName ? v.matterName : v.matterFullName }}
</p>
</div>
......
......@@ -26,6 +26,13 @@
v-for="matter in matterList"
:key="matter.id"
@click="handleCheck(matter)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'check_matter',
businessName: '查看事项',
routers: $route,
}"
>
<div v-if="matter.isRecommend" class="hot-icon flex jcc aic">
<i class="iconfont icon-hot"></i>
......@@ -330,4 +337,4 @@ export default {
font-size: 28px;
}
}
</style>
\ No newline at end of file
</style>
......@@ -32,6 +32,13 @@
v-for="v in matterList"
:key="v.id"
@click="handleCheck(v)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'check_matter',
businessName: '查看事项',
routers: $route,
}"
>
<div v-if="v.isRecommend" class="hot-icon flex jcc aic">
<i class="iconfont icon-hot"></i>
......
......@@ -7,6 +7,13 @@
slot="right"
class="back-home flex aic jcc ml20"
@click="handleBackHome"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'back_homepage',
businessName: '返回首页',
routers: $route,
}"
>
<i class="iconfont icon-home mr10"></i>
<span>首页</span>
......@@ -41,10 +48,30 @@
</div>
<!-- 放大,缩小 -->
<div class="control-box">
<div class="control-btn" @click="handleEnlargement">
<div
class="control-btn"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'expansion',
businessName: '放大表单',
routers: $route,
}"
@click="handleEnlargement"
>
<i class="el-icon-zoom-in"></i>
</div>
<div class="control-btn" @click="handleShrink">
<div
class="control-btn"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'shrink',
businessName: '缩小表单',
routers: $route,
}"
@click="handleShrink"
>
<i class="el-icon-zoom-out"></i>
</div>
</div>
......@@ -52,7 +79,17 @@
<div class="sidebar-box" :class="{ show: !showSidebar }">
<!-- 侧边内容 -->
<div class="sidebar-main">
<div class="title flex jcc aic" @click="showSidebar = false">
<div
class="title flex jcc aic"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'hidden_sidebar',
businessName: '隐藏边栏',
routers: $route,
}"
@click="showSidebar = false"
>
<span class="mr30"> 样表展示 </span>
<span class="icon2">
<i class="el-icon-d-arrow-left"></i>
......@@ -75,6 +112,13 @@
v-for="(v, i) in materailsList"
:key="v.id"
@click="changeIndex(v, i)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'change_materials',
businessName: '切换表单',
routers: $route,
}"
>
{{ v.materialName ? v.materialName : v.materiaFullName }}
<div class="line"></div>
......@@ -87,6 +131,13 @@
class="sidebar-btn flex jcc aic"
v-show="!showSidebar"
@click="showSidebar = true"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'show_sidebar',
businessName: '显示边栏',
routers: $route,
}"
>
<div class="sidebar-btn-text flex flexc aic">
<span class="sidebar-btn-title"> 样表展示 </span>
......@@ -437,4 +488,4 @@ export default {
}
}
}
</style>
\ No newline at end of file
</style>
......@@ -7,6 +7,13 @@
v-for="(v, i) in deptList"
:key="v.deptCode"
@click="changeDept(v.deptCode, i)"
v-onEvent="{
eventName: '点击',
eventCode: 'Click',
businessCode: 'change_dept',
businessName: '切换部门',
routers: $route,
}"
>
<div class="dept-name">
{{ v.deptAbb ? v.deptAbb : v.name }}
......
......@@ -12,54 +12,48 @@ const routes = [
{
path: "/",
redirect: "/home",
},
// 首页
{
path: "/home",
component: () => import("@/pages/home/Home.vue"),
},
// 快速查看
{
path: "/matterList",
component: Layouts,
children: [
// 首页
{
path: "",
component: () => import("@/pages/showpage/MatterList.vue"),
path: "/home",
component: () => import("@/pages/home/Home.vue"),
meta: {
name: "首页",
},
},
],
},
// 快速搜索
{
path: "/searchpage",
component: Layouts,
children: [
// 快速查看
{
path: "",
component: () => import("@/pages/searchpage/SearchPage.vue"),
path: "/matterList",
component: () => import("@/pages/showpage/MatterList.vue"),
meta: {
name: "快速查看",
},
},
],
},
// 事项分类
{
path: "/matterify",
component: Layouts,
children: [
// 快速搜索
{
path: "",
component: () => import("@/pages/showpage/MatterIfy.vue"),
path: "/searchpage",
name: "快速搜索",
component: () => import("@/pages/searchpage/SearchPage.vue"),
meta: {
name: "快速搜索",
},
},
],
},
// 材料展示
{
path: "/showmaterials",
component: Layouts,
children: [
// 事项分类
// {
// path: "/matterify",
// component: () => import("@/pages/showpage/MatterIfy.vue"),
// meta:{
// name: "事项分类",
// }
// },
// 材料展示
{
path: "",
path: "/showmaterials",
component: () => import("@/pages/showpage/ShowMaterials.vue"),
meta: {
name: "材料展示",
},
},
],
},
......
import html2canvas from "html2canvas";
import { burySave, screenSave } from "@/api";
let routerArr = []; //每次流程路径
let lastRouterArr = []; //上一次流程路径
let putStartTime = null;
export default {
install(Vue, options) {
const { router } = options;
// 监听路由数据
router.beforeEach((to, from, next) => {
document.title = to.meta.name || "";
next();
// 统计路由次数
const { path, meta } = to;
if (path == "/") {
lastRouterArr = routerArr;
routerArr = [];
} else {
lastRouterArr = [];
}
// 保存每次流程
routerArr.push({
//页面路由信息
sourceCode: from.path || "/", //开始页面编码(路由)
sourceName: from.meta.name || "首页", //开始页面名称
targetCode: path, //目标页面编码(路由)
targetName: meta.name, //目标页面名称
});
// 后台桑基图请求数据
try {
let { productId } = JSON.parse(localStorage.getItem("deviceInfo"));
if (!productId) return; //未获取设备信息取消
burySave({
// "deviceNum":"",
// "productId": "",//产品id
// "productName": "",//产品名称
pageCode: path, //页面编码(页面路由)
pageName: meta.name, //页面名称
// "sceneDepth": 1,//场景维度
depthValue: lastRouterArr.length > 0 ? lastRouterArr.length : "", //本次访问深度 每次回到首页为每次流程
depthArr: lastRouterArr.length > 0 ? lastRouterArr : [],
// "eventInfo": {//页面事件信息
// "businessCode": '',//业务场景编码
// "businessName": '',//业务场景名称
// // "eventCode": "u9xo59",//事件编码
// // "eventName": "ku7l71",//事件名称
// // "takeTime": 12345,//事件耗时(单位毫秒)
// "coordinate": `${event.pageX},${event.pageY}`//事件坐标(x,y)
// },
routeInfo: {
//页面路由信息
sourceCode: from.path || "/", //开始页面编码(路由)
sourceName: from.meta.name || "首页", //开始页面名称
targetCode: path, //目标页面编码(路由)
targetName: meta.name, //目标页面名称
},
});
} catch (error) {}
});
// 封装事件埋点
Vue.directive("onEvent", {
bind: (el, bindings) => {
const { businessCode, businessName, eventCode, eventName, routers } =
bindings.value;
if (eventCode == "Click") {
el.addEventListener("click", (event) => {
const { meta, path } = routers;
try {
burySave({
// "deviceNum":"",//设备编码
// "productId": "",//产品id
// "productName": "",//产品名称
pageCode: path, //页面编码(页面路由)
pageName: meta.name, //页面名称
// "sceneDepth": 1,//场景维度
// "depthValue": 1,//本次访问深度
eventInfo: {
//页面事件信息
businessCode: businessCode, //业务场景编码
businessName: businessName, //业务场景名称
eventCode: eventCode, //事件编码
eventName: eventName, //事件名称
takeTime: 1000, //事件耗时(单位毫秒)
coordinate: `${event.pageX},${event.pageY}`, //事件坐标(x,y)生成热力图
},
// "routeInfo": {//页面路由信息
// "sourceCode": "6mq7ry",//开始页面编码(路由)
// "sourceName": "fxb3mk",//开始页面名称
// "targetCode": "fzrr3u",//目标页面编码(路由)
// "targetName": "fzrr3u"//目标页面名称
// }
});
} catch (error) {}
});
}
if (eventCode == "Put") {
el.addEventListener("blur", (event) => {
let endPutTime = new Date();
const { meta, path } = routers;
try {
burySave({
// "deviceNum":"",//设备编码
// "productId": "",//产品id
// "productName": "",//产品名称
pageCode: path, //页面编码(页面路由)
pageName: meta.name, //页面名称
// "sceneDepth": 1,//场景维度
// "depthValue": 1,//本次访问深度
eventInfo: {
//页面事件信息
businessCode: businessCode, //业务场景编码
businessName: businessName, //业务场景名称
eventCode: eventCode, //事件编码
eventName: eventName, //事件名称
takeTime: endPutTime - putStartTime, //事件耗时(单位毫秒)
},
// "routeInfo": {//页面路由信息
// "sourceCode": "6mq7ry",//开始页面编码(路由)
// "sourceName": "fxb3mk",//开始页面名称
// "targetCode": "fzrr3u",//目标页面编码(路由)
// "targetName": "fzrr3u"//目标页面名称
// }
});
} catch (error) {}
});
el.addEventListener("focus", (event) => {
putStartTime = new Date();
console.log(event, putStartTime, "@@@@@");
});
}
},
});
// 封装函数
Vue.prototype.$onEvent = function (obj) {
const {
businessCode,
businessName,
eventCode,
eventName,
routers,
takeTime,
} = obj;
const { meta, path } = routers;
try {
burySave({
// "deviceNum":"",//设备编码
// "productId": "",//产品id
// "productName": "",//产品名称
pageCode: path, //页面编码(页面路由)
pageName: meta.name, //页面名称
// "sceneDepth": 1,//场景维度
// "depthValue": 1,//本次访问深度
eventInfo: {
//页面事件信息
businessCode: businessCode, //业务场景编码
businessName: businessName, //业务场景名称
eventCode: eventCode, //事件编码
eventName: eventName, //事件名称
takeTime: takeTime || 1000, //事件耗时(单位毫秒)
// "coordinate": ``//事件坐标(x,y)生成热力图
},
// "routeInfo": {//页面路由信息
// "sourceCode": "6mq7ry",//开始页面编码(路由)
// "sourceName": "fxb3mk",//开始页面名称
// "targetCode": "fzrr3u",//目标页面编码(路由)
// "targetName": "fzrr3u"//目标页面名称
// }
});
} catch (error) {}
};
// 热力图背景图生成
const rightDom = document.createElement("div");
rightDom.style.width = "200px";
rightDom.style.height = "100px";
rightDom.style.zIndex = 999;
rightDom.style.position = "fixed";
rightDom.style.top = 0;
rightDom.style.right = "50%";
rightDom.style.marginRight = "-100px";
document.body.appendChild(rightDom);
rightDom.addEventListener("dblclick", function () {
const { meta, fullPath } = router.app.$route;
html2canvas(document.body, {
backgroundColor: null,
allowTaint: false,
useCORS: true,
}).then((canvas) => {
try {
screenSave({
// "deviceNum":"",//设备编码
// "productId": "",//产品id
// "productName": "",//产品名称
pageCode: fullPath, //页面编码(页面路由)
pageName: meta.name, //页面名称
screenUrl: canvas.toDataURL("image/png"),
});
} catch (error) {}
});
});
},
};
......@@ -2148,6 +2148,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
......@@ -3037,6 +3042,13 @@ css-declaration-sorter@^6.3.0:
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec"
integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==
css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
dependencies:
utrie "^1.0.2"
css-loader@^3.5.3:
version "3.6.0"
resolved "https://registry.npmmirror.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645"
......@@ -4800,6 +4812,14 @@ html-webpack-plugin@^5.1.0:
pretty-error "^4.0.0"
tapable "^2.0.0"
html2canvas@^1.4.1:
version "1.4.1"
resolved "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
dependencies:
css-line-break "^2.1.0"
text-segmentation "^1.0.3"
htmlparser2@^3.8.3:
version "3.10.1"
resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
......@@ -9104,6 +9124,13 @@ terser@^5.10.0, terser@^5.14.1:
commander "^2.20.0"
source-map-support "~0.5.20"
text-segmentation@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
dependencies:
utrie "^1.0.2"
text-table@^0.2.0, text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
......@@ -9504,6 +9531,13 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
utrie@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
dependencies:
base64-arraybuffer "^1.0.2"
uuid@^3.3.2, uuid@^3.3.3:
version "3.4.0"
resolved "https://registry.npmmirror.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment