duqing2026 commited on
Commit
198ccdc
·
1 Parent(s): 08adec3

fix: internal server error, add default data, optimize layout

Browse files
Files changed (3) hide show
  1. __pycache__/app.cpython-314.pyc +0 -0
  2. app.py +11 -5
  3. templates/index.html +60 -14
__pycache__/app.cpython-314.pyc ADDED
Binary file (1.21 kB). View file
 
app.py CHANGED
@@ -1,15 +1,21 @@
1
- from flask import Flask, render_template, send_from_directory
2
  import os
3
 
4
  app = Flask(__name__, static_folder='static')
5
 
6
  @app.route('/')
7
  def index():
8
- return render_template('index.html')
 
 
 
9
 
10
- @app.route('/static/<path:path>')
11
- def send_static(path):
12
- return send_from_directory('static', path)
 
 
 
13
 
14
  if __name__ == '__main__':
15
  port = int(os.environ.get('PORT', 7860))
 
1
+ from flask import Flask, render_template, send_from_directory, jsonify
2
  import os
3
 
4
  app = Flask(__name__, static_folder='static')
5
 
6
  @app.route('/')
7
  def index():
8
+ try:
9
+ return render_template('index.html')
10
+ except Exception as e:
11
+ return f"An error occurred: {str(e)}", 500
12
 
13
+ @app.route('/health')
14
+ def health():
15
+ return jsonify({"status": "healthy"}), 200
16
+
17
+ # Flask serves static files automatically from the 'static' folder
18
+ # at the /static endpoint. No need for a manual route unless customizing.
19
 
20
  if __name__ == '__main__':
21
  port = int(os.environ.get('PORT', 7860))
templates/index.html CHANGED
@@ -14,23 +14,30 @@
14
  .slide-enter-active, .slide-leave-active { transition: all 0.3s ease; }
15
  .slide-enter-from, .slide-leave-to { opacity: 0; transform: translateY(10px); }
16
  .canvas-grid {
17
- display: grid;
18
- grid-template-columns: repeat(5, 1fr);
19
- grid-template-rows: repeat(3, minmax(200px, auto));
20
  gap: 1px;
21
  background-color: #e2e8f0;
22
  border: 1px solid #e2e8f0;
23
  }
24
- .canvas-cell { background: white; padding: 1rem; display: flex; flex-direction: column; }
25
- .cell-problem { grid-area: 1 / 1 / 3 / 2; }
26
- .cell-solution { grid-area: 1 / 2 / 2 / 3; }
27
- .cell-metrics { grid-area: 2 / 2 / 3 / 3; }
28
- .cell-uvp { grid-area: 1 / 3 / 3 / 4; }
29
- .cell-advantage { grid-area: 1 / 4 / 2 / 5; }
30
- .cell-channels { grid-area: 2 / 4 / 3 / 5; }
31
- .cell-segments { grid-area: 1 / 5 / 3 / 6; }
32
- .cell-cost { grid-area: 3 / 1 / 4 / 3; }
33
- .cell-revenue { grid-area: 3 / 3 / 4 / 6; }
 
 
 
 
 
 
 
 
34
  </style>
35
  </head>
36
  <body>
