Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
2045c603
提交
2045c603
authored
7月 12, 2024
作者:
lhh
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
营销报告
上级
45efe60f
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
495 行增加
和
19 行删除
+495
-19
Report.vue
src/modules/market/my/components/Report.vue
+71
-12
api.ts
src/modules/market/review/api.ts
+1
-1
Report.vue
src/modules/market/review/components/Report.vue
+348
-0
index.ts
src/modules/market/review/index.ts
+2
-1
Index.vue
src/modules/market/review/views/Index.vue
+20
-5
View.vue
src/modules/market/review/views/View.vue
+53
-0
没有找到文件。
src/modules/market/my/components/Report.vue
浏览文件 @
2045c603
...
...
@@ -150,7 +150,12 @@ defineExpose({ generateImage, generatePdf })
<li>
指导教师:
{{
teacherName
}}
</li>
</ul>
</div>
<section
id=
"step1"
class=
"section"
:class=
"
{ hide: step !== 1 }" v-element-visibility="state => onElementVisibility(state, 1)">
<section
id=
"step1"
class=
"section"
:class=
"
{ hide: step !== 1 }"
v-element-visibility="state => onElementVisibility(state, 1)"
>
<h2>
一、营销背景
</h2>
<h3>
(一)当前业务面临的问题及挑战
</h3>
<template
v-for=
"(item, index) in objectiveStore.problems"
:key=
"item.id"
>
...
...
@@ -161,7 +166,12 @@ defineExpose({ generateImage, generatePdf })
<p>
营销目标
{{
index
+
1
}}
:
{{
item
.
content
}}
</p>
</
template
>
</section>
<section
id=
"step2"
class=
"section"
:class=
"{ hide: step !== 2 }"
v-element-visibility=
"state => onElementVisibility(state, 2)"
>
<section
id=
"step2"
class=
"section"
:class=
"{ hide: step !== 2 }"
v-element-visibility=
"state => onElementVisibility(state, 2)"
>
<h2>
二、营销渠道
</h2>
<p>
本次营销选择的主要渠道为:
</p>
<
template
v-for=
"(item, index) in connectionStore.activeConnections"
:key=
"item.id"
>
...
...
@@ -170,7 +180,12 @@ defineExpose({ generateImage, generatePdf })
<p>
选择该渠道的原因为:
{{
item
.
content
}}
</p>
</
template
>
</section>
<section
id=
"step3"
class=
"section"
:class=
"{ hide: step !== 3 }"
v-element-visibility=
"state => onElementVisibility(state, 3)"
>
<section
id=
"step3"
class=
"section"
:class=
"{ hide: step !== 3 }"
v-element-visibility=
"state => onElementVisibility(state, 3)"
>
<h2>
三、用户分析
</h2>
<h3>
(一)用户性别分析
</h3>
<p>
{{ memberStore.member.sex }}
</p>
...
...
@@ -183,7 +198,12 @@ defineExpose({ generateImage, generatePdf })
<img
:src=
"memberStore.member.source_file"
/>
</div>
</section>
<section
id=
"step4"
class=
"section"
:class=
"{ hide: step !== 4 }"
v-element-visibility=
"state => onElementVisibility(state, 4)"
>
<section
id=
"step4"
class=
"section"
:class=
"{ hide: step !== 4 }"
v-element-visibility=
"state => onElementVisibility(state, 4)"
>
<h2>
四、用户标签体系设计
</h2>
<
template
v-for=
"(item, index) in labelStore.treeLabels"
:key=
"item.id"
>
<h3>
(
{{
numberToChinese
(
index
+
1
)
}}
)
{{
item
.
name
}}
</h3>
...
...
@@ -195,7 +215,12 @@ defineExpose({ generateImage, generatePdf })
</
template
>
</template>
</section>
<section
id=
"step5"
class=
"section"
:class=
"{ hide: step !== 5 }"
v-element-visibility=
"state => onElementVisibility(state, 5)"
>
<section
id=
"step5"
class=
"section"
:class=
"{ hide: step !== 5 }"
v-element-visibility=
"state => onElementVisibility(state, 5)"
>
<h2>
五、用户精准分群设计
</h2>
<h3>
(一)静态群组
</h3>
<p>
本项目设计如下静态群组:
</p>
...
...
@@ -214,11 +239,22 @@ defineExpose({ generateImage, generatePdf })
<p>
设计该群组的原因是:
{{
item
.
reason
}}
</p>
</
template
>
</section>
<section
id=
"step6"
class=
"section"
:class=
"{ hide: step !== 6 }"
v-element-visibility=
"state => onElementVisibility(state, 6)"
>
<section
id=
"step6"
class=
"section"
:class=
"{ hide: step !== 6 }"
v-element-visibility=
"state => onElementVisibility(state, 6)"
>
<h2>
六、自动化营销旅程设计
</h2>
<h3>
(一)一级流程
</h3>
<p>
本项目设计一级流程图如下。
</p>
<Flow
:nodes=
"tripStore.nodes"
:edges=
"tripStore.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<Flow
:nodes=
"tripStore.nodes"
:edges=
"tripStore.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<p>
相关节点设计说明如下:
</p>
<
template
v-for=
"(item, index) in tripStore.nodes"
:key=
"item.id"
>
<p>
{{
index
+
1
}}
、
{{
item
.
data
.
label
||
item
.
label
}}
节点
</p>
...
...
@@ -229,13 +265,22 @@ defineExpose({ generateImage, generatePdf })
<
template
v-else-if=
"item.type === 'end'"
>
结束节点
</
template
>
<
template
v-else
>
业务节点
</
template
>
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
</template>
<h3>
(二)二级流程
</h3>
<p>
本项目如下一级流程节点设计了二级流程。
</p>
<
template
v-for=
"(item, index) in tripStore.node1List"
:key=
"item.id"
>
<p>
{{
index
+
1
}}
、
{{
item
.
data
.
label
||
item
.
label
}}
节点。该节点设计的二级流程图如下:
</p>
<Flow
:process=
"2"
:nodes=
"item.data.nodes"
:edges=
"item.data.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<Flow
:process=
"2"
:nodes=
"item.data.nodes"
:edges=
"item.data.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<p>
该二级流程图节点说明如下:
</p>
<template
v-for=
"(item, index) in item.data.nodes"
:key=
"item.id"
>
<p>
(
{{
index
+
1
}}
)
{{
item
.
data
.
label
||
item
.
label
}}
节点
</p>
...
...
@@ -246,19 +291,33 @@ defineExpose({ generateImage, generatePdf })
<
template
v-else-if=
"item.type === 'end'"
>
结束节点
</
template
>
<
template
v-else
>
业务节点
</
template
>
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
<p
v-if=
"item.type === 'custom'"
>
是否用到营销物料:{{ item.use_material }}
</p>
<p
v-if=
"item.type === 'custom'"
>
营销物料类型:{{ item.material_type }}
</p>
</template>
</template>
</section>
<section
id=
"step7"
class=
"section"
:class=
"{ hide: step !== 7 }"
v-element-visibility=
"state => onElementVisibility(state, 7)"
>
<section
id=
"step7"
class=
"section"
:class=
"{ hide: step !== 7 }"
v-element-visibility=
"state => onElementVisibility(state, 7)"
>
<h2>
七、营销物料设计
</h2>
<p>
本项目设计如下营销物料。
</p>
<AppList
v-bind=
"listOptions"
></AppList>
</section>
<ul
class=
"market-report-step"
>
<li
v-for=
"(item, index) in steps"
:key=
"index"
:class=
"{ 'is-active': index + 1 === step }"
@
click=
"handleClick(item)"
>
{{ item.name }}
</li>
<li
v-for=
"(item, index) in steps"
:key=
"index"
:class=
"{ 'is-active': index + 1 === step }"
@
click=
"handleClick(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</div>
...
...
src/modules/market/review/api.ts
浏览文件 @
2045c603
...
...
@@ -11,7 +11,7 @@ export function getSearchCriteria() {
}
// 获取列表
export
function
getRecordList
(
params
?:
{
name
:
string
,
sno_number
:
string
})
{
export
function
getRecordList
(
params
?:
{
name
?:
string
,
sno_number
?:
any
})
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/marketing-planning/record-list'
,
{
params
})
}
...
...
src/modules/market/review/components/Report.vue
0 → 100644
浏览文件 @
2045c603
<
script
setup
>
import
{
toBlob
,
toCanvas
}
from
'html-to-image'
import
{
jsPDF
}
from
'jspdf'
// import { saveAs } from 'file-saver'
import
{
upload
}
from
'@/utils/upload'
import
Flow
from
'./flow/Flow.vue'
import
{
useMarketStore
}
from
'../stores/market'
import
{
vElementVisibility
}
from
'@vueuse/components'
import
scrollIntoView
from
'scroll-into-view-if-needed'
const
props
=
defineProps
({
step
:
{
type
:
Number
,
default
:
1
},
experimentName
:
{
type
:
String
},
studentName
:
{
type
:
String
},
teacherName
:
{
type
:
String
},
detail
:
{
type
:
Object
}
})
const
marketStore
=
useMarketStore
()
const
{
objectiveStore
,
connectionStore
,
memberStore
,
labelStore
,
groupStore
,
tripStore
,
materialStore
}
=
marketStore
watch
(
()
=>
props
.
detail
,
()
=>
{
if
(
props
.
detail
)
marketStore
.
setData
(
props
.
detail
)
},
{
immediate
:
true
}
)
const
step
=
ref
(
props
.
step
)
const
steps
=
[
{
name
:
'营销背景'
,
step
:
1
},
{
name
:
'营销渠道'
,
step
:
2
},
{
name
:
'用户分析'
,
step
:
3
},
{
name
:
'用户标签'
,
step
:
4
},
{
name
:
'用户分群'
,
step
:
5
},
{
name
:
'自动化旅程'
,
step
:
6
},
{
name
:
'营销物料'
,
step
:
7
}
]
const
listOptions
=
computed
(()
=>
{
return
{
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'一级流程节点'
,
prop
:
'node1'
},
{
label
:
'二级流程节点'
,
prop
:
'node2'
},
{
label
:
'营销物料类型'
,
prop
:
'type'
},
{
label
:
'物料风格'
,
prop
:
'style'
},
{
label
:
'物料侧重点'
,
prop
:
'desc'
},
{
label
:
'物料更新频率'
,
prop
:
'update_rule'
}
],
data
:
materialStore
.
materials
}
})
const
reportRef
=
ref
()
// 生成图片
async
function
generateImage
()
{
const
blob
=
await
toBlob
(
reportRef
.
value
,
{
width
:
1000
})
const
url
=
await
upload
(
blob
)
return
url
}
// 生成PDF
async
function
generatePdf
()
{
// const blob = await toBlob(reportRef.value, { width: 1000 })
// saveAs(blob, '营销策划报告.png')
const
canvas
=
await
toCanvas
(
reportRef
.
value
)
const
imgData
=
canvas
.
toDataURL
(
'image/png'
)
const
pdf
=
new
jsPDF
(
'p'
,
'px'
,
'a4'
)
const
pdfWidth
=
pdf
.
internal
.
pageSize
.
getWidth
()
const
pdfHeight
=
pdf
.
internal
.
pageSize
.
getHeight
()
const
canvasWidth
=
canvas
.
width
const
canvasHeight
=
canvas
.
height
const
imgWidth
=
pdfWidth
const
imgHeight
=
(
pdfWidth
/
canvasWidth
)
*
canvasHeight
const
totalPages
=
Math
.
ceil
(
imgHeight
/
pdfHeight
)
for
(
let
i
=
0
;
i
<
totalPages
;
i
++
)
{
if
(
i
>
0
)
{
pdf
.
addPage
()
}
const
position
=
-
i
*
pdfHeight
pdf
.
addImage
(
imgData
,
'PNG'
,
0
,
position
,
imgWidth
,
imgHeight
)
}
pdf
.
save
(
'营销策划报告.pdf'
)
}
function
onElementVisibility
(
state
,
stepIndex
)
{
if
(
state
)
step
.
value
=
stepIndex
}
function
handleClick
(
item
)
{
const
node
=
document
.
getElementById
(
`step
${
item
.
step
}
`
)
scrollIntoView
(
node
,
{
behavior
:
'smooth'
,
block
:
'start'
})
step
.
value
=
item
.
step
}
function
numberToChinese
(
num
)
{
// 简单的中文数字映射
const
chineseNums
=
[
'零'
,
'一'
,
'二'
,
'三'
,
'四'
,
'五'
,
'六'
,
'七'
,
'八'
,
'九'
]
const
chineseUnits
=
[
''
,
'十'
,
'百'
,
'千'
,
'万'
,
'十'
,
'百'
,
'千'
,
'亿'
]
if
(
num
===
0
)
return
chineseNums
[
0
]
let
str
=
''
let
unitIndex
=
0
while
(
num
>
0
)
{
let
digit
=
num
%
10
// 取出个位数字
if
(
digit
!==
0
)
{
// 如果不为零,则添加中文数字和单位
str
=
chineseNums
[
digit
]
+
chineseUnits
[
unitIndex
]
+
str
}
else
if
(
str
.
length
>
0
&&
str
[
0
]
!==
chineseNums
[
0
])
{
// 如果当前数字为零且上一个数字不为零,添加零
str
=
chineseNums
[
0
]
+
str
}
num
=
Math
.
floor
(
num
/
10
)
unitIndex
++
// 当到万位时,重置单位索引(因为接下来是亿)
if
(
unitIndex
===
5
)
{
unitIndex
=
1
}
}
// 去除开头的零(如果有的话)
if
(
str
.
startsWith
(
chineseNums
[
0
]))
{
str
=
str
.
slice
(
1
)
}
return
str
}
defineExpose
({
generateImage
,
generatePdf
})
</
script
>
<
template
>
<div
class=
"market-report-wrapper"
>
<div
class=
"market-report"
ref=
"reportRef"
>
<div
class=
"market-report-header"
>
<h1>
“
{{
experimentName
}}
”实验
<br
/>
营销策划报告
</h1>
<ul>
<li>
策划人:
{{
studentName
}}
</li>
<li>
指导教师:
{{
teacherName
}}
</li>
</ul>
</div>
<section
id=
"step1"
class=
"section"
:class=
"
{ hide: step !== 1 }" v-element-visibility="state => onElementVisibility(state, 1)">
<h2>
一、营销背景
</h2>
<h3>
(一)当前业务面临的问题及挑战
</h3>
<template
v-for=
"(item, index) in objectiveStore.problems"
:key=
"item.id"
>
<p>
问题与挑战
{{
index
+
1
}}
:
{{
item
.
content
}}
</p>
</
template
>
<h3>
(二)业务部门营销目标
</h3>
<
template
v-for=
"(item, index) in objectiveStore.objectives"
:key=
"item.id"
>
<p>
营销目标
{{
index
+
1
}}
:
{{
item
.
content
}}
</p>
</
template
>
</section>
<section
id=
"step2"
class=
"section"
:class=
"{ hide: step !== 2 }"
v-element-visibility=
"state => onElementVisibility(state, 2)"
>
<h2>
二、营销渠道
</h2>
<p>
本次营销选择的主要渠道为:
</p>
<
template
v-for=
"(item, index) in connectionStore.activeConnections"
:key=
"item.id"
>
<h3>
(
{{
numberToChinese
(
index
+
1
)
}}
)
{{
item
.
type_name
}}
</h3>
<p>
当前渠道拥有的用户数为:
{{
item
.
member_count
}}
人,拥有的用户事件数量为:
{{
item
.
event_count
}}
件
</p>
<p>
选择该渠道的原因为:
{{
item
.
content
}}
</p>
</
template
>
</section>
<section
id=
"step3"
class=
"section"
:class=
"{ hide: step !== 3 }"
v-element-visibility=
"state => onElementVisibility(state, 3)"
>
<h2>
三、用户分析
</h2>
<h3>
(一)用户性别分析
</h3>
<p>
{{ memberStore.member.sex }}
</p>
<div
style=
"text-align: center"
>
<img
:src=
"memberStore.member.sex_file"
/>
</div>
<h3>
(二)用户数据来源分析
</h3>
<p>
{{ memberStore.member.source }}
</p>
<div
style=
"text-align: center"
>
<img
:src=
"memberStore.member.source_file"
/>
</div>
</section>
<section
id=
"step4"
class=
"section"
:class=
"{ hide: step !== 4 }"
v-element-visibility=
"state => onElementVisibility(state, 4)"
>
<h2>
四、用户标签体系设计
</h2>
<
template
v-for=
"(item, index) in labelStore.treeLabels"
:key=
"item.id"
>
<h3>
(
{{
numberToChinese
(
index
+
1
)
}}
)
{{
item
.
name
}}
</h3>
<p>
本项目设计如下
{{
item
.
name
}}
:
</p>
<template
v-for=
"(label, index) in item.children"
:key=
"label.id"
>
<p>
{{
index
+
1
}}
、
{{
label
.
name
}}
</p>
<p>
该标签关联“
{{
label
.
data_type
}}
”,关联字段为:
{{
label
.
attr_name
||
label
.
event_name
}}
。
</p>
<p>
该标签的设置规则为:
{{
label
.
desc
}}
。
</p>
</
template
>
</template>
</section>
<section
id=
"step5"
class=
"section"
:class=
"{ hide: step !== 5 }"
v-element-visibility=
"state => onElementVisibility(state, 5)"
>
<h2>
五、用户精准分群设计
</h2>
<h3>
(一)静态群组
</h3>
<p>
本项目设计如下静态群组:
</p>
<
template
v-for=
"(item, index) in groupStore.staticGroups"
:key=
"item.id"
>
<h3>
{{
index
+
1
}}
、
{{
item
.
name
}}
</h3>
<p>
该群组的加入规则为:
{{
item
.
join_rule
}}
</p>
<p>
该群组的移除规则为:
{{
item
.
remove_rule
}}
</p>
<p>
设计该群组的原因是:
{{
item
.
reason
}}
</p>
</
template
>
<h3>
(二)动态群组
</h3>
<p>
本项目设计如下动态群组:
</p>
<
template
v-for=
"(item, index) in groupStore.dynamicGroups"
:key=
"item.id"
>
<h3>
{{
index
+
1
}}
、
{{
item
.
name
}}
</h3>
<p>
该群组的加入规则为:
{{
item
.
join_rule
}}
</p>
<p>
该群组的移除规则为:
{{
item
.
remove_rule
}}
</p>
<p>
设计该群组的原因是:
{{
item
.
reason
}}
</p>
</
template
>
</section>
<section
id=
"step6"
class=
"section"
:class=
"{ hide: step !== 6 }"
v-element-visibility=
"state => onElementVisibility(state, 6)"
>
<h2>
六、自动化营销旅程设计
</h2>
<h3>
(一)一级流程
</h3>
<p>
本项目设计一级流程图如下。
</p>
<Flow
:nodes=
"tripStore.nodes"
:edges=
"tripStore.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<p>
相关节点设计说明如下:
</p>
<
template
v-for=
"(item, index) in tripStore.nodes"
:key=
"item.id"
>
<p>
{{
index
+
1
}}
、
{{
item
.
data
.
label
||
item
.
label
}}
节点
</p>
<p
v-if=
"item.data.desc"
>
节点说明:
{{
item
.
data
.
desc
}}
</p>
<p>
节点类型:
<template
v-if=
"item.type === 'start'"
>
开始节点
</
template
>
<
template
v-else-if=
"item.type === 'end'"
>
结束节点
</
template
>
<
template
v-else
>
业务节点
</
template
>
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
</template>
<h3>
(二)二级流程
</h3>
<p>
本项目如下一级流程节点设计了二级流程。
</p>
<
template
v-for=
"(item, index) in tripStore.node1List"
:key=
"item.id"
>
<p>
{{
index
+
1
}}
、
{{
item
.
data
.
label
||
item
.
label
}}
节点。该节点设计的二级流程图如下:
</p>
<Flow
:process=
"2"
:nodes=
"item.data.nodes"
:edges=
"item.data.edges"
:nodes-draggable=
"false"
:nodes-connectable=
"false"
style=
"height: 200px"
></Flow>
<p>
该二级流程图节点说明如下:
</p>
<template
v-for=
"(item, index) in item.data.nodes"
:key=
"item.id"
>
<p>
(
{{
index
+
1
}}
)
{{
item
.
data
.
label
||
item
.
label
}}
节点
</p>
<p
v-if=
"item.data.desc"
>
节点说明:
{{
item
.
data
.
desc
}}
</p>
<p>
节点类型:
<template
v-if=
"item.type === 'start'"
>
开始节点
</
template
>
<
template
v-else-if=
"item.type === 'end'"
>
结束节点
</
template
>
<
template
v-else
>
业务节点
</
template
>
</p>
<p
v-if=
"item.type === 'start'"
>
节点配置:触发时机为“{{ item.data.time }}”,触发条件为“{{ item.data.condition }}”。
</p>
<p
v-if=
"item.type === 'custom'"
>
是否用到营销物料:{{ item.use_material }}
</p>
<p
v-if=
"item.type === 'custom'"
>
营销物料类型:{{ item.material_type }}
</p>
</template>
</template>
</section>
<section
id=
"step7"
class=
"section"
:class=
"{ hide: step !== 7 }"
v-element-visibility=
"state => onElementVisibility(state, 7)"
>
<h2>
七、营销物料设计
</h2>
<p>
本项目设计如下营销物料。
</p>
<AppList
v-bind=
"listOptions"
></AppList>
</section>
<ul
class=
"market-report-step"
>
<li
v-for=
"(item, index) in steps"
:key=
"index"
:class=
"{ 'is-active': index + 1 === step }"
@
click=
"handleClick(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</div>
</template>
<
style
lang=
"scss"
scoped
>
.market-report-wrapper
{
max-width
:
1000px
;
margin
:
0
auto
;
}
.market-report
{
padding
:
0
40px
;
background-color
:
#fff
;
position
:
relative
;
.market-report-header
{
padding
:
40px
0
;
margin-bottom
:
40px
;
border-bottom
:
1px
solid
#eee
;
text-align
:
center
;
h1
{
color
:
rgba
(
16
,
16
,
16
,
1
);
font-size
:
18px
;
font-weight
:
700
;
line-height
:
25px
;
}
ul
{
margin-top
:
40px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-evenly
;
}
li
{
color
:
rgba
(
118
,
117
,
117
,
1
);
font-weight
:
400
;
letter-spacing
:
1px
;
}
}
section
{
margin-bottom
:
20px
;
// &.hide {
// display: none;
// }
}
h2
{
padding
:
10px
0
;
font-size
:
20px
;
}
h3
{
margin-top
:
10px
;
padding
:
10px
0
;
font-size
:
16px
;
}
p
{
margin-left
:
20px
;
font-size
:
14px
;
line-height
:
24px
;
strong
{
font-weight
:
bold
;
}
}
img
{
max-width
:
100%
;
}
.market-report-step
{
position
:
fixed
;
right
:
50px
;
top
:
50%
;
transform
:
translateY
(
-50%
);
li
{
margin-top
:
10px
;
width
:
80px
;
height
:
58px
;
line-height
:
58px
;
text-align
:
center
;
border-radius
:
10px
;
border
:
1px
solid
rgb
(
187
,
187
,
187
);
box-sizing
:
border-box
;
cursor
:
pointer
;
background-color
:
#fff
;
&
.is-active
{
background-color
:
rgb
(
189
,
248
,
180
);
border
:
none
;
}
}
}
}
</
style
>
src/modules/market/review/index.ts
浏览文件 @
2045c603
...
...
@@ -7,7 +7,8 @@ const routes: RouteRecordRaw[] = [
component
:
Layout
,
children
:
[
{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
},
{
path
:
'score'
,
component
:
()
=>
import
(
'./views/Score.vue'
)
}
{
path
:
'score'
,
component
:
()
=>
import
(
'./views/Score.vue'
)
},
{
path
:
'view'
,
component
:
()
=>
import
(
'./views/View.vue'
)
}
]
}
]
...
...
src/modules/market/review/views/Index.vue
浏览文件 @
2045c603
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentInfo
}
from
'../types'
import
{
getSearchCriteria
,
getRecordList
}
from
'../api'
import
Report
from
'@/modules/market/my/components/Report.vue'
const
route
=
useRoute
()
...
...
@@ -79,9 +80,7 @@ const listOptions = computed(() => {
function
isComplete
(
is
:
Boolean
)
{
let
n
=
''
is
?
(
n
=
'<div style="color: #009b3b; font-size:20px;">✓</div>'
)
:
(
n
=
'<div style="font-size:20px;">-</div>'
)
is
?
(
n
=
'<div style="color: #009b3b; font-size:20px;">✓</div>'
)
:
(
n
=
'<div style="font-size:20px;">-</div>'
)
return
n
}
</
script
>
...
...
@@ -95,10 +94,27 @@ function isComplete(is: Boolean) {
<el-form-item
label=
"实验学时"
>
{{
experimentInfo
?.
length
}}
</el-form-item>
</el-form>
<el-divider
/>
<!--
<Report
:experimentName=
"11"
:teacherName=
"11"
:studentName=
"11"
ref=
"reportRef"
/>
-->
<h2
class=
"h2-title"
>
营销策划
</h2>
<AppList
v-bind=
"listOptions"
>
<template
#
table-x=
"
{ row }">
<el-button
text
type=
"primary"
>
查看营销策划报告
</el-button>
<!--
<el-button
text
type=
"primary"
>
查看营销策划报告
</el-button>
-->
<router-link
target=
"_blank"
:to=
"
{
path: '/market/review/view',
query: {
id: row.id,
snoNumber: row.sno_number,
experiment_id: route.query.experiment_id
}
}"
>
<el-button
text
type=
"primary"
>
查看营销策划报告
</el-button></router-link
>
<router-link
target=
"_blank"
:to=
"
{
...
...
@@ -113,7 +129,6 @@ function isComplete(is: Boolean) {
}"
>
<el-button
text
type=
"primary"
>
评分
</el-button></router-link
>
<!--
<el-button
text
type=
"primary"
@
click=
""
>
评分
</el-button>
-->
</
template
>
</AppList>
</AppCard>
...
...
src/modules/market/review/views/View.vue
0 → 100644
浏览文件 @
2045c603
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentInfo
}
from
'../types'
import
{
getSearchCriteria
,
getRecordList
}
from
'../api'
import
Report
from
'@/modules/market/my/components/Report.vue'
const
route
=
useRoute
()
let
experimentInfo
=
$ref
<
ExperimentInfo
>
()
getSearchCriteria
().
then
((
res
:
{
data
:
{
experiment
:
ExperimentInfo
}
})
=>
{
if
(
res
?.
data
)
{
const
data
=
res
.
data
.
experiment
data
.
teacher_name
=
data
.
teacher
.
reduce
((
a
:
any
,
b
:
any
)
=>
a
.
push
(
b
.
name
)
&&
a
,
[]).
join
(
','
)
experimentInfo
=
data
}
})
let
detail
=
ref
<
any
>
({})
getRecordList
({
sno_number
:
route
.
query
.
snoNumber
}).
then
(
res
=>
{
if
(
res
.
data
)
{
detail
.
value
=
res
.
data
.
list
[
0
]
}
})
const
data
=
$computed
(()
=>
{
return
detail
.
value
?.
details
?
JSON
.
parse
(
detail
.
value
.
details
)
:
{}
})
</
script
>
<
template
>
<AppCard>
<el-form
label-suffix=
":"
inline
class=
"info"
>
<el-form-item
label=
"实验名称"
>
{{
experimentInfo
?.
name
}}
</el-form-item>
<el-form-item
label=
"课程名称"
>
{{
experimentInfo
?.
course_name
}}
</el-form-item>
<el-form-item
label=
"指导教师"
>
{{
experimentInfo
?.
teacher_name
}}
</el-form-item>
<el-form-item
label=
"实验学时"
>
{{
experimentInfo
?.
length
}}
</el-form-item>
</el-form>
<el-divider
/>
<Report
:detail=
"data"
:experimentName=
"experimentInfo?.name"
:teacherName=
"experimentInfo?.teacher_name"
:studentName=
"detail?.name"
ref=
"reportRef"
/>
</AppCard>
</
template
>
<
style
lang=
"scss"
scoped
>
.info
{
display
:
flex
;
justify-content
:
space-between
;
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论