@ -14,41 +14,28 @@
/ >
/ >
< section class = "price-workbench" >
< section class = "price-workbench" >
<!-- legacy malformed navigation retained only for source compatibility
< nav class = "step-indicator" aria -label = " 新 产 品 定 价 步 骤 " >
< nav class = "step-switcher" aria -label = " 新 产 品 定 价 步 骤 " >
< template v-for ="step in pricingSteps" :key="step.no" >
< button type = "button" : class = "{ active: currentStep === 1 }" @click ="switchStep(1)" >
< button
< span > 01 < / span > { { labels . pricingTitle } }
type = "button"
< / button >
class = "step-tab"
< i > → < / i >
: class = "{ active: currentStep === step.no, complete: currentStep > step.no }"
< button type = "button" : class = "{ active: currentStep === 2 }" @click ="switchStep(2)" >
: aria - current = "currentStep === step.no ? 'step' : undefined"
< span > 02 < / span > { { labels . competitorPricingTitle } }
@ click = "switchStep(step.no)"
< / button >
>
< i > → < / i >
< span class = "step-marker" > { { String ( step . no ) . padStart ( 2 , "0" ) } } < / span >
< button type = "button" : class = "{ active: currentStep === 4 }" @click ="switchStep(4)" >
< span class = "step-copy" >
< span > 04 < / span > { { labels . psmTitle } }
< strong > { { step . title } } < / strong >
< / button >
< span > { { currentStep === step . no ? "当前步骤" : "点击切换" } } < / span >
< i > → < / i >
< / span >
< button type = "button" : class = "{ active: currentStep === 5 }" @click ="switchStep(5)" >
< / button >
< span > 05 < / span > { { labels . finalPricingTitle } }
< span
< / button >
v - if = "step.no < pricingSteps.length"
< / nav >
class = "step-connector"
-- >
: class = "{ complete: currentStep > step.no }"
< nav class = "step-switcher" aria -label = " 新 产 品 定 价 步 骤 " >
aria - hidden = "true"
< button type = "button" : class = "{ active: currentStep === 1 }" @click ="switchStep(1)" >
/ >
< span > 01 < / span > { { labels . pricingTitle } }
< / template >
< / button >
< i > → < / i >
< button type = "button" : class = "{ active: currentStep === 2 }" @click ="switchStep(2)" >
< span > 02 < / span > { { labels . competitorPricingTitle } }
< / button >
< i > → < / i >
< button type = "button" : class = "{ active: currentStep === 3 }" @click ="switchStep(3)" >
< span > 03 < / span > { { labels . valueBasedPricingTitle } }
< / button >
< i > → < / i >
< button type = "button" : class = "{ active: currentStep === 4 }" @click ="switchStep(4)" >
< span > 04 < / span > { { labels . psmTitle } }
< / button >
< / nav >
< / nav >
< header class = "workbench-head" >
< header class = "workbench-head" >
@ -658,6 +645,13 @@ const finalPricingAnalysis = ref("");
const dynamicStepAnswers = ref ( { } ) ;
const dynamicStepAnswers = ref ( { } ) ;
const canRemovePsmRow = computed ( ( ) => psmRows . value . some ( ( row ) => ! row . isDefault ) ) ;
const canRemovePsmRow = computed ( ( ) => psmRows . value . some ( ( row ) => ! row . isDefault ) ) ;
const canRemovePerceivedValueItem = computed ( ( ) => perceivedValueItems . value . some ( ( row ) => ! row . isDefault ) ) ;
const canRemovePerceivedValueItem = computed ( ( ) => perceivedValueItems . value . some ( ( row ) => ! row . isDefault ) ) ;
const pricingSteps = computed ( ( ) => [
{ no : 1 , title : labels . pricingTitle } ,
{ no : 2 , title : labels . competitorPricingTitle } ,
{ no : 3 , title : labels . valueBasedPricingTitle } ,
{ no : 4 , title : labels . psmTitle } ,
{ no : 5 , title : labels . finalPricingTitle } ,
] ) ;
const currentStepTitle = computed ( ( ) => {
const currentStepTitle = computed ( ( ) => {
if ( currentStep . value === 1 ) return labels . pricingTitle ;
if ( currentStep . value === 1 ) return labels . pricingTitle ;
if ( currentStep . value === 2 ) return labels . competitorPricingTitle ;
if ( currentStep . value === 2 ) return labels . competitorPricingTitle ;
@ -1574,50 +1568,187 @@ onMounted(async () => {
box - shadow : 0 20 px 45 px rgba ( 0 , 0 , 0 , 0.2 ) ;
box - shadow : 0 20 px 45 px rgba ( 0 , 0 , 0 , 0.2 ) ;
}
}
. step - switche r {
. step - indicato r {
display : flex ;
display : flex ;
flex - wrap : wrap ;
align - items : center ;
align - items : center ;
gap : 10 px ;
width : calc ( 100 % - 48 px ) ;
padding : 18 px 26 px 0 ;
margin : 18 px 24 px 0 ;
padding : 12 px 14 px ;
overflow - x : auto ;
border : 1 px solid rgba ( 0 , 180 , 255 , 0.3 ) ;
border - radius : 14 px ;
background : linear - gradient ( 110 deg , rgba ( 4 , 39 , 58 , 0.9 ) , rgba ( 2 , 20 , 33 , 0.94 ) ) ;
box - shadow : inset 0 1 px 0 rgba ( 169 , 229 , 255 , 0.08 ) ;
}
button {
. step - tab {
display : inline - flex ;
display : flex ;
align - items : center ;
flex : 1 0 136 px ;
gap : 8 px ;
align - items : center ;
padding : 8 px 12 px ;
min - width : 0 ;
color : var ( -- muted ) ;
min - height : 52 px ;
cursor : pointer ;
padding : 7 px 9 px ;
border : 1 px solid var ( -- line ) ;
color : # 9 ab3d0 ;
border - radius : 999 px ;
cursor : pointer ;
background : transparent ;
border : 1 px solid rgba ( 68 , 141 , 177 , 0.35 ) ;
border - radius : 8 px ;
background : rgba ( 3 , 27 , 43 , 0.52 ) ;
transition : transform 0.2 s , color 0.2 s , background 0.2 s , border - color 0.2 s , box - shadow 0.2 s ;
& : hover ,
& : focus - visible {
color : # fff ;
border - color : rgba ( 89 , 223 , 255 , 0.82 ) ;
outline : none ;
background : rgba ( 8 , 92 , 131 , 0.52 ) ;
box - shadow : 0 8 px 18 px rgba ( 0 , 0 , 0 , 0.2 ) ;
transform : translateY ( - 2 px ) ;
}
& . active {
color : # fff ;
border - color : rgba ( 89 , 226 , 255 , 0.85 ) ;
background : linear - gradient ( 115 deg , rgba ( 4 , 109 , 155 , 0.78 ) , rgba ( 5 , 62 , 102 , 0.64 ) ) ;
box - shadow : 0 0 18 px rgba ( 24 , 183 , 235 , 0.22 ) , inset 0 1 px 0 rgba ( 176 , 246 , 255 , 0.2 ) ;
}
}
button . active {
& . complete {
color : # e9fbff ;
color : # dffbff ;
border - color : var ( -- line - strong ) ;
}
background : rgba ( 20 , 149 , 190 , 0.25 ) ;
}
. step - marker {
display : inline - flex ;
flex : 0 0 30 px ;
align - items : center ;
justify - content : center ;
width : 30 px ;
height : 30 px ;
color : # a6c4d9 ;
border : 1 px solid rgba ( 101 , 176 , 208 , 0.6 ) ;
border - radius : 50 % ;
background : rgba ( 3 , 25 , 40 , 0.8 ) ;
box - shadow : inset 0 0 12 px rgba ( 38 , 174 , 233 , 0.08 ) ;
font - size : 11 px ;
font - weight : 900 ;
letter - spacing : 0.04 em ;
}
. step - copy {
display : grid ;
min - width : 0 ;
gap : 3 px ;
margin - left : 8 px ;
strong {
display : - webkit - box ;
overflow : hidden ;
color : inherit ;
font - size : 13 px ;
line - height : 1.25 ;
- webkit - box - orient : vertical ;
- webkit - line - clamp : 2 ;
}
}
span {
span {
display : grid ;
color : # 66 b6d4 ;
width : 20 px ;
font - size : 10 px ;
height : 20 px ;
font - weight : 800 ;
place - items : center ;
letter - spacing : 0.06 em ;
color : # 7 de2ff ;
font - size : 11 px ;
font - weight : 700 ;
background : rgba ( 117 , 226 , 255 , 0.18 ) ;
border - radius : 50 % ;
}
}
}
i {
. step - tab . active . step - marker {
color : # 55 d3f8 ;
color : # fff ;
font - size : 18 px ;
border - color : # 72 e8ff ;
font - style : normal ;
background : linear - gradient ( 135 deg , # 08 b7e8 , # 1375 d0 ) ;
box - shadow : 0 0 0 5 px rgba ( 25 , 179 , 237 , 0.14 ) , 0 0 18 px rgba ( 46 , 208 , 255 , 0.58 ) ;
}
. step - tab . complete . step - marker {
color : # 062 b37 ;
border - color : rgba ( 84 , 230 , 221 , 0.85 ) ;
background : # 6 ef0e1 ;
box - shadow : 0 0 12 px rgba ( 79 , 231 , 218 , 0.35 ) ;
}
. step - connector {
position : relative ;
flex : 0 1 40 px ;
min - width : 18 px ;
height : 2 px ;
margin : 0 8 px ;
color : transparent ;
background : rgba ( 98 , 169 , 201 , 0.34 ) ;
& : : after {
position : absolute ;
top : 50 % ;
right : - 1 px ;
width : 6 px ;
height : 6 px ;
border - top : 1 px solid # 73 b1ce ;
border - right : 1 px solid # 73 b1ce ;
content : "" ;
transform : translateY ( - 50 % ) rotate ( 45 deg ) ;
}
& . complete {
background : linear - gradient ( 90 deg , # 6 ef0e1 , # 1 cb8e9 ) ;
box - shadow : 0 0 9 px rgba ( 53 , 218 , 235 , 0.46 ) ;
& : : after {
border - color : # 63 e6f1 ;
}
}
}
. primary - button ,
. secondary - button {
display : inline - flex ;
align - items : center ;
justify - content : center ;
min - height : 36 px ;
padding : 0 14 px ;
color : # e9fbff ;
cursor : pointer ;
border : 1 px solid rgba ( 99 , 217 , 255 , 0.55 ) ;
border - radius : 8 px ;
font : inherit ;
font - size : 14 px ;
font - weight : 700 ;
line - height : 1 ;
transition : transform 0.18 s , border - color 0.18 s , background 0.18 s , opacity 0.18 s ;
& : hover : not ( : disabled ) ,
& : focus - visible : not ( : disabled ) {
border - color : # 74 ebff ;
outline : none ;
transform : translateY ( - 1 px ) ;
}
& : disabled {
cursor : not - allowed ;
opacity : 0.45 ;
}
}
}
}
. primary - button {
background : linear - gradient ( 135 deg , # 08 a5d6 , # 147 bb9 ) ;
}
. secondary - button {
background : rgba ( 17 , 126 , 178 , 0.36 ) ;
}
. toolbar - actions {
display : flex ;
flex : none ;
flex - wrap : wrap ;
justify - content : flex - end ;
gap : 10 px ;
}
. workbench - head {
. workbench - head {
display : flex ;
display : flex ;
align - items : center ;
align - items : center ;
@ -1995,7 +2126,7 @@ onMounted(async () => {
}
}
}
}
@ media ( max - width : 1 20 0px ) {
@ media ( max - width : 1 44 0px ) {
grid - template - columns : 1 fr ;
grid - template - columns : 1 fr ;
}
}
@ -2024,152 +2155,193 @@ onMounted(async () => {
}
}
}
}
}
}
. psm - section {
/* PSM dark theme */
display : grid ;
. price - page {
gap : 20 px ;
. psm - section {
}
display : grid ;
gap : 20 px ;
padding : 0 26 px 26 px ;
}
. psm - toolbar ,
. psm - toolbar ,
. psm - chart - head {
. psm - chart - head {
display : flex ;
display : flex ;
align - items : flex - start ;
align - items : flex - start ;
justify - content : space - between ;
justify - content : space - between ;
gap : 16 px ;
gap : 16 px ;
}
}
. psm - toolbar p ,
. psm - toolbar p ,
. psm - chart - head p {
. psm - chart - head p ,
margin : 0 ;
. psm - guide - row p {
color : # 5 e6b7b ;
margin : 0 ;
line - height : 1.7 ;
color : var ( -- muted ) ;
}
line - height : 1.7 ;
}
. psm - subtitle {
. psm - subtitle {
margin - top : 8 px ! important ;
margin - top : 8 px ! important ;
color : # 25384 c ! important ;
color : # dffaff ! important ;
font - weight : 700 ;
font - weight : 700 ;
}
}
. toolbar - actions {
. table - scroll {
display : flex ;
overflow - x : auto ;
flex - wrap : wrap ;
border : 1 px solid var ( -- line ) ;
justify - content : flex - end ;
border - radius : 14 px ;
gap : 10 px ;
background : rgba ( 2 , 19 , 28 , 0.42 ) ;
}
}
. psm - table input ,
. psm - table {
. psm - point - grid input {
width : 100 % ;
box - sizing : border - box ;
min - width : 980 px ;
width : 100 % ;
border - collapse : collapse ;
padding : 8 px 10 px ;
color : # 243447 ;
background : # fff ;
border : 1 px solid # d8e1eb ;
border - radius : 6 px ;
}
. psm - table td {
th ,
min - width : 170 px ;
td {
}
padding : 12 px ;
border - bottom : 1 px solid var ( -- line ) ;
text - align : left ;
}
. psm - point - section ,
th {
. psm - chart - section {
color : # ddf8ff ;
padding : 20 px ;
font - size : 14 px ;
background : # fbfdff ;
background : rgba ( 25 , 122 , 157 , 0.46 ) ;
border : 1 px solid # dbe5ef ;
}
border - radius : 12 px ;
}
. psm - point - section h3 ,
td {
. psm - chart - section h3 {
min - width : 150 px ;
margin : 0 0 14 px ;
color : # dffaff ;
color : # 20344 b ;
}
font - size : 17 px ;
}
. psm - point - grid {
td : first - child {
display : grid ;
min - width : 120 px ;
grid - template - columns : repeat ( 3 , minmax ( 0 , 1 fr ) ) ;
font - weight : 700 ;
gap : 16 px ;
}
}
. psm - point - grid label {
tbody tr : last - child td {
display : grid ;
border - bottom : 0 ;
gap : 8 px ;
}
color : # 45566 a ;
}
font - weight : 600 ;
}
. file - picker {
. psm - table input ,
display : none ;
. psm - point - grid input {
}
box - sizing : border - box ;
width : 100 % ;
min - height : 38 px ;
padding : 8 px 10 px ;
color : # edfaff ;
background : rgba ( 2 , 19 , 28 , 0.7 ) ;
border : 1 px solid rgba ( 94 , 213 , 245 , 0.3 ) ;
border - radius : 7 px ;
outline : none ;
. psm - chart - preview {
& : focus {
display : flex ;
border - color : # 63 e5ff ;
align - items : center ;
box - shadow : 0 0 0 3 px rgba ( 50 , 204 , 241 , 0.12 ) ;
gap : 14 px ;
}
padding : 12 px ;
}
margin - top : 16 px ;
background : # fff ;
border : 1 px solid # dbe5ef ;
border - radius : 10 px ;
}
. psm - chart - image {
. psm - point - section ,
width : 148 px ;
. psm - chart - section {
height : 92 px ;
padding : 20 px ;
overflow : hidden ;
background : rgba ( 5 , 35 , 48 , 0.72 ) ;
border - radius : 8 px ;
border : 1 px solid var ( -- line ) ;
cursor : zoom - in ;
border - radius : 12 px ;
}
}
. psm - chart - preview p {
. psm - point - section h3 ,
margin : 0 0 7 px ;
. psm - chart - section h3 {
color : # 45566 a ;
margin : 0 0 14 px ;
word - break : break - all ;
color : # e5f9ff ;
}
font - size : 17 px ;
}
. psm - guide - row {
. psm - point - grid {
display : flex ;
display : grid ;
align - items : center ;
grid - template - columns : repeat ( 3 , minmax ( 0 , 1 fr ) ) ;
justify - content : space - between ;
gap : 16 px ;
gap : 16 px ;
}
padding - top : 16 px ;
margin - top : 16 px ;
border - top : 1 px solid # dbe5ef ;
}
. psm - guide - row p {
. psm - point - grid label {
margin : 0 ;
display : grid ;
color : # 5 e6b7b ;
gap : 8 px ;
line - height : 1.7 ;
color : # dffaff ;
}
font - weight : 600 ;
}
. text - button {
. file - picker {
padding : 0 ;
display : none ;
color : # 1687 c6 ;
}
cursor : pointer ;
background : transparent ;
border : 0 ;
}
@ media ( max - width : 768 px ) {
. psm - chart - preview {
. psm - toolbar ,
display : flex ;
. psm - chart - head {
align - items : center ;
flex - direction : column ;
gap : 14 px ;
padding : 12 px ;
margin - top : 16 px ;
background : rgba ( 2 , 19 , 28 , 0.7 ) ;
border : 1 px solid var ( -- line ) ;
border - radius : 10 px ;
}
}
. toolbar - actions {
. psm - chart - image {
justify - content : flex - start ;
width : 148 px ;
height : 92 px ;
overflow : hidden ;
border - radius : 8 px ;
cursor : zoom - in ;
}
}
. psm - point - grid {
. psm - chart - preview p {
grid - template - columns : 1 fr ;
margin : 0 0 7 px ;
color : # dffaff ;
word - break : break - all ;
}
}
. psm - guide - row {
. psm - guide - row {
align - items : flex - start ;
display : flex ;
flex - direction : column ;
align - items : center ;
justify - content : space - between ;
gap : 16 px ;
padding - top : 16 px ;
margin - top : 16 px ;
border - top : 1 px solid var ( -- line ) ;
}
. step - footer {
display : flex ;
justify - content : flex - end ;
}
. text - button {
padding : 0 ;
color : # 63 e5ff ;
cursor : pointer ;
background : transparent ;
border : 0 ;
}
@ media ( max - width : 768 px ) {
. psm - section {
padding : 0 14 px 18 px ;
}
. psm - toolbar ,
. psm - chart - head ,
. psm - guide - row {
align - items : stretch ;
flex - direction : column ;
}
. toolbar - actions {
justify - content : flex - start ;
}
. psm - point - grid {
grid - template - columns : 1 fr ;
}
}
}
}
}
< / style >
< / style >