@@ -259,6 +266,34 @@
259
  createApp({
260
  components: { CanvasCell },
261
  setup() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  const projects = ref([]);
263
  const currentProject = ref(null);
264
  const currentTab = ref('concept');
@@ -333,7 +368,18 @@
333
  const load = () => {
334
  const data = localStorage.getItem('idea-validator-pro-data');
335
  if (data) {
336
- projects.value = JSON.parse(data);
 
 
 
 
 
 
 
 
 
 
 
337
  }
338
  };
339
 
 
14
  .slide-enter-active, .slide-leave-active { transition: all 0.3s ease; }
15
  .slide-enter-from, .slide-leave-to { opacity: 0; transform: translateY(10px); }
16
  .canvas-grid {
17
+ display: flex;
18
+ flex-direction: column;
 
19
  gap: 1px;
20
  background-color: #e2e8f0;
21
  border: 1px solid #e2e8f0;
22
  }
23
+ .canvas-cell { background: white; padding: 1rem; display: flex; flex-direction: column; min-height: 200px; }
24
+
25
+ @media (min-width: 1024px) {
26
+ .canvas-grid {
27
+ display: grid;
28
+ grid-template-columns: repeat(5, 1fr);
29
+ grid-template-rows: repeat(3, minmax(200px, auto));
30
+ }
31
+ .cell-problem { grid-area: 1 / 1 / 3 / 2; }
32
+ .cell-solution { grid-area: 1 / 2 / 2 / 3; }
33
+ .cell-metrics { grid-area: 2 / 2 / 3 / 3; }
34
+ .cell-uvp { grid-area: 1 / 3 / 3 / 4; }
35
+ .cell-advantage { grid-area: 1 / 4 / 2 / 5; }
36
+ .cell-channels { grid-area: 2 / 4 / 3 / 5; }
37
+ .cell-segments { grid-area: 1 / 5 / 3 / 6; }
38
+ .cell-cost { grid-area: 3 / 1 / 4 / 3; }
39
+ .cell-revenue { grid-area: 3 / 3 / 4 / 6; }
40
+ }
41
  </style>
42
  </head>
43
  <body>
 
266
  createApp({
267
  components: { CanvasCell },
268
  setup() {
269
+ const DEFAULT_PROJECT = {
270
+ id: 'demo-1',
271
+ title: '智能周报生成器 (示例)',
272
+ pitch: '帮助程序员从繁琐的周报中解脱出来,自动从代码提交记录生成高质量周报。',
273
+ who: '互联网公司的程序员、技术经理',
274
+ why: '每周五写周报很痛苦,容易遗漏工作内容,且浪费开发时间。',
275
+ updatedAt: new Date(),
276
+ canvas: {
277
+ problem: ['写周报浪费时间', '容易遗漏工作内容', '格式不统一,主管难以阅读'],
278
+ solution: ['自动读取 Git Commit', 'AI 润色生成自然语言', '支持导出为 Markdown/PDF'],
279
+ metrics: ['周报生成时间从30分钟降至2分钟', '用户留存率'],
280
+ uvp: ['一键生成', '智能润色', '多平台集成 (Jira/GitHub)'],
281
+ advantage: ['先发优势', '高质量的 AI Prompt 库'],
282
+ channels: ['技术博客', 'GitHub Trending', '技术社区 (掘金/V2EX)'],
283
+ segments: ['中大型互联网公司开发团队', '个人开发者'],
284
+ cost: ['OpenAI API 费用', '服务器运维成本'],
285
+ revenue: ['个人版免费', '团队版 $5/人/月']
286
+ },
287
+ experiments: [
288
+ {
289
+ hypothesis: '如果我在 V2EX 发布产品介绍,会有至少 50 人注册试用。',
290
+ method: '撰写一篇详细的软文,介绍产品痛点和解决方案,发布到 V2EX 创造节点。',
291
+ result: '获得了 120 个注册用户,但只有 10% 留存。',
292
+ status: 'success'
293
+ }
294
+ ]
295
+ };
296
+
297
  const projects = ref([]);
298
  const currentProject = ref(null);
299
  const currentTab = ref('concept');
 
368
  const load = () => {
369
  const data = localStorage.getItem('idea-validator-pro-data');
370
  if (data) {
371
+ try {
372
+ projects.value = JSON.parse(data);
373
+ } catch(e) {
374
+ console.error("Data parse error", e);
375
+ projects.value = [];
376
+ }
377
+ }
378
+
379
+ if (projects.value.length === 0) {
380
+ // 使用 JSON.parse(JSON.stringify(...)) 深拷贝,避免引用问题
381
+ projects.value = [JSON.parse(JSON.stringify(DEFAULT_PROJECT))];
382
+ save();
383
  }
384
  };
385