@yaoxiu/marketing-dsl 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4762,20 +4762,22 @@ var achieveCell3 = (verb, value, unit, label) => ({
4762
4762
  type: "flex",
4763
4763
  style: {
4764
4764
  direction: "column",
4765
+ // grid 不在白名单,用 flex wrap + 半宽复刻 grid-template-columns: 1fr 1fr(gap 9)
4765
4766
  width: "calc(50% - 5px)",
4766
4767
  background: "rgba(255,255,255,0.16)",
4767
4768
  borderWidth: 1,
4768
4769
  borderStyle: "solid",
4769
4770
  borderColor: "rgba(255,255,255,0.2)",
4770
4771
  radius: 10,
4771
- padding: "10px 13px",
4772
- gap: 3
4772
+ // .period-price-modal .ac 把基础规则的 9px 11px 覆盖成 10px 13px
4773
+ padding: "10px 13px"
4773
4774
  },
4774
4775
  children: [
4775
4776
  {
4776
- // lineHeight 必须显式给,否则 20px 数字的默认行高会把格子撑高
4777
+ // .ac .n:line-height 1.1 × 20px = 22px,显式给死,
4778
+ // 否则 20px 数字的默认行高(≈1.5)会把格子撑高 8px 左右
4777
4779
  type: "flex",
4778
- style: { align: "baseline", gap: 3, height: 22 },
4780
+ style: { align: "baseline", height: 22, whiteSpace: "nowrap" },
4779
4781
  children: [
4780
4782
  {
4781
4783
  type: "text",
@@ -4784,7 +4786,10 @@ var achieveCell3 = (verb, value, unit, label) => ({
4784
4786
  fontSize: 11.5,
4785
4787
  fontWeight: "600",
4786
4788
  lineHeight: 1.1,
4787
- color: "rgba(255,255,255,0.92)"
4789
+ letterSpacing: 0.2,
4790
+ marginRight: 3,
4791
+ // demo 是 opacity .7 叠在 .m-top 的白字上,等价于这个色值
4792
+ color: "rgba(255,255,255,0.7)"
4788
4793
  }
4789
4794
  },
4790
4795
  {
@@ -4795,14 +4800,25 @@ var achieveCell3 = (verb, value, unit, label) => ({
4795
4800
  {
4796
4801
  type: "text",
4797
4802
  content: ` ${unit}`,
4798
- style: { fontSize: 12, lineHeight: 1.1, color: "rgba(255,255,255,0.92)" }
4803
+ style: {
4804
+ fontSize: 12,
4805
+ fontWeight: "600",
4806
+ lineHeight: 1.1,
4807
+ // demo 是 opacity .85
4808
+ color: "rgba(255,255,255,0.85)"
4809
+ }
4799
4810
  }
4800
4811
  ]
4801
4812
  },
4802
4813
  {
4803
4814
  type: "text",
4804
4815
  content: label,
4805
- style: { fontSize: 11.5, lineHeight: 1.35, color: "rgba(255,255,255,0.72)" }
4816
+ style: {
4817
+ fontSize: 11,
4818
+ lineHeight: 1.4,
4819
+ marginTop: 2,
4820
+ color: "rgba(255,255,255,0.85)"
4821
+ }
4806
4822
  }
4807
4823
  ]
4808
4824
  });
@@ -4813,7 +4829,15 @@ var loseRow3 = {
4813
4829
  {
4814
4830
  type: "text",
4815
4831
  content: "",
4816
- style: { width: 6, height: 6, radius: "50%", background: "#f53f3f", marginTop: 7 }
4832
+ style: {
4833
+ width: 6,
4834
+ height: 6,
4835
+ radius: "50%",
4836
+ background: "#f53f3f",
4837
+ marginTop: 7,
4838
+ // demo 的 flex: none —— 文案换行时圆点不许被压扁
4839
+ flexShrink: "0"
4840
+ }
4817
4841
  },
4818
4842
  {
4819
4843
  type: "flex",
@@ -4829,20 +4853,6 @@ var loseRow3 = {
4829
4853
  color: "#1f2533"
4830
4854
  }
4831
4855
  },
4832
- {
4833
- type: "text",
4834
- content: "{{ item.tag }}",
4835
- visibleWhen: "item.tag != ''",
4836
- style: {
4837
- background: "{{ item.sev == 'lose' ? '#ffd5cf' : 'rgba(255,255,255,0.78)' }}",
4838
- color: "{{ item.sev == 'lose' ? '#cf1322' : '#8a7f78' }}",
4839
- fontSize: 10,
4840
- fontWeight: "800",
4841
- radius: 4,
4842
- padding: "1px 6px",
4843
- whiteSpace: "nowrap"
4844
- }
4845
- },
4846
4856
  {
4847
4857
  type: "text",
4848
4858
  content: "\u2014 {{ item.t }}",
@@ -4856,14 +4866,18 @@ var tierCard3 = {
4856
4866
  type: "box",
4857
4867
  style: {
4858
4868
  flex: "1",
4859
- height: 121,
4869
+ height: 119,
4860
4870
  radius: 12,
4861
4871
  background: "{{ item.key == current.key ? '#fffaf0' : '#ffffff' }}",
4862
4872
  borderStyle: "solid",
4863
4873
  borderWidth: "{{ item.key == current.key ? '2px' : '1px' }}",
4864
4874
  borderColor: "{{ item.key == current.key ? '#f0a000' : '#e5e8ed' }}",
4865
- cursor: "pointer"
4875
+ shadow: "{{ item.key == current.key ? '0 7px 18px rgba(240,160,0,0.1)' : 'none' }}",
4876
+ cursor: "pointer",
4877
+ transition: "border-color 0.15s, background 0.15s, box-shadow 0.15s"
4866
4878
  },
4879
+ // .tcol:hover { border-color: var(--gold) }
4880
+ hoverStyle: { borderColor: "#faad14" },
4867
4881
  action: {
4868
4882
  type: "sequence",
4869
4883
  actions: [
@@ -4877,6 +4891,8 @@ var tierCard3 = {
4877
4891
  },
4878
4892
  children: [
4879
4893
  {
4894
+ // .thot:top -9、字号 11、padding 2px 8px、radius 6。
4895
+ // 宽 38 = 2 字 × 11px + 左右 8px;居中靠 left: calc(50% - 19px)
4880
4896
  type: "text",
4881
4897
  rect: ["calc(50% - 19px)", -9, 38, 22],
4882
4898
  content: "\u63A8\u8350",
@@ -4888,29 +4904,41 @@ var tierCard3 = {
4888
4904
  fontWeight: "800",
4889
4905
  radius: 6,
4890
4906
  textAlign: "center",
4891
- lineHeight: 22
4907
+ lineHeight: 22,
4908
+ whiteSpace: "nowrap"
4892
4909
  }
4893
4910
  },
4894
4911
  {
4895
4912
  type: "text",
4896
4913
  rect: [0, 12, "100%", 19],
4897
4914
  content: "{{ item.p }}",
4898
- style: { fontSize: 13, color: "#8a909c", textAlign: "center" }
4915
+ style: { fontSize: 13, lineHeight: 1.45, color: "#8a909c", textAlign: "center" }
4899
4916
  },
4900
4917
  {
4901
4918
  type: "flex",
4902
- rect: [0, 34, "100%", 26],
4919
+ rect: [0, 36, "100%", 26],
4903
4920
  style: { justify: "center", align: "baseline" },
4904
4921
  children: [
4905
4922
  {
4923
+ // .tpr i:符号比数字小一号、字重 600
4906
4924
  type: "text",
4907
4925
  content: "\xA5",
4908
- style: { fontSize: 13, fontWeight: "800", color: "#1f2533" }
4926
+ style: {
4927
+ fontSize: 14,
4928
+ fontWeight: "600",
4929
+ lineHeight: 1.2,
4930
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4931
+ }
4909
4932
  },
4910
4933
  {
4911
4934
  type: "text",
4912
4935
  content: "{{ item.price }}",
4913
- style: { fontSize: 21, fontWeight: "800", color: "#1f2533" }
4936
+ style: {
4937
+ fontSize: 21,
4938
+ fontWeight: "800",
4939
+ lineHeight: 1.2,
4940
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4941
+ }
4914
4942
  }
4915
4943
  ]
4916
4944
  },
@@ -4918,14 +4946,21 @@ var tierCard3 = {
4918
4946
  type: "text",
4919
4947
  rect: [4, 63, "calc(100% - 8px)", 32],
4920
4948
  content: "{{ item.per }}",
4921
- style: { fontSize: 11, color: "#8a909c", textAlign: "center", lineHeight: 1.35 }
4949
+ style: {
4950
+ fontSize: 11,
4951
+ lineHeight: 1.5,
4952
+ textAlign: "center",
4953
+ color: "{{ item.key == current.key ? '#d46b08' : '#8a909c' }}",
4954
+ fontWeight: "{{ item.key == current.key ? '600' : '400' }}"
4955
+ }
4922
4956
  },
4923
4957
  {
4958
+ // .tflag 的 margin-top: auto(贴底)在绝对定位里直接写死 y = 119 - 9 - 15
4924
4959
  type: "text",
4925
- rect: [0, 98, "100%", 15],
4960
+ rect: [0, 95, "100%", 15],
4926
4961
  content: "{{ item.flag }}",
4927
4962
  visibleWhen: "item.flag != ''",
4928
- style: { fontSize: 11, color: "#8a909c", textAlign: "center" }
4963
+ style: { fontSize: 11, lineHeight: 1.35, color: "#8a909c", textAlign: "center" }
4929
4964
  }
4930
4965
  ]
4931
4966
  };
@@ -4934,13 +4969,37 @@ var quotaLow = {
4934
4969
  type: "popup",
4935
4970
  meta: { name: "\u642C\u5BB6\u6B21\u6570\u5C06\u5C3D \xB7 \u989D\u5EA6\u8FDB\u5EA6\u6761\uFF08\u590D\u523B\u8FD0\u8425 demo\uFF09" },
4936
4971
  stage: {
4972
+ // .modal.period-price-modal { width: min(520px, calc(100vw - 24px)) }
4937
4973
  width: 520,
4938
4974
  height: "auto",
4939
4975
  layout: "flow",
4940
4976
  mask: true,
4941
4977
  maskClosable: false,
4942
- closeButton: { show: true, position: "top-right", offset: [14, 14] },
4943
- style: { radius: 18 }
4978
+ closeButton: {
4979
+ // .m-close:24×24 的半透明白圆点,字符 ×、15px
4980
+ show: true,
4981
+ position: "top-right",
4982
+ offset: [14, 14],
4983
+ size: 24,
4984
+ icon: "\xD7",
4985
+ style: { background: "rgba(255,255,255,0.3)", fontSize: 15, color: "#ffffff" }
4986
+ },
4987
+ // .modal 的圆角与投影(--shadow-lg)
4988
+ style: { radius: 18, shadow: "0 28px 72px rgba(16,27,51,0.24)" },
4989
+ // demo 的 animation: pop .38s cubic-bezier(.16,1,.3,1) both
4990
+ // 注意 easing 的小数必须写成 0.16 —— 校验的正则不认 CSS 允许的 .16 简写
4991
+ animate: {
4992
+ name: "pop",
4993
+ duration: 380,
4994
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)",
4995
+ fill: "both"
4996
+ }
4997
+ },
4998
+ keyframes: {
4999
+ pop: {
5000
+ from: { opacity: 0, transform: "translateY(14px) scale(0.96)" },
5001
+ to: { opacity: 1, transform: "none" }
5002
+ }
4944
5003
  },
4945
5004
  data: {
4946
5005
  // 实时统计走后端数据源。$source 填的是宿主注册过的数据源名(不是接口地址),
@@ -4948,20 +5007,11 @@ var quotaLow = {
4948
5007
  stat: { $source: "userStatistics" },
4949
5008
  // 总额度:运营按当前套餐手填。为什么不走接口、以后怎么换,见文件头注释
4950
5009
  total: 30,
5010
+ // 三条都没有状态标签 —— demo 这一屏的 lose 配置里就没有 tag 字段
4951
5011
  lose: [
4952
- { b: "\u6279\u91CF\u642C\u5BB6", tag: "\u5C06\u505C\u7528", sev: "lose", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
4953
- {
4954
- b: "1688 \u4E00\u4EF6\u4EE3\u53D1",
4955
- tag: "\u5C06\u505C\u7528",
4956
- sev: "lose",
4957
- t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A"
4958
- },
4959
- {
4960
- b: "AI \u81EA\u52A8\u4F18\u5316",
4961
- tag: "\u5C06\u6682\u505C",
4962
- sev: "pause",
4963
- t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE"
4964
- }
5012
+ { b: "\u6279\u91CF\u642C\u5BB6", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
5013
+ { b: "1688 \u4E00\u4EF6\u4EE3\u53D1", t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A" },
5014
+ { b: "AI \u81EA\u52A8\u4F18\u5316", t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE" }
4965
5015
  ],
4966
5016
  // 价格档位从后端数据源取,后端返回几档就渲染几档,配置时不用知道数量
4967
5017
  tiers: { $source: "listRenewTiers", params: { scene: "quota_low" } }
@@ -4969,118 +5019,114 @@ var quotaLow = {
4969
5019
  state: { period: 1 },
4970
5020
  derived: { current: { list: "tiers", indexBy: "period" } },
4971
5021
  nodes: [
4972
- // ===== 深色渐变头部:标签 + 2×2 成果格 =====
5022
+ // ===== .m-top 深色渐变头部:(标签 + 额度条)同排 + 2×2 成果格 =====
4973
5023
  {
4974
5024
  type: "flex",
4975
5025
  style: {
4976
5026
  direction: "column",
4977
5027
  background: "linear-gradient(135deg,#2b0f0f,#3a1414)",
4978
- padding: "20px 22px 16px",
4979
- gap: 13
5028
+ padding: "20px 22px 16px"
4980
5029
  },
4981
5030
  children: [
4982
5031
  {
4983
- type: "text",
4984
- content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
4985
- style: {
4986
- // 不写 alignSelf 会被 flex 列拉满整行,标签必须按内容宽度
4987
- alignSelf: "flex-start",
4988
- background: "rgba(255,255,255,0.18)",
4989
- color: "#ffffff",
4990
- fontSize: 12,
4991
- fontWeight: "700",
4992
- radius: 6,
4993
- padding: "5px 10px"
4994
- }
4995
- },
4996
- {
4997
- // 四格并列写死(扁平对象没法 bind 遍历),flex + wrap 排成 2×2。
4998
- // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
4999
- type: "flex",
5000
- style: { gap: 9, wrap: true },
5001
- children: [
5002
- achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
5003
- achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
5004
- achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
5005
- achieveCell3(
5006
- "\u5DF2\u8865\u9F50",
5007
- "{{ stat.white_image_fill_count }}",
5008
- "\u5F20",
5009
- "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
5010
- )
5011
- ]
5012
- }
5013
- ]
5014
- },
5015
- // ===== 白色 body =====
5016
- {
5017
- type: "flex",
5018
- style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
5019
- children: [
5020
- // ===== 额度进度条:轨道 + 填充条 + 百分比表达式(本示例的重点)=====
5021
- {
5032
+ // .m-top-head:右侧留 30px 给关闭按钮让位
5022
5033
  type: "flex",
5023
5034
  style: {
5024
- direction: "column",
5025
- background: "#fff8f3",
5026
- radius: 10,
5027
- padding: "8px 13px 9px",
5028
- gap: 4
5035
+ align: "center",
5036
+ justify: "space-between",
5037
+ gap: 14,
5038
+ padding: "0 30px 0 0"
5029
5039
  },
5030
5040
  children: [
5031
5041
  {
5032
- // 标题行:左边「剩余 N 次」,右边「已用 X / 总额度 次」
5042
+ // .tag:flex: none,按内容宽度,不许被额度条挤扁
5043
+ type: "text",
5044
+ content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
5045
+ style: {
5046
+ background: "rgba(255,255,255,0.18)",
5047
+ color: "#ffffff",
5048
+ fontSize: 12,
5049
+ fontWeight: "700",
5050
+ radius: 6,
5051
+ padding: "3px 10px",
5052
+ flexShrink: "0",
5053
+ whiteSpace: "nowrap"
5054
+ }
5055
+ },
5056
+ {
5057
+ // ===== 额度进度条(本示例的重点)。.m-top .quota 反白配色版 =====
5033
5058
  type: "flex",
5034
- style: { align: "baseline", justify: "space-between" },
5059
+ style: {
5060
+ direction: "column",
5061
+ flex: "1",
5062
+ maxWidth: 280,
5063
+ background: "rgba(255,255,255,0.12)",
5064
+ borderWidth: 1,
5065
+ borderStyle: "solid",
5066
+ borderColor: "rgba(255,255,255,0.16)",
5067
+ radius: 7,
5068
+ padding: "3px 10px 4px"
5069
+ },
5035
5070
  children: [
5036
5071
  {
5072
+ // .qh:左「搬家次数剩余」,右加粗的剩余次数
5037
5073
  type: "flex",
5038
- style: { align: "baseline", gap: 3 },
5074
+ style: { align: "baseline", justify: "space-between" },
5039
5075
  children: [
5040
5076
  {
5041
5077
  type: "text",
5042
5078
  content: "\u642C\u5BB6\u6B21\u6570\u5269\u4F59",
5043
- style: { fontSize: 12, lineHeight: 1.35, color: "#3f4656" }
5079
+ style: {
5080
+ fontSize: 10.5,
5081
+ lineHeight: 1.25,
5082
+ color: "rgba(255,255,255,0.85)"
5083
+ }
5044
5084
  },
5045
5085
  {
5046
5086
  type: "text",
5047
5087
  content: "{{ user.collectCount }} \u6B21",
5048
5088
  style: {
5049
- fontSize: 15,
5089
+ fontSize: 12.5,
5050
5090
  fontWeight: "800",
5051
- lineHeight: 1.25,
5052
- color: "#cf1322"
5091
+ lineHeight: 1.15,
5092
+ color: "#ffb066"
5093
+ }
5094
+ }
5095
+ ]
5096
+ },
5097
+ {
5098
+ // .qbar 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
5099
+ // 填充条要的是「跟着父级流」;overflow: hidden 必须写,
5100
+ // 否则填充条的直角会戳出轨道的圆角外面
5101
+ type: "flex",
5102
+ style: {
5103
+ height: 3,
5104
+ radius: 4,
5105
+ background: "rgba(255,255,255,0.2)",
5106
+ margin: "2px 0 1px",
5107
+ overflow: "hidden"
5108
+ },
5109
+ children: [
5110
+ {
5111
+ // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
5112
+ // 字符串同样走插值,所以百分比不需要后端多下发一个字段
5113
+ type: "box",
5114
+ style: {
5115
+ width: "{{ (total - user.collectCount) / total * 100 }}%",
5116
+ height: "100%",
5117
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
5053
5118
  }
5054
5119
  }
5055
5120
  ]
5056
5121
  },
5057
5122
  {
5123
+ // .qn
5058
5124
  type: "text",
5059
5125
  content: `\u5DF2\u7528 ${USED} / {{ total }} \u6B21`,
5060
- style: { fontSize: 10.5, lineHeight: 1.35, color: "#8a909c" }
5061
- }
5062
- ]
5063
- },
5064
- {
5065
- // 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
5066
- // 填充条要的是「跟着父级流」;overflow: hidden 必须写,否则填充条的
5067
- // 直角会戳出轨道的圆角外面
5068
- type: "flex",
5069
- style: {
5070
- height: 5,
5071
- radius: 4,
5072
- background: "#ffe0cc",
5073
- overflow: "hidden"
5074
- },
5075
- children: [
5076
- {
5077
- // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
5078
- // 字符串同样走插值,所以百分比不需要后端多下发一个字段
5079
- type: "box",
5080
5126
  style: {
5081
- width: "{{ (total - user.collectCount) / total * 100 }}%",
5082
- height: "100%",
5083
- background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
5127
+ fontSize: 9,
5128
+ lineHeight: 1.25,
5129
+ color: "rgba(255,255,255,0.6)"
5084
5130
  }
5085
5131
  }
5086
5132
  ]
@@ -5088,17 +5134,49 @@ var quotaLow = {
5088
5134
  ]
5089
5135
  },
5090
5136
  {
5137
+ // .achieve:四格并列写死(扁平对象没法 bind 遍历),flex + wrap 复刻 2×2 grid。
5138
+ // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
5139
+ type: "flex",
5140
+ style: { gap: 9, wrap: true, marginTop: 14 },
5141
+ children: [
5142
+ achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
5143
+ achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
5144
+ achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
5145
+ achieveCell3(
5146
+ "\u5DF2\u8865\u9F50",
5147
+ "{{ stat.white_image_fill_count }}",
5148
+ "\u5F20",
5149
+ "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
5150
+ )
5151
+ ]
5152
+ }
5153
+ ]
5154
+ },
5155
+ // ===== .m-body 白底 =====
5156
+ {
5157
+ type: "flex",
5158
+ style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
5159
+ children: [
5160
+ {
5161
+ // .m-copy-panel
5091
5162
  type: "text",
5092
5163
  content: "\u642C\u5BB6\u6B21\u6570\u7528\u5B8C\uFF0C\u4EA7\u54C1\u80FD\u529B\u5C06\u53D7\u9650\uFF1A",
5093
- style: { fontSize: 15, fontWeight: "800", color: "#1f2533", marginTop: 17 }
5164
+ style: {
5165
+ fontSize: 15,
5166
+ fontWeight: "800",
5167
+ lineHeight: 1.55,
5168
+ letterSpacing: -0.15,
5169
+ color: "#1f2533"
5170
+ }
5094
5171
  },
5095
5172
  {
5173
+ // .lose
5096
5174
  type: "repeat",
5097
5175
  bind: "lose",
5098
5176
  template: loseRow3,
5099
5177
  style: {
5100
5178
  direction: "column",
5101
- marginTop: 12,
5179
+ marginTop: 14,
5102
5180
  background: "#ffe9e6",
5103
5181
  borderWidth: 1,
5104
5182
  borderStyle: "solid",
@@ -5108,13 +5186,20 @@ var quotaLow = {
5108
5186
  }
5109
5187
  },
5110
5188
  {
5189
+ // .tiers 的 border-top:白名单没有 borderTop,用 1px 实心分隔条代替
5190
+ type: "box",
5191
+ style: { height: 1, background: "#eceef3", marginTop: 18 }
5192
+ },
5193
+ {
5194
+ // .tv:lead 被 normalizeTrialPricing 置空,所以整行都在 <b> 里
5195
+ //(字重 800、墨色),后面跟价格口径标记 .tv-tag
5111
5196
  type: "flex",
5112
- style: { align: "center", gap: 8, marginTop: 17, marginBottom: 9 },
5197
+ style: { align: "center", gap: 8, marginTop: 17, marginBottom: 11 },
5113
5198
  children: [
5114
5199
  {
5115
5200
  type: "text",
5116
- content: "\u7EED\u6EE1\u989D\u5EA6 \xB7 \u9009\u62E9\u5468\u671F",
5117
- style: { fontSize: 13.5, fontWeight: "700", color: "#747b89" }
5201
+ content: "\u4E13\u5C5E\u4F18\u60E0 \xB7 \u5012\u8BA1\u65F6",
5202
+ style: { fontSize: 13.5, fontWeight: "800", color: "#1f2533" }
5118
5203
  },
5119
5204
  {
5120
5205
  type: "text",
@@ -5131,19 +5216,27 @@ var quotaLow = {
5131
5216
  }
5132
5217
  ]
5133
5218
  },
5219
+ // .tcols:wide 版 gap 8
5134
5220
  { type: "repeat", bind: "tiers", style: { gap: 8 }, template: tierCard3 },
5135
5221
  {
5222
+ // .m-cta(th-loss 主题的红橙渐变)
5136
5223
  type: "flex",
5137
5224
  style: {
5138
5225
  justify: "center",
5139
- align: "center",
5226
+ align: "baseline",
5140
5227
  gap: 5,
5141
- height: 52,
5228
+ padding: "13px",
5142
5229
  radius: 11,
5143
5230
  background: "linear-gradient(90deg,#f53f3f,#ff7a45)",
5144
- marginTop: 15,
5231
+ marginTop: 20,
5232
+ shadow: "0 8px 18px rgba(245,63,63,0.14)",
5233
+ transition: "transform 0.18s, box-shadow 0.18s",
5145
5234
  cursor: "pointer"
5146
5235
  },
5236
+ hoverStyle: {
5237
+ transform: "translateY(-1px)",
5238
+ shadow: "0 10px 22px rgba(245,63,63,0.2)"
5239
+ },
5147
5240
  action: {
5148
5241
  type: "sequence",
5149
5242
  actions: [
@@ -5157,11 +5250,18 @@ var quotaLow = {
5157
5250
  },
5158
5251
  children: [
5159
5252
  {
5253
+ // .m-cta .ct
5160
5254
  type: "text",
5161
5255
  content: "\u7EED\u6EE1\u989D\u5EA6 \xB7",
5162
- style: { fontSize: 14, fontWeight: "800", color: "#ffffff" }
5256
+ style: {
5257
+ fontSize: 14,
5258
+ fontWeight: "800",
5259
+ letterSpacing: -0.2,
5260
+ color: "#ffffff"
5261
+ }
5163
5262
  },
5164
5263
  {
5264
+ // .m-cta .cp —— demo 的 syncCTAPrice() 把它同步成「选中档位名 + 价格」
5165
5265
  type: "text",
5166
5266
  content: "{{ current.p }} \xA5{{ current.price }}",
5167
5267
  style: { fontSize: 16.5, fontWeight: "800", color: "#ffffff" }
@@ -5169,13 +5269,14 @@ var quotaLow = {
5169
5269
  ]
5170
5270
  },
5171
5271
  {
5272
+ // .m-ghost
5172
5273
  type: "text",
5173
5274
  content: "\u5347\u7EA7\u6216\u67E5\u770B\u66F4\u591A\u4EA7\u54C1\u5957\u9910",
5174
5275
  style: {
5175
- fontSize: 12.5,
5276
+ fontSize: 12,
5176
5277
  color: "#8a909c",
5177
5278
  textAlign: "center",
5178
- marginTop: 11,
5279
+ marginTop: 10,
5179
5280
  cursor: "pointer"
5180
5281
  },
5181
5282
  action: { type: "track", event: "popup_more_plans" }
@@ -4601,20 +4601,22 @@ var achieveCell3 = (verb, value, unit, label) => ({
4601
4601
  type: "flex",
4602
4602
  style: {
4603
4603
  direction: "column",
4604
+ // grid 不在白名单,用 flex wrap + 半宽复刻 grid-template-columns: 1fr 1fr(gap 9)
4604
4605
  width: "calc(50% - 5px)",
4605
4606
  background: "rgba(255,255,255,0.16)",
4606
4607
  borderWidth: 1,
4607
4608
  borderStyle: "solid",
4608
4609
  borderColor: "rgba(255,255,255,0.2)",
4609
4610
  radius: 10,
4610
- padding: "10px 13px",
4611
- gap: 3
4611
+ // .period-price-modal .ac 把基础规则的 9px 11px 覆盖成 10px 13px
4612
+ padding: "10px 13px"
4612
4613
  },
4613
4614
  children: [
4614
4615
  {
4615
- // lineHeight 必须显式给,否则 20px 数字的默认行高会把格子撑高
4616
+ // .ac .n:line-height 1.1 × 20px = 22px,显式给死,
4617
+ // 否则 20px 数字的默认行高(≈1.5)会把格子撑高 8px 左右
4616
4618
  type: "flex",
4617
- style: { align: "baseline", gap: 3, height: 22 },
4619
+ style: { align: "baseline", height: 22, whiteSpace: "nowrap" },
4618
4620
  children: [
4619
4621
  {
4620
4622
  type: "text",
@@ -4623,7 +4625,10 @@ var achieveCell3 = (verb, value, unit, label) => ({
4623
4625
  fontSize: 11.5,
4624
4626
  fontWeight: "600",
4625
4627
  lineHeight: 1.1,
4626
- color: "rgba(255,255,255,0.92)"
4628
+ letterSpacing: 0.2,
4629
+ marginRight: 3,
4630
+ // demo 是 opacity .7 叠在 .m-top 的白字上,等价于这个色值
4631
+ color: "rgba(255,255,255,0.7)"
4627
4632
  }
4628
4633
  },
4629
4634
  {
@@ -4634,14 +4639,25 @@ var achieveCell3 = (verb, value, unit, label) => ({
4634
4639
  {
4635
4640
  type: "text",
4636
4641
  content: ` ${unit}`,
4637
- style: { fontSize: 12, lineHeight: 1.1, color: "rgba(255,255,255,0.92)" }
4642
+ style: {
4643
+ fontSize: 12,
4644
+ fontWeight: "600",
4645
+ lineHeight: 1.1,
4646
+ // demo 是 opacity .85
4647
+ color: "rgba(255,255,255,0.85)"
4648
+ }
4638
4649
  }
4639
4650
  ]
4640
4651
  },
4641
4652
  {
4642
4653
  type: "text",
4643
4654
  content: label,
4644
- style: { fontSize: 11.5, lineHeight: 1.35, color: "rgba(255,255,255,0.72)" }
4655
+ style: {
4656
+ fontSize: 11,
4657
+ lineHeight: 1.4,
4658
+ marginTop: 2,
4659
+ color: "rgba(255,255,255,0.85)"
4660
+ }
4645
4661
  }
4646
4662
  ]
4647
4663
  });
@@ -4652,7 +4668,15 @@ var loseRow3 = {
4652
4668
  {
4653
4669
  type: "text",
4654
4670
  content: "",
4655
- style: { width: 6, height: 6, radius: "50%", background: "#f53f3f", marginTop: 7 }
4671
+ style: {
4672
+ width: 6,
4673
+ height: 6,
4674
+ radius: "50%",
4675
+ background: "#f53f3f",
4676
+ marginTop: 7,
4677
+ // demo 的 flex: none —— 文案换行时圆点不许被压扁
4678
+ flexShrink: "0"
4679
+ }
4656
4680
  },
4657
4681
  {
4658
4682
  type: "flex",
@@ -4668,20 +4692,6 @@ var loseRow3 = {
4668
4692
  color: "#1f2533"
4669
4693
  }
4670
4694
  },
4671
- {
4672
- type: "text",
4673
- content: "{{ item.tag }}",
4674
- visibleWhen: "item.tag != ''",
4675
- style: {
4676
- background: "{{ item.sev == 'lose' ? '#ffd5cf' : 'rgba(255,255,255,0.78)' }}",
4677
- color: "{{ item.sev == 'lose' ? '#cf1322' : '#8a7f78' }}",
4678
- fontSize: 10,
4679
- fontWeight: "800",
4680
- radius: 4,
4681
- padding: "1px 6px",
4682
- whiteSpace: "nowrap"
4683
- }
4684
- },
4685
4695
  {
4686
4696
  type: "text",
4687
4697
  content: "\u2014 {{ item.t }}",
@@ -4695,14 +4705,18 @@ var tierCard3 = {
4695
4705
  type: "box",
4696
4706
  style: {
4697
4707
  flex: "1",
4698
- height: 121,
4708
+ height: 119,
4699
4709
  radius: 12,
4700
4710
  background: "{{ item.key == current.key ? '#fffaf0' : '#ffffff' }}",
4701
4711
  borderStyle: "solid",
4702
4712
  borderWidth: "{{ item.key == current.key ? '2px' : '1px' }}",
4703
4713
  borderColor: "{{ item.key == current.key ? '#f0a000' : '#e5e8ed' }}",
4704
- cursor: "pointer"
4714
+ shadow: "{{ item.key == current.key ? '0 7px 18px rgba(240,160,0,0.1)' : 'none' }}",
4715
+ cursor: "pointer",
4716
+ transition: "border-color 0.15s, background 0.15s, box-shadow 0.15s"
4705
4717
  },
4718
+ // .tcol:hover { border-color: var(--gold) }
4719
+ hoverStyle: { borderColor: "#faad14" },
4706
4720
  action: {
4707
4721
  type: "sequence",
4708
4722
  actions: [
@@ -4716,6 +4730,8 @@ var tierCard3 = {
4716
4730
  },
4717
4731
  children: [
4718
4732
  {
4733
+ // .thot:top -9、字号 11、padding 2px 8px、radius 6。
4734
+ // 宽 38 = 2 字 × 11px + 左右 8px;居中靠 left: calc(50% - 19px)
4719
4735
  type: "text",
4720
4736
  rect: ["calc(50% - 19px)", -9, 38, 22],
4721
4737
  content: "\u63A8\u8350",
@@ -4727,29 +4743,41 @@ var tierCard3 = {
4727
4743
  fontWeight: "800",
4728
4744
  radius: 6,
4729
4745
  textAlign: "center",
4730
- lineHeight: 22
4746
+ lineHeight: 22,
4747
+ whiteSpace: "nowrap"
4731
4748
  }
4732
4749
  },
4733
4750
  {
4734
4751
  type: "text",
4735
4752
  rect: [0, 12, "100%", 19],
4736
4753
  content: "{{ item.p }}",
4737
- style: { fontSize: 13, color: "#8a909c", textAlign: "center" }
4754
+ style: { fontSize: 13, lineHeight: 1.45, color: "#8a909c", textAlign: "center" }
4738
4755
  },
4739
4756
  {
4740
4757
  type: "flex",
4741
- rect: [0, 34, "100%", 26],
4758
+ rect: [0, 36, "100%", 26],
4742
4759
  style: { justify: "center", align: "baseline" },
4743
4760
  children: [
4744
4761
  {
4762
+ // .tpr i:符号比数字小一号、字重 600
4745
4763
  type: "text",
4746
4764
  content: "\xA5",
4747
- style: { fontSize: 13, fontWeight: "800", color: "#1f2533" }
4765
+ style: {
4766
+ fontSize: 14,
4767
+ fontWeight: "600",
4768
+ lineHeight: 1.2,
4769
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4770
+ }
4748
4771
  },
4749
4772
  {
4750
4773
  type: "text",
4751
4774
  content: "{{ item.price }}",
4752
- style: { fontSize: 21, fontWeight: "800", color: "#1f2533" }
4775
+ style: {
4776
+ fontSize: 21,
4777
+ fontWeight: "800",
4778
+ lineHeight: 1.2,
4779
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4780
+ }
4753
4781
  }
4754
4782
  ]
4755
4783
  },
@@ -4757,14 +4785,21 @@ var tierCard3 = {
4757
4785
  type: "text",
4758
4786
  rect: [4, 63, "calc(100% - 8px)", 32],
4759
4787
  content: "{{ item.per }}",
4760
- style: { fontSize: 11, color: "#8a909c", textAlign: "center", lineHeight: 1.35 }
4788
+ style: {
4789
+ fontSize: 11,
4790
+ lineHeight: 1.5,
4791
+ textAlign: "center",
4792
+ color: "{{ item.key == current.key ? '#d46b08' : '#8a909c' }}",
4793
+ fontWeight: "{{ item.key == current.key ? '600' : '400' }}"
4794
+ }
4761
4795
  },
4762
4796
  {
4797
+ // .tflag 的 margin-top: auto(贴底)在绝对定位里直接写死 y = 119 - 9 - 15
4763
4798
  type: "text",
4764
- rect: [0, 98, "100%", 15],
4799
+ rect: [0, 95, "100%", 15],
4765
4800
  content: "{{ item.flag }}",
4766
4801
  visibleWhen: "item.flag != ''",
4767
- style: { fontSize: 11, color: "#8a909c", textAlign: "center" }
4802
+ style: { fontSize: 11, lineHeight: 1.35, color: "#8a909c", textAlign: "center" }
4768
4803
  }
4769
4804
  ]
4770
4805
  };
@@ -4773,13 +4808,37 @@ var quotaLow = {
4773
4808
  type: "popup",
4774
4809
  meta: { name: "\u642C\u5BB6\u6B21\u6570\u5C06\u5C3D \xB7 \u989D\u5EA6\u8FDB\u5EA6\u6761\uFF08\u590D\u523B\u8FD0\u8425 demo\uFF09" },
4775
4810
  stage: {
4811
+ // .modal.period-price-modal { width: min(520px, calc(100vw - 24px)) }
4776
4812
  width: 520,
4777
4813
  height: "auto",
4778
4814
  layout: "flow",
4779
4815
  mask: true,
4780
4816
  maskClosable: false,
4781
- closeButton: { show: true, position: "top-right", offset: [14, 14] },
4782
- style: { radius: 18 }
4817
+ closeButton: {
4818
+ // .m-close:24×24 的半透明白圆点,字符 ×、15px
4819
+ show: true,
4820
+ position: "top-right",
4821
+ offset: [14, 14],
4822
+ size: 24,
4823
+ icon: "\xD7",
4824
+ style: { background: "rgba(255,255,255,0.3)", fontSize: 15, color: "#ffffff" }
4825
+ },
4826
+ // .modal 的圆角与投影(--shadow-lg)
4827
+ style: { radius: 18, shadow: "0 28px 72px rgba(16,27,51,0.24)" },
4828
+ // demo 的 animation: pop .38s cubic-bezier(.16,1,.3,1) both
4829
+ // 注意 easing 的小数必须写成 0.16 —— 校验的正则不认 CSS 允许的 .16 简写
4830
+ animate: {
4831
+ name: "pop",
4832
+ duration: 380,
4833
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)",
4834
+ fill: "both"
4835
+ }
4836
+ },
4837
+ keyframes: {
4838
+ pop: {
4839
+ from: { opacity: 0, transform: "translateY(14px) scale(0.96)" },
4840
+ to: { opacity: 1, transform: "none" }
4841
+ }
4783
4842
  },
4784
4843
  data: {
4785
4844
  // 实时统计走后端数据源。$source 填的是宿主注册过的数据源名(不是接口地址),
@@ -4787,20 +4846,11 @@ var quotaLow = {
4787
4846
  stat: { $source: "userStatistics" },
4788
4847
  // 总额度:运营按当前套餐手填。为什么不走接口、以后怎么换,见文件头注释
4789
4848
  total: 30,
4849
+ // 三条都没有状态标签 —— demo 这一屏的 lose 配置里就没有 tag 字段
4790
4850
  lose: [
4791
- { b: "\u6279\u91CF\u642C\u5BB6", tag: "\u5C06\u505C\u7528", sev: "lose", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
4792
- {
4793
- b: "1688 \u4E00\u4EF6\u4EE3\u53D1",
4794
- tag: "\u5C06\u505C\u7528",
4795
- sev: "lose",
4796
- t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A"
4797
- },
4798
- {
4799
- b: "AI \u81EA\u52A8\u4F18\u5316",
4800
- tag: "\u5C06\u6682\u505C",
4801
- sev: "pause",
4802
- t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE"
4803
- }
4851
+ { b: "\u6279\u91CF\u642C\u5BB6", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
4852
+ { b: "1688 \u4E00\u4EF6\u4EE3\u53D1", t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A" },
4853
+ { b: "AI \u81EA\u52A8\u4F18\u5316", t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE" }
4804
4854
  ],
4805
4855
  // 价格档位从后端数据源取,后端返回几档就渲染几档,配置时不用知道数量
4806
4856
  tiers: { $source: "listRenewTiers", params: { scene: "quota_low" } }
@@ -4808,118 +4858,114 @@ var quotaLow = {
4808
4858
  state: { period: 1 },
4809
4859
  derived: { current: { list: "tiers", indexBy: "period" } },
4810
4860
  nodes: [
4811
- // ===== 深色渐变头部:标签 + 2×2 成果格 =====
4861
+ // ===== .m-top 深色渐变头部:(标签 + 额度条)同排 + 2×2 成果格 =====
4812
4862
  {
4813
4863
  type: "flex",
4814
4864
  style: {
4815
4865
  direction: "column",
4816
4866
  background: "linear-gradient(135deg,#2b0f0f,#3a1414)",
4817
- padding: "20px 22px 16px",
4818
- gap: 13
4867
+ padding: "20px 22px 16px"
4819
4868
  },
4820
4869
  children: [
4821
4870
  {
4822
- type: "text",
4823
- content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
4824
- style: {
4825
- // 不写 alignSelf 会被 flex 列拉满整行,标签必须按内容宽度
4826
- alignSelf: "flex-start",
4827
- background: "rgba(255,255,255,0.18)",
4828
- color: "#ffffff",
4829
- fontSize: 12,
4830
- fontWeight: "700",
4831
- radius: 6,
4832
- padding: "5px 10px"
4833
- }
4834
- },
4835
- {
4836
- // 四格并列写死(扁平对象没法 bind 遍历),flex + wrap 排成 2×2。
4837
- // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
4838
- type: "flex",
4839
- style: { gap: 9, wrap: true },
4840
- children: [
4841
- achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
4842
- achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
4843
- achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
4844
- achieveCell3(
4845
- "\u5DF2\u8865\u9F50",
4846
- "{{ stat.white_image_fill_count }}",
4847
- "\u5F20",
4848
- "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
4849
- )
4850
- ]
4851
- }
4852
- ]
4853
- },
4854
- // ===== 白色 body =====
4855
- {
4856
- type: "flex",
4857
- style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
4858
- children: [
4859
- // ===== 额度进度条:轨道 + 填充条 + 百分比表达式(本示例的重点)=====
4860
- {
4871
+ // .m-top-head:右侧留 30px 给关闭按钮让位
4861
4872
  type: "flex",
4862
4873
  style: {
4863
- direction: "column",
4864
- background: "#fff8f3",
4865
- radius: 10,
4866
- padding: "8px 13px 9px",
4867
- gap: 4
4874
+ align: "center",
4875
+ justify: "space-between",
4876
+ gap: 14,
4877
+ padding: "0 30px 0 0"
4868
4878
  },
4869
4879
  children: [
4870
4880
  {
4871
- // 标题行:左边「剩余 N 次」,右边「已用 X / 总额度 次」
4881
+ // .tag:flex: none,按内容宽度,不许被额度条挤扁
4882
+ type: "text",
4883
+ content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
4884
+ style: {
4885
+ background: "rgba(255,255,255,0.18)",
4886
+ color: "#ffffff",
4887
+ fontSize: 12,
4888
+ fontWeight: "700",
4889
+ radius: 6,
4890
+ padding: "3px 10px",
4891
+ flexShrink: "0",
4892
+ whiteSpace: "nowrap"
4893
+ }
4894
+ },
4895
+ {
4896
+ // ===== 额度进度条(本示例的重点)。.m-top .quota 反白配色版 =====
4872
4897
  type: "flex",
4873
- style: { align: "baseline", justify: "space-between" },
4898
+ style: {
4899
+ direction: "column",
4900
+ flex: "1",
4901
+ maxWidth: 280,
4902
+ background: "rgba(255,255,255,0.12)",
4903
+ borderWidth: 1,
4904
+ borderStyle: "solid",
4905
+ borderColor: "rgba(255,255,255,0.16)",
4906
+ radius: 7,
4907
+ padding: "3px 10px 4px"
4908
+ },
4874
4909
  children: [
4875
4910
  {
4911
+ // .qh:左「搬家次数剩余」,右加粗的剩余次数
4876
4912
  type: "flex",
4877
- style: { align: "baseline", gap: 3 },
4913
+ style: { align: "baseline", justify: "space-between" },
4878
4914
  children: [
4879
4915
  {
4880
4916
  type: "text",
4881
4917
  content: "\u642C\u5BB6\u6B21\u6570\u5269\u4F59",
4882
- style: { fontSize: 12, lineHeight: 1.35, color: "#3f4656" }
4918
+ style: {
4919
+ fontSize: 10.5,
4920
+ lineHeight: 1.25,
4921
+ color: "rgba(255,255,255,0.85)"
4922
+ }
4883
4923
  },
4884
4924
  {
4885
4925
  type: "text",
4886
4926
  content: "{{ user.collectCount }} \u6B21",
4887
4927
  style: {
4888
- fontSize: 15,
4928
+ fontSize: 12.5,
4889
4929
  fontWeight: "800",
4890
- lineHeight: 1.25,
4891
- color: "#cf1322"
4930
+ lineHeight: 1.15,
4931
+ color: "#ffb066"
4932
+ }
4933
+ }
4934
+ ]
4935
+ },
4936
+ {
4937
+ // .qbar 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
4938
+ // 填充条要的是「跟着父级流」;overflow: hidden 必须写,
4939
+ // 否则填充条的直角会戳出轨道的圆角外面
4940
+ type: "flex",
4941
+ style: {
4942
+ height: 3,
4943
+ radius: 4,
4944
+ background: "rgba(255,255,255,0.2)",
4945
+ margin: "2px 0 1px",
4946
+ overflow: "hidden"
4947
+ },
4948
+ children: [
4949
+ {
4950
+ // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
4951
+ // 字符串同样走插值,所以百分比不需要后端多下发一个字段
4952
+ type: "box",
4953
+ style: {
4954
+ width: "{{ (total - user.collectCount) / total * 100 }}%",
4955
+ height: "100%",
4956
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
4892
4957
  }
4893
4958
  }
4894
4959
  ]
4895
4960
  },
4896
4961
  {
4962
+ // .qn
4897
4963
  type: "text",
4898
4964
  content: `\u5DF2\u7528 ${USED} / {{ total }} \u6B21`,
4899
- style: { fontSize: 10.5, lineHeight: 1.35, color: "#8a909c" }
4900
- }
4901
- ]
4902
- },
4903
- {
4904
- // 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
4905
- // 填充条要的是「跟着父级流」;overflow: hidden 必须写,否则填充条的
4906
- // 直角会戳出轨道的圆角外面
4907
- type: "flex",
4908
- style: {
4909
- height: 5,
4910
- radius: 4,
4911
- background: "#ffe0cc",
4912
- overflow: "hidden"
4913
- },
4914
- children: [
4915
- {
4916
- // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
4917
- // 字符串同样走插值,所以百分比不需要后端多下发一个字段
4918
- type: "box",
4919
4965
  style: {
4920
- width: "{{ (total - user.collectCount) / total * 100 }}%",
4921
- height: "100%",
4922
- background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
4966
+ fontSize: 9,
4967
+ lineHeight: 1.25,
4968
+ color: "rgba(255,255,255,0.6)"
4923
4969
  }
4924
4970
  }
4925
4971
  ]
@@ -4927,17 +4973,49 @@ var quotaLow = {
4927
4973
  ]
4928
4974
  },
4929
4975
  {
4976
+ // .achieve:四格并列写死(扁平对象没法 bind 遍历),flex + wrap 复刻 2×2 grid。
4977
+ // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
4978
+ type: "flex",
4979
+ style: { gap: 9, wrap: true, marginTop: 14 },
4980
+ children: [
4981
+ achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
4982
+ achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
4983
+ achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
4984
+ achieveCell3(
4985
+ "\u5DF2\u8865\u9F50",
4986
+ "{{ stat.white_image_fill_count }}",
4987
+ "\u5F20",
4988
+ "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
4989
+ )
4990
+ ]
4991
+ }
4992
+ ]
4993
+ },
4994
+ // ===== .m-body 白底 =====
4995
+ {
4996
+ type: "flex",
4997
+ style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
4998
+ children: [
4999
+ {
5000
+ // .m-copy-panel
4930
5001
  type: "text",
4931
5002
  content: "\u642C\u5BB6\u6B21\u6570\u7528\u5B8C\uFF0C\u4EA7\u54C1\u80FD\u529B\u5C06\u53D7\u9650\uFF1A",
4932
- style: { fontSize: 15, fontWeight: "800", color: "#1f2533", marginTop: 17 }
5003
+ style: {
5004
+ fontSize: 15,
5005
+ fontWeight: "800",
5006
+ lineHeight: 1.55,
5007
+ letterSpacing: -0.15,
5008
+ color: "#1f2533"
5009
+ }
4933
5010
  },
4934
5011
  {
5012
+ // .lose
4935
5013
  type: "repeat",
4936
5014
  bind: "lose",
4937
5015
  template: loseRow3,
4938
5016
  style: {
4939
5017
  direction: "column",
4940
- marginTop: 12,
5018
+ marginTop: 14,
4941
5019
  background: "#ffe9e6",
4942
5020
  borderWidth: 1,
4943
5021
  borderStyle: "solid",
@@ -4947,13 +5025,20 @@ var quotaLow = {
4947
5025
  }
4948
5026
  },
4949
5027
  {
5028
+ // .tiers 的 border-top:白名单没有 borderTop,用 1px 实心分隔条代替
5029
+ type: "box",
5030
+ style: { height: 1, background: "#eceef3", marginTop: 18 }
5031
+ },
5032
+ {
5033
+ // .tv:lead 被 normalizeTrialPricing 置空,所以整行都在 <b> 里
5034
+ //(字重 800、墨色),后面跟价格口径标记 .tv-tag
4950
5035
  type: "flex",
4951
- style: { align: "center", gap: 8, marginTop: 17, marginBottom: 9 },
5036
+ style: { align: "center", gap: 8, marginTop: 17, marginBottom: 11 },
4952
5037
  children: [
4953
5038
  {
4954
5039
  type: "text",
4955
- content: "\u7EED\u6EE1\u989D\u5EA6 \xB7 \u9009\u62E9\u5468\u671F",
4956
- style: { fontSize: 13.5, fontWeight: "700", color: "#747b89" }
5040
+ content: "\u4E13\u5C5E\u4F18\u60E0 \xB7 \u5012\u8BA1\u65F6",
5041
+ style: { fontSize: 13.5, fontWeight: "800", color: "#1f2533" }
4957
5042
  },
4958
5043
  {
4959
5044
  type: "text",
@@ -4970,19 +5055,27 @@ var quotaLow = {
4970
5055
  }
4971
5056
  ]
4972
5057
  },
5058
+ // .tcols:wide 版 gap 8
4973
5059
  { type: "repeat", bind: "tiers", style: { gap: 8 }, template: tierCard3 },
4974
5060
  {
5061
+ // .m-cta(th-loss 主题的红橙渐变)
4975
5062
  type: "flex",
4976
5063
  style: {
4977
5064
  justify: "center",
4978
- align: "center",
5065
+ align: "baseline",
4979
5066
  gap: 5,
4980
- height: 52,
5067
+ padding: "13px",
4981
5068
  radius: 11,
4982
5069
  background: "linear-gradient(90deg,#f53f3f,#ff7a45)",
4983
- marginTop: 15,
5070
+ marginTop: 20,
5071
+ shadow: "0 8px 18px rgba(245,63,63,0.14)",
5072
+ transition: "transform 0.18s, box-shadow 0.18s",
4984
5073
  cursor: "pointer"
4985
5074
  },
5075
+ hoverStyle: {
5076
+ transform: "translateY(-1px)",
5077
+ shadow: "0 10px 22px rgba(245,63,63,0.2)"
5078
+ },
4986
5079
  action: {
4987
5080
  type: "sequence",
4988
5081
  actions: [
@@ -4996,11 +5089,18 @@ var quotaLow = {
4996
5089
  },
4997
5090
  children: [
4998
5091
  {
5092
+ // .m-cta .ct
4999
5093
  type: "text",
5000
5094
  content: "\u7EED\u6EE1\u989D\u5EA6 \xB7",
5001
- style: { fontSize: 14, fontWeight: "800", color: "#ffffff" }
5095
+ style: {
5096
+ fontSize: 14,
5097
+ fontWeight: "800",
5098
+ letterSpacing: -0.2,
5099
+ color: "#ffffff"
5100
+ }
5002
5101
  },
5003
5102
  {
5103
+ // .m-cta .cp —— demo 的 syncCTAPrice() 把它同步成「选中档位名 + 价格」
5004
5104
  type: "text",
5005
5105
  content: "{{ current.p }} \xA5{{ current.price }}",
5006
5106
  style: { fontSize: 16.5, fontWeight: "800", color: "#ffffff" }
@@ -5008,13 +5108,14 @@ var quotaLow = {
5008
5108
  ]
5009
5109
  },
5010
5110
  {
5111
+ // .m-ghost
5011
5112
  type: "text",
5012
5113
  content: "\u5347\u7EA7\u6216\u67E5\u770B\u66F4\u591A\u4EA7\u54C1\u5957\u9910",
5013
5114
  style: {
5014
- fontSize: 12.5,
5115
+ fontSize: 12,
5015
5116
  color: "#8a909c",
5016
5117
  textAlign: "center",
5017
- marginTop: 11,
5118
+ marginTop: 10,
5018
5119
  cursor: "pointer"
5019
5120
  },
5020
5121
  action: { type: "track", event: "popup_more_plans" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaoxiu/marketing-dsl",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "type": "module",
5
5
  "description": "营销弹窗 DSL 解释器核心,纯逻辑无框架依赖",
6
6
  "license": "MIT",