新增定制需求功能和营销素材
@@ -298,3 +298,37 @@ export function cancelVirtualResourceOrder(orderNo) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询后台启用的项目定制技术栈
|
||||
export function listCustomTechStacks() {
|
||||
return request({
|
||||
url: '/app/techStack/options',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 提交项目定制需求(服务端同时扣除 99 积分)
|
||||
export function createCustomRequest(data) {
|
||||
return request({
|
||||
url: '/app/customRequest',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询当前用户的定制需求
|
||||
export function listMyCustomRequests(query) {
|
||||
return request({
|
||||
url: '/app/customRequest/my',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询当前用户的定制需求详情
|
||||
export function getMyCustomRequest(id) {
|
||||
return request({
|
||||
url: '/app/customRequest/my/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ module.exports = {
|
||||
version: "1.1.0",
|
||||
// 应用logo
|
||||
logo: "https://img.yidaima.cn/feast/logo.png",
|
||||
// 项目定制完成后的联系微信
|
||||
contactWechat: "forfeastcoding",
|
||||
// 博客官方网站技术支持
|
||||
site_url: "http://www.yidaima.cn/"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name" : "博客",
|
||||
"name" : "yimo-resource-blog-master",
|
||||
"appid" : "__UNI__ABCEB14",
|
||||
"description" : "",
|
||||
"versionName" : "1.1.0",
|
||||
|
||||
186
marketing/source-code-community-article-richtext.html
Normal file
@@ -0,0 +1,186 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>南音源码库交流群|富文本复制版</title>
|
||||
</head>
|
||||
<body style="margin:0;background:#eef5ff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Microsoft YaHei',Arial,sans-serif;color:#172554;">
|
||||
<div style="position:sticky;top:0;z-index:10;padding:14px;text-align:center;background:rgba(255,255,255,.96);border-bottom:1px solid #dbeafe;">
|
||||
<button id="copyButton" type="button" style="border:0;border-radius:10px;padding:11px 26px;background:linear-gradient(135deg,#1685ff,#7357ee);color:#fff;font-size:16px;font-weight:700;cursor:pointer;box-shadow:0 6px 18px rgba(50,100,220,.22);">复制富文本正文</button>
|
||||
<span id="copyStatus" style="margin-left:12px;color:#526581;font-size:14px;">已适配后台编辑器,复制后直接粘贴</span>
|
||||
</div>
|
||||
|
||||
<main style="padding:28px 14px 60px;">
|
||||
<article id="articleContent" style="box-sizing:border-box;max-width:760px;margin:0 auto;padding:34px 30px;background:#fff;border-radius:18px;box-shadow:0 12px 40px rgba(37,99,235,.10);font-size:16px;line-height:1.9;letter-spacing:.02em;">
|
||||
<section style="margin:0 0 28px;padding:25px 24px;border-radius:16px;background:linear-gradient(135deg,#eef8ff,#f4efff);border:1px solid #dbeafe;text-align:center;">
|
||||
<p style="margin:0 0 10px;color:#2563eb;font-size:14px;font-weight:700;letter-spacing:.12em;">南音源码库 · 社群招募</p>
|
||||
<h2 style="margin:0 0 12px;color:#10235b;font-size:30px;line-height:1.35;font-weight:800;">南音源码库交流群,开放加入</h2>
|
||||
<p style="margin:0;color:#526581;font-size:16px;">源码分享 | 技术交流 | 项目互助</p>
|
||||
</section>
|
||||
|
||||
<p style="margin:0 0 18px;">做「南音源码库」这段时间,陆续认识了不少喜欢折腾项目、研究源码的朋友。</p>
|
||||
<p style="margin:0 0 12px;">大家经常会问:</p>
|
||||
<ul style="margin:0 0 22px;padding-left:24px;color:#33466b;">
|
||||
<li style="margin:7px 0;">某个项目该怎么部署?</li>
|
||||
<li style="margin:7px 0;">遇到报错应该从哪里排查?</li>
|
||||
<li style="margin:7px 0;">有没有适合学习、练手或二次开发的源码?</li>
|
||||
<li style="margin:7px 0;">有了项目想法,能不能找到人一起交流?</li>
|
||||
</ul>
|
||||
<p style="margin:0 0 18px;">一个人摸索当然可以,但很多时候,别人的一句提醒,就能帮你少走不少弯路。</p>
|
||||
<p style="margin:0 0 26px;">所以,我准备建一个「南音源码库交流群」,把对源码、项目和技术感兴趣的朋友聚到一起。这里不追求人数多,只希望大家能真诚交流、互相帮助、一起进步。</p>
|
||||
|
||||
<h3 style="margin:30px 0 16px;padding-left:12px;border-left:5px solid #3978f6;color:#10235b;font-size:22px;line-height:1.4;">在群里可以聊什么?</h3>
|
||||
|
||||
<section style="margin:0 0 12px;padding:18px 20px;border-radius:12px;background:#f6f9ff;border:1px solid #e4edff;">
|
||||
<p style="margin:0 0 5px;color:#2563eb;font-size:17px;font-weight:800;">01 源码分享</p>
|
||||
<p style="margin:0;color:#455777;">分享值得学习和研究的开源项目、实用工具及项目资料,也欢迎大家交流自己的作品和使用体验。</p>
|
||||
</section>
|
||||
<section style="margin:0 0 12px;padding:18px 20px;border-radius:12px;background:#f8f6ff;border:1px solid #ebe5ff;">
|
||||
<p style="margin:0 0 5px;color:#6d4ee8;font-size:17px;font-weight:800;">02 技术交流</p>
|
||||
<p style="margin:0;color:#455777;">开发、部署、环境配置、报错排查、二次开发……遇到问题可以在群里讨论。会的朋友帮一把,不会的朋友一起研究。</p>
|
||||
</section>
|
||||
<section style="margin:0 0 12px;padding:18px 20px;border-radius:12px;background:#f6f9ff;border:1px solid #e4edff;">
|
||||
<p style="margin:0 0 5px;color:#2563eb;font-size:17px;font-weight:800;">03 项目互助</p>
|
||||
<p style="margin:0;color:#455777;">从需求分析、技术选型到功能实现和项目上线,都可以交流思路。毕业设计、个人项目和独立开发者项目也欢迎加入讨论。</p>
|
||||
</section>
|
||||
<section style="margin:0 0 24px;padding:18px 20px;border-radius:12px;background:#fff9ed;border:1px solid #ffebbd;">
|
||||
<p style="margin:0 0 5px;color:#d48513;font-size:17px;font-weight:800;">04 资源更新</p>
|
||||
<p style="margin:0;color:#455777;">「南音源码库」有新的源码、软件、教程或实用资源时,会在群里同步,方便大家及时了解。</p>
|
||||
</section>
|
||||
|
||||
<h3 style="margin:30px 0 14px;padding-left:12px;border-left:5px solid #7957ed;color:#10235b;font-size:22px;line-height:1.4;">适合这些朋友加入</h3>
|
||||
<ul style="margin:0 0 18px;padding-left:24px;color:#33466b;">
|
||||
<li style="margin:7px 0;">正在学习编程,想找项目练手的同学</li>
|
||||
<li style="margin:7px 0;">在做毕业设计、课程设计或个人项目的朋友</li>
|
||||
<li style="margin:7px 0;">喜欢研究源码、部署项目和二次开发的开发者</li>
|
||||
<li style="margin:7px 0;">独立开发者、技术博主和资源分享者</li>
|
||||
<li style="margin:7px 0;">愿意交流经验、分享工具、帮助他人的朋友</li>
|
||||
</ul>
|
||||
<p style="margin:0 0 25px;">无论你是刚入门,还是已经有多年开发经验,只要愿意友好交流,都欢迎加入。</p>
|
||||
|
||||
<h3 style="margin:30px 0 14px;padding-left:12px;border-left:5px solid #f1b334;color:#10235b;font-size:22px;line-height:1.4;">一个小小的群约定</h3>
|
||||
<p style="margin:0 0 10px;">为了让交流更舒服,希望大家共同遵守:</p>
|
||||
<ul style="margin:0 0 28px;padding-left:24px;color:#33466b;">
|
||||
<li style="margin:7px 0;">尊重他人,友好交流</li>
|
||||
<li style="margin:7px 0;">提问时尽量说明环境、报错信息和已经尝试过的方法</li>
|
||||
<li style="margin:7px 0;">不刷屏,不发无关广告,不频繁私聊骚扰群友</li>
|
||||
<li style="margin:7px 0;">尊重原创与版权,不传播来路不明或存在风险的内容</li>
|
||||
<li style="margin:7px 0;">分享不是义务,帮助值得感谢</li>
|
||||
</ul>
|
||||
|
||||
<section style="margin:32px 0 24px;padding:24px;border-radius:16px;background:linear-gradient(135deg,#186ef2,#7054e8);color:#fff;text-align:center;">
|
||||
<h3 style="margin:0 0 12px;font-size:24px;line-height:1.4;">如何加入?</h3>
|
||||
<p style="margin:0 0 16px;color:#eef5ff;">扫描下方二维码,或添加微信「【填写微信号】」<br>备注「源码群」即可。</p>
|
||||
<div style="margin:0 auto;padding:28px 15px;max-width:330px;border:2px dashed rgba(255,255,255,.75);border-radius:12px;background:rgba(255,255,255,.12);font-weight:700;">【在这里插入群二维码或个人微信二维码】</div>
|
||||
</section>
|
||||
|
||||
<p style="margin:0 0 16px;">希望这个群不只是一个资源群,更是一个能认真讨论问题、分享经验、认识同路人的技术交流空间。</p>
|
||||
<p style="margin:0 0 8px;">如果你也喜欢折腾源码、研究项目,欢迎加入「南音源码库交流群」。</p>
|
||||
<p style="margin:0;color:#2563eb;font-size:18px;font-weight:800;">我们群里见。</p>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<div id="copySource" aria-hidden="true" style="position:fixed;left:-10000px;top:0;width:720px;background:#fff;color:#333;"></div>
|
||||
|
||||
<script>
|
||||
const button = document.getElementById('copyButton');
|
||||
const status = document.getElementById('copyStatus');
|
||||
const copySource = document.getElementById('copySource');
|
||||
|
||||
// 仅使用 Quill 常见白名单标签,并避免 ul/li 间的空白文本节点。
|
||||
// 圆点使用普通字符,防止编辑器把换行解析成额外的空列表项。
|
||||
const quillHtml = [
|
||||
'<p><strong style="color:#2563eb;">南音源码库 · 社群招募</strong></p>',
|
||||
'<h2 style="color:#10235b;">南音源码库交流群,开放加入</h2>',
|
||||
'<p><strong>源码分享 | 技术交流 | 项目互助</strong></p>',
|
||||
'<p><br></p>',
|
||||
'<p>做「南音源码库」这段时间,陆续认识了不少喜欢折腾项目、研究源码的朋友。</p>',
|
||||
'<p>大家经常会问:</p>',
|
||||
'<p>• 某个项目该怎么部署?</p>',
|
||||
'<p>• 遇到报错应该从哪里排查?</p>',
|
||||
'<p>• 有没有适合学习、练手或二次开发的源码?</p>',
|
||||
'<p>• 有了项目想法,能不能找到人一起交流?</p>',
|
||||
'<p><br></p>',
|
||||
'<p>一个人摸索当然可以,但很多时候,别人的一句提醒,就能帮你少走不少弯路。</p>',
|
||||
'<p>所以,我准备建一个「南音源码库交流群」,把对源码、项目和技术感兴趣的朋友聚到一起。这里不追求人数多,只希望大家能真诚交流、互相帮助、一起进步。</p>',
|
||||
'<p><br></p>',
|
||||
'<h3 style="color:#2563eb;">在群里可以聊什么?</h3>',
|
||||
'<p><strong>01 源码分享</strong></p>',
|
||||
'<p>分享值得学习和研究的开源项目、实用工具及项目资料,也欢迎大家交流自己的作品和使用体验。</p>',
|
||||
'<p><strong>02 技术交流</strong></p>',
|
||||
'<p>开发、部署、环境配置、报错排查、二次开发……遇到问题可以在群里讨论。会的朋友帮一把,不会的朋友一起研究。</p>',
|
||||
'<p><strong>03 项目互助</strong></p>',
|
||||
'<p>从需求分析、技术选型到功能实现和项目上线,都可以交流思路。毕业设计、个人项目和独立开发者项目也欢迎加入讨论。</p>',
|
||||
'<p><strong>04 资源更新</strong></p>',
|
||||
'<p>「南音源码库」有新的源码、软件、教程或实用资源时,会在群里同步,方便大家及时了解。</p>',
|
||||
'<p><br></p>',
|
||||
'<h3 style="color:#6d4ee8;">适合这些朋友加入</h3>',
|
||||
'<p>• 正在学习编程,想找项目练手的同学</p>',
|
||||
'<p>• 在做毕业设计、课程设计或个人项目的朋友</p>',
|
||||
'<p>• 喜欢研究源码、部署项目和二次开发的开发者</p>',
|
||||
'<p>• 独立开发者、技术博主和资源分享者</p>',
|
||||
'<p>• 愿意交流经验、分享工具、帮助他人的朋友</p>',
|
||||
'<p>无论你是刚入门,还是已经有多年开发经验,只要愿意友好交流,都欢迎加入。</p>',
|
||||
'<p><br></p>',
|
||||
'<h3 style="color:#d48513;">一个小小的群约定</h3>',
|
||||
'<p>为了让交流更舒服,希望大家共同遵守:</p>',
|
||||
'<p>• 尊重他人,友好交流</p>',
|
||||
'<p>• 提问时尽量说明环境、报错信息和已经尝试过的方法</p>',
|
||||
'<p>• 不刷屏,不发无关广告,不频繁私聊骚扰群友</p>',
|
||||
'<p>• 尊重原创与版权,不传播来路不明或存在风险的内容</p>',
|
||||
'<p>• 分享不是义务,帮助值得感谢</p>',
|
||||
'<p><br></p>',
|
||||
'<h3 style="color:#2563eb;">如何加入?</h3>',
|
||||
'<blockquote>扫描下方二维码,或添加微信「【填写微信号】」,备注「源码群」即可。</blockquote>',
|
||||
'<p><strong>【在这里插入群二维码或个人微信二维码】</strong></p>',
|
||||
'<p><br></p>',
|
||||
'<p>希望这个群不只是一个资源群,更是一个能认真讨论问题、分享经验、认识同路人的技术交流空间。</p>',
|
||||
'<p>如果你也喜欢折腾源码、研究项目,欢迎加入「南音源码库交流群」。</p>',
|
||||
'<p><strong style="color:#2563eb;">我们群里见。</strong></p>'
|
||||
].join('');
|
||||
|
||||
copySource.innerHTML = quillHtml;
|
||||
|
||||
function fallbackCopy() {
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(copySource);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
const copied = document.execCommand('copy');
|
||||
selection.removeAllRanges();
|
||||
if (!copied) throw new Error('copy failed');
|
||||
}
|
||||
|
||||
button.addEventListener('click', async () => {
|
||||
try {
|
||||
const html = quillHtml;
|
||||
const text = copySource.innerText;
|
||||
if (navigator.clipboard && window.ClipboardItem) {
|
||||
const item = new ClipboardItem({
|
||||
'text/html': new Blob([html], { type: 'text/html' }),
|
||||
'text/plain': new Blob([text], { type: 'text/plain' })
|
||||
});
|
||||
await navigator.clipboard.write([item]);
|
||||
} else {
|
||||
fallbackCopy();
|
||||
}
|
||||
status.textContent = '已复制,可以粘贴到编辑器了';
|
||||
status.style.color = '#16815b';
|
||||
button.textContent = '复制成功';
|
||||
} catch (error) {
|
||||
try {
|
||||
fallbackCopy();
|
||||
status.textContent = '已复制,可以粘贴到编辑器了';
|
||||
status.style.color = '#16815b';
|
||||
button.textContent = '复制成功';
|
||||
} catch (fallbackError) {
|
||||
status.textContent = '自动复制失败,请拖选正文后按 Ctrl+C';
|
||||
status.style.color = '#c43b4c';
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
70
marketing/source-code-community-article.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 南音源码库交流群,开放加入
|
||||
|
||||
做「南音源码库」这段时间,陆续认识了不少喜欢折腾项目、研究源码的朋友。
|
||||
|
||||
大家经常会问:
|
||||
|
||||
- 某个项目该怎么部署?
|
||||
- 遇到报错应该从哪里排查?
|
||||
- 有没有适合学习、练手或二次开发的源码?
|
||||
- 有了项目想法,能不能找到人一起交流?
|
||||
|
||||
一个人摸索当然可以,但很多时候,别人的一句提醒,就能帮你少走不少弯路。
|
||||
|
||||
所以,我准备建一个「南音源码库交流群」,把对源码、项目和技术感兴趣的朋友聚到一起。这里不追求人数多,只希望大家能真诚交流、互相帮助、一起进步。
|
||||
|
||||
## 在群里可以聊什么?
|
||||
|
||||
### 1. 源码分享
|
||||
|
||||
分享值得学习和研究的开源项目、实用工具及项目资料,也欢迎大家交流自己的作品和使用体验。
|
||||
|
||||
### 2. 技术交流
|
||||
|
||||
开发、部署、环境配置、报错排查、二次开发……遇到问题可以在群里讨论。会的朋友帮一把,不会的朋友一起研究。
|
||||
|
||||
### 3. 项目互助
|
||||
|
||||
从需求分析、技术选型到功能实现和项目上线,都可以交流思路。毕业设计、个人项目和独立开发者项目也欢迎加入讨论。
|
||||
|
||||
### 4. 资源更新
|
||||
|
||||
「南音源码库」有新的源码、软件、教程或实用资源时,会在群里同步,方便大家及时了解。
|
||||
|
||||
## 适合这些朋友加入
|
||||
|
||||
- 正在学习编程,想找项目练手的同学
|
||||
- 在做毕业设计、课程设计或个人项目的朋友
|
||||
- 喜欢研究源码、部署项目和二次开发的开发者
|
||||
- 独立开发者、技术博主和资源分享者
|
||||
- 愿意交流经验、分享工具、帮助他人的朋友
|
||||
|
||||
无论你是刚入门,还是已经有多年开发经验,只要愿意友好交流,都欢迎加入。
|
||||
|
||||
## 一个小小的群约定
|
||||
|
||||
为了让交流更舒服,希望大家共同遵守:
|
||||
|
||||
- 尊重他人,友好交流
|
||||
- 提问时尽量说明环境、报错信息和已经尝试过的方法
|
||||
- 不刷屏,不发无关广告,不频繁私聊骚扰群友
|
||||
- 尊重原创与版权,不传播来路不明或存在风险的内容
|
||||
- 分享不是义务,帮助值得感谢
|
||||
|
||||
## 如何加入?
|
||||
|
||||
扫描下方二维码,或添加微信「【填写微信号】」,备注「源码群」即可。
|
||||
|
||||
> 【在这里插入群二维码或个人微信二维码】
|
||||
|
||||
希望这个群不只是一个资源群,更是一个能认真讨论问题、分享经验、认识同路人的技术交流空间。
|
||||
|
||||
如果你也喜欢折腾源码、研究项目,欢迎加入「南音源码库交流群」。
|
||||
|
||||
我们群里见。
|
||||
|
||||
---
|
||||
|
||||
**文章摘要:** 南音源码库交流群开放加入,聊源码、聊技术、聊项目。欢迎正在学习编程、准备毕业设计、喜欢二次开发或独立做项目的朋友一起交流成长。
|
||||
|
||||
**转发配文:** 建了一个南音源码库交流群,主要交流源码、开发技术、项目部署和问题排查。不论新手还是老手,只要愿意友好交流,都欢迎来一起玩。进群方式见文章末尾。
|
||||
BIN
marketing/source-code-community-cover-horizontal.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
marketing/source-code-community-cover.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
marketing/xiaohongshu-cover-creator.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
marketing/xiaohongshu-cover-safe.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
marketing/xiaohongshu-cover.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
41
marketing/xiaohongshu-custom-feature-copy.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 标题
|
||||
|
||||
有项目想法但不会开发?可以先看演示再决定
|
||||
|
||||
# 正文
|
||||
|
||||
最近给小程序新增了一个「项目定制」功能。
|
||||
|
||||
如果你有小程序、后台管理系统、课程设计或个人工具方面的想法,但自己不会开发,或者不想一开始就花很多钱,可以先提交需求让我看看。
|
||||
|
||||
提交时需要填写:
|
||||
|
||||
- 项目名称
|
||||
- 想使用的技术栈
|
||||
- 项目主要给谁使用
|
||||
- 希望解决什么问题
|
||||
- 需要哪些核心功能
|
||||
|
||||
提交需求会扣除99积分,主要是为了减少随意提交和无效需求。如果审核未通过,积分会自动退回;审核通过后,我会根据需求安排开发,并在小程序里持续更新进度。
|
||||
|
||||
项目开发完成后,可以先看演示效果,满意后再选择是否获取源码:
|
||||
|
||||
「获取源码」¥99
|
||||
交付完整源码,包含1次本地部署服务;项目之后仍可能在小程序内展示或发布。
|
||||
|
||||
「独家买断」¥299
|
||||
交付完整源码,包含1次本地部署服务和1次原需求范围内的集中修改;买断后项目不再发布到小程序。
|
||||
|
||||
两种方案都包含交付后30天内、原需求范围内的Bug修复。本地部署是协助在1台电脑上完成环境配置、数据库导入和项目启动,不包含服务器上线;新增功能需要另外评估。
|
||||
|
||||
整个流程就是:
|
||||
|
||||
提交需求 → 平台审核 → 查看开发进度 → 查看演示 → 满意后购买源码
|
||||
|
||||
比较适合需求明确、功能规模不大,想做课程设计、小程序或实用管理工具的朋友。
|
||||
|
||||
有想法可以去小程序「定制」页面提交。如有疑问,也可以联系南音。
|
||||
|
||||
# 话题
|
||||
|
||||
#程序员 #软件开发 #小程序开发 #管理系统 #项目定制 #源码 #课程设计 #毕业设计 #独立开发者 #技术分享
|
||||
BIN
marketing/xiaohongshu-custom-feature-cover-v2.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
marketing/xiaohongshu-custom-feature-cover.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
23
pages.json
@@ -45,9 +45,8 @@
|
||||
"path" : "pages/tool/index",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleText" : "项目定制",
|
||||
"enablePullDownRefresh" : false
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -139,6 +138,22 @@
|
||||
"enablePullDownRefresh" : false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/mine/custom_requests",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "我的定制",
|
||||
"enablePullDownRefresh" : true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/mine/custom_request_detail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "定制详情",
|
||||
"enablePullDownRefresh" : true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/mine/exchange_records",
|
||||
"style" :
|
||||
@@ -207,7 +222,7 @@
|
||||
"pagePath": "pages/tool/index",
|
||||
"iconPath": "static/tabar/follow.png",
|
||||
"selectedIconPath": "static/tabar/follow_1.png",
|
||||
"text": "宝库"
|
||||
"text": "定制"
|
||||
}, {
|
||||
"pagePath": "pages/mine/index",
|
||||
"iconPath": "static/tabar/my.png",
|
||||
|
||||
165
pages/mine/custom_request_detail.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<view class="detail-root">
|
||||
<view v-if="loading" class="detail-loading"><text class="cuIcon-loading2 loading-icon"></text>正在加载...</view>
|
||||
|
||||
<view v-else-if="loadError" class="error-state">
|
||||
<text class="cuIcon-warn error-icon"></text>
|
||||
<view class="error-title">详情加载失败</view>
|
||||
<view class="error-desc">请检查网络后重新加载</view>
|
||||
<button class="retry-button" @tap="loadDetail">重新加载</button>
|
||||
</view>
|
||||
|
||||
<view v-else-if="detail.id" class="detail-page">
|
||||
<view class="status-card" :class="statusClass">
|
||||
<view class="status-icon"><text :class="statusIconClass"></text></view>
|
||||
<view class="status-content">
|
||||
<view class="status-title">{{ statusText }}</view>
|
||||
<view class="status-desc">{{ statusDisplayText }}</view>
|
||||
<view v-if="showStatusTime" class="status-time">更新于 {{ detail.updateTime || detail.createTime }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-card contact-card">
|
||||
<view class="contact-main">
|
||||
<view class="contact-icon"><text class="cuIcon-weixin"></text></view>
|
||||
<view class="contact-content">
|
||||
<view class="contact-title">如有疑问,请联系南音</view>
|
||||
<view class="contact-wechat">微信号:{{ contactWechat }}</view>
|
||||
</view>
|
||||
<button class="copy-button" @tap="copyWechat">复制微信号</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-card">
|
||||
<view class="card-title"><text class="cuIcon-titles card-title-icon"></text>项目需求</view>
|
||||
<view class="info-row"><text class="info-label">项目名称</text><text class="info-value project-value">{{ detail.projectName }}</text></view>
|
||||
<view class="info-row"><text class="info-label">技术栈</text><text class="info-value tech-stack-value">{{ detail.techStackName || '-' }}</text></view>
|
||||
<view class="info-row requirement-row"><text class="info-label">项目需求</text><text class="info-value requirement-value">{{ detail.requirementContent }}</text></view>
|
||||
</view>
|
||||
|
||||
<view class="content-card record-card">
|
||||
<view class="card-title"><text class="cuIcon-titles card-title-icon"></text>提交记录</view>
|
||||
<view class="info-row"><text class="info-label">需求单号</text><text class="info-value">{{ detail.requestNo }}</text></view>
|
||||
<view class="info-row"><text class="info-label">提交时间</text><text class="info-value">{{ detail.createTime || '-' }}</text></view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">积分</text>
|
||||
<view class="info-value integral-info">
|
||||
<text class="point-text">{{ detail.pointAmount }}积分</text>
|
||||
<text class="info-separator">·</text>
|
||||
<text :class="pointStatusClass">{{ pointStatusText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMyCustomRequest } from '@/api/app/index.js'
|
||||
import { getCustomRequestStatus } from '@/utils/customRequest.js'
|
||||
import config from '@/config'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
id: null,
|
||||
detail: {},
|
||||
loading: false,
|
||||
loadError: false,
|
||||
contactWechat: config.appInfo.contactWechat
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
statusValue() { return Number(this.detail.status) },
|
||||
statusConfig() { return getCustomRequestStatus(this.statusValue) },
|
||||
isRejected() { return this.statusValue === 5 },
|
||||
isRefunded() { return Number(this.detail.pointStatus) === 1 },
|
||||
statusClass() { return this.statusConfig.className },
|
||||
statusIconClass() { return this.statusConfig.icon },
|
||||
statusText() { return this.statusConfig.text },
|
||||
statusDesc() { return this.statusConfig.description },
|
||||
statusDisplayText() {
|
||||
if (this.isRejected) return this.detail.rejectReason ? '未通过原因:' + this.detail.rejectReason : this.statusDesc
|
||||
return this.detail.progressNote || this.statusDesc
|
||||
},
|
||||
showStatusTime() { return !!(this.detail.updateTime || this.detail.createTime) },
|
||||
pointStatusClass() { return this.isRefunded ? 'refund-text' : '' },
|
||||
pointStatusText() { return this.isRefunded ? '已退回' : '已扣除' }
|
||||
},
|
||||
onLoad(options) { this.id = options.id; this.loadDetail() },
|
||||
onPullDownRefresh() { this.loadDetail() },
|
||||
methods: {
|
||||
copyWechat() {
|
||||
uni.setClipboardData({
|
||||
data: this.contactWechat,
|
||||
success: () => uni.showToast({ title: '微信号已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
loadDetail() {
|
||||
if (!this.id || this.loading) return
|
||||
this.loading = true
|
||||
this.loadError = false
|
||||
getMyCustomRequest(this.id).then(response => {
|
||||
this.detail = response.data || {}
|
||||
}).catch(() => {
|
||||
this.loadError = true
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page { min-height: 100%; background: #f7f7f7; }
|
||||
.detail-root { min-height: 100vh; }
|
||||
.detail-page { padding: 28rpx; }
|
||||
.status-card, .content-card { border-radius: 20rpx; background: #fff; box-shadow: 0 6rpx 18rpx rgba(50, 50, 50, .04); }
|
||||
.status-card { display: flex; align-items: center; padding: 30rpx; border-left: 7rpx solid #ff9700; }
|
||||
.status-reviewing, .status-developing { border-left-color: #0081ff; }
|
||||
.status-accepted { border-left-color: #1cbbb4; }
|
||||
.status-completed { border-left-color: #20a05a; }
|
||||
.status-rejected { border-left-color: #e54d42; }
|
||||
.status-unknown { border-left-color: #999; }
|
||||
.status-icon { display: flex; flex-shrink: 0; align-items: center; justify-content: center; width: 76rpx; height: 76rpx; margin-right: 22rpx; border-radius: 50%; font-size: 40rpx; color: #0081ff; background: #edf7ff; }
|
||||
.status-pending .status-icon { color: #ff9700; background: #fff6e8; }
|
||||
.status-accepted .status-icon { color: #1cbbb4; background: #eaf9f7; }
|
||||
.status-completed .status-icon { color: #20a05a; background: #ebf8f1; }
|
||||
.status-rejected .status-icon { color: #e54d42; background: #fff0ef; }
|
||||
.status-content { min-width: 0; }
|
||||
.status-title { font-size: 34rpx; font-weight: 600; color: #222; }
|
||||
.status-desc { margin-top: 10rpx; font-size: 24rpx; line-height: 1.55; color: #888; }
|
||||
.status-time { margin-top: 12rpx; font-size: 20rpx; line-height: 1.4; color: #b1b1b1; }
|
||||
.content-card { margin-top: 24rpx; padding: 28rpx; }
|
||||
.card-title { display: flex; align-items: center; margin-bottom: 20rpx; font-size: 31rpx; font-weight: 600; color: #222; }
|
||||
.card-title-icon { margin-right: 4rpx; font-size: 38rpx; color: #0081ff; }
|
||||
.info-row { display: flex; align-items: flex-start; justify-content: space-between; padding: 17rpx 0; font-size: 25rpx; border-bottom: 1rpx solid #eee; }
|
||||
.info-row:last-child { border-bottom: 0; }
|
||||
.info-label { color: #999; }
|
||||
.info-value { max-width: 470rpx; text-align: right; color: #555; }
|
||||
.integral-info { display: flex; align-items: center; justify-content: flex-end; }
|
||||
.info-separator { margin: 0 9rpx; color: #ccc; }
|
||||
.point-text { color: #ff9700; }
|
||||
.refund-text { color: #20a05a; }
|
||||
.project-value { font-weight: 500; color: #333; }
|
||||
.tech-stack-value { color: #3976a8; }
|
||||
.requirement-row { min-height: 70rpx; }
|
||||
.requirement-value { line-height: 1.65; color: #666; white-space: pre-wrap; word-break: break-all; }
|
||||
.contact-card { border: 1rpx solid #d8f1e1; background: linear-gradient(135deg, #f4fff7, #fff); }
|
||||
.contact-main { display: flex; align-items: center; }
|
||||
.contact-icon { display: flex; flex-shrink: 0; align-items: center; justify-content: center; width: 72rpx; height: 72rpx; margin-right: 18rpx; border-radius: 50%; font-size: 40rpx; color: #fff; background: #20b85a; }
|
||||
.contact-content { flex: 1; min-width: 0; }
|
||||
.contact-title { font-size: 28rpx; font-weight: 600; color: #27352c; }
|
||||
.contact-wechat { margin-top: 7rpx; font-size: 23rpx; color: #7b887f; }
|
||||
.copy-button { flex-shrink: 0; height: 62rpx; margin: 0 0 0 16rpx; padding: 0 20rpx; border: 0; border-radius: 10rpx; font-size: 23rpx; line-height: 62rpx; color: #fff; background: #20b85a; }
|
||||
.copy-button::after { border: 0; }
|
||||
.detail-loading, .error-state { padding: 220rpx 60rpx 0; text-align: center; font-size: 25rpx; color: #999; }
|
||||
.loading-icon { display: inline-block; margin-right: 10rpx; }
|
||||
.error-icon { font-size: 90rpx; color: #c8cfdb; }
|
||||
.error-title { margin-top: 20rpx; font-size: 31rpx; color: #666; }
|
||||
.error-desc { margin-top: 12rpx; font-size: 25rpx; color: #aaa; }
|
||||
.retry-button { width: 280rpx; height: 76rpx; margin-top: 30rpx; border-radius: 12rpx; font-size: 27rpx; line-height: 76rpx; color: #fff; background: #0081ff; }
|
||||
.retry-button::after { border: 0; }
|
||||
</style>
|
||||
146
pages/mine/custom_requests.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<view class="request-page">
|
||||
<view v-if="dataList.length" class="request-list">
|
||||
<view class="section-title"><text class="cuIcon-titles section-icon"></text>定制记录</view>
|
||||
<view v-for="item in dataList" :key="item.id" class="request-card" @tap="goDetail(item.id)">
|
||||
<view class="request-head">
|
||||
<text class="request-no">需求单号:{{ item.requestNo }}</text>
|
||||
<text class="request-status" :class="item.statusClass">{{ item.statusText }}</text>
|
||||
</view>
|
||||
<view class="project-line">
|
||||
<view class="project-name">{{ item.projectName }}</view>
|
||||
<view v-if="item.techStackName" class="tech-stack-tag"><text class="cuIcon-settingsfill tech-stack-icon"></text><text class="tech-stack-name">{{ item.techStackName }}</text></view>
|
||||
</view>
|
||||
<view class="requirement-text">{{ item.requirementContent }}</view>
|
||||
<view v-if="item.progressNote && !item.isRejected" class="progress-note">
|
||||
<text class="cuIcon-timefill note-icon"></text><text class="note-content">{{ item.progressNote }}</text>
|
||||
</view>
|
||||
<view v-if="item.isRejected && item.rejectReason" class="reject-note">
|
||||
<text class="cuIcon-infofill note-icon"></text><text class="note-content">未通过原因:{{ item.rejectReason }}</text>
|
||||
</view>
|
||||
<view class="request-footer">
|
||||
<text>{{ item.updateTime || item.createTime }}</text>
|
||||
<text class="detail-link">查看详情 <text class="cuIcon-right"></text></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!loading && !loadError" class="empty-state">
|
||||
<image class="empty-image" src="https://img.yidaima.cn/feast/nodata.svg" mode="aspectFit"></image>
|
||||
<view class="empty-title">还没有定制需求</view>
|
||||
<view class="empty-desc">提交项目想法后,可以在这里查看审核和开发进度。</view>
|
||||
<button class="empty-button" @tap="goSubmit">去提交需求</button>
|
||||
</view>
|
||||
|
||||
<view v-if="!loading && loadError" class="error-state">
|
||||
<text class="cuIcon-warn error-icon"></text>
|
||||
<view class="error-title">加载失败</view>
|
||||
<view class="error-desc">请检查网络后重新加载</view>
|
||||
<button class="retry-button" @tap="retryLoad">重新加载</button>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="loading-text"><text class="cuIcon-loading2 loading-icon"></text>正在加载...</view>
|
||||
<view v-if="dataList.length && !hasMore" class="bottom-text">没有更多了</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listMyCustomRequests } from '@/api/app/index.js'
|
||||
import { getCustomRequestStatus } from '@/utils/customRequest.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
loadError: false,
|
||||
dataList: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10 }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasMore() { return this.dataList.length < this.total }
|
||||
},
|
||||
onLoad() { this.loadList(true) },
|
||||
onShow() { if (this.dataList.length) this.loadList(true) },
|
||||
onPullDownRefresh() { this.loadList(true) },
|
||||
onReachBottom() {
|
||||
if (!this.loading && this.hasMore) {
|
||||
this.queryParams.pageNum++
|
||||
this.loadList(false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
decorateItem(item) {
|
||||
const status = Number(item.status)
|
||||
const statusConfig = getCustomRequestStatus(status)
|
||||
return Object.assign({}, item, {
|
||||
statusClass: statusConfig.className,
|
||||
statusText: statusConfig.text,
|
||||
isRejected: status === 5
|
||||
})
|
||||
},
|
||||
loadList(reset) {
|
||||
if (this.loading) return
|
||||
if (reset) this.queryParams.pageNum = 1
|
||||
this.loading = true
|
||||
this.loadError = false
|
||||
listMyCustomRequests(this.queryParams).then(response => {
|
||||
const rows = (response.rows || []).map(this.decorateItem)
|
||||
this.dataList = reset ? rows : this.dataList.concat(rows)
|
||||
this.total = Number(response.total || 0)
|
||||
}).catch(() => {
|
||||
this.loadError = true
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
},
|
||||
retryLoad() { this.loadList(true) },
|
||||
goDetail(id) { this.$tab.navigateTo('/pages/mine/custom_request_detail?id=' + id) },
|
||||
goSubmit() { uni.switchTab({ url: '/pages/tool/index' }) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page { min-height: 100%; background: #f7f7f7; }
|
||||
.request-page { min-height: 100vh; }
|
||||
.request-list { padding: 28rpx; }
|
||||
.section-title { margin: 4rpx 2rpx 24rpx; font-size: 35rpx; font-weight: 600; color: #222; }
|
||||
.section-icon { margin-right: 4rpx; font-size: 42rpx; color: #0081ff; }
|
||||
.request-card { margin-bottom: 24rpx; padding: 28rpx; border-radius: 20rpx; background: #fff; box-shadow: 0 6rpx 18rpx rgba(50, 50, 50, .04); }
|
||||
.request-head, .request-footer { display: flex; align-items: center; justify-content: space-between; }
|
||||
.request-head { padding-bottom: 20rpx; border-bottom: 1rpx solid #eee; }
|
||||
.request-no { max-width: 500rpx; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 23rpx; color: #999; }
|
||||
.request-status { flex-shrink: 0; margin-left: 14rpx; padding: 6rpx 12rpx; border-radius: 999rpx; font-size: 22rpx; }
|
||||
.status-pending { color: #e98500; background: #fff6e8; }
|
||||
.status-reviewing, .status-developing { color: #0081ff; background: #edf7ff; }
|
||||
.status-accepted { color: #149d96; background: #eaf9f7; }
|
||||
.status-completed { color: #178c4d; background: #ebf8f1; }
|
||||
.status-rejected { color: #d8473d; background: #fff0ef; }
|
||||
.status-unknown { color: #777; background: #f2f2f2; }
|
||||
.project-line { display: flex; align-items: center; min-width: 0; margin-top: 22rpx; }
|
||||
.project-name { flex: 1; min-width: 0; overflow: hidden; font-size: 32rpx; font-weight: 600; line-height: 1.5; color: #242424; white-space: nowrap; text-overflow: ellipsis; }
|
||||
.tech-stack-tag { display: flex; flex-shrink: 0; align-items: center; max-width: 250rpx; margin-left: 14rpx; padding: 6rpx 12rpx; border-radius: 8rpx; font-size: 21rpx; color: #3976a8; background: #edf7ff; }
|
||||
.tech-stack-icon { flex-shrink: 0; margin-right: 7rpx; }
|
||||
.tech-stack-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||||
.requirement-text { margin-top: 14rpx; overflow: hidden; font-size: 26rpx; line-height: 1.65; color: #666; white-space: nowrap; text-overflow: ellipsis; }
|
||||
.progress-note, .reject-note { display: flex; align-items: flex-start; margin-top: 20rpx; padding: 16rpx 18rpx; border-radius: 12rpx; font-size: 24rpx; line-height: 1.55; }
|
||||
.progress-note { color: #3976a8; background: #edf7ff; }
|
||||
.reject-note { color: #b54b43; background: #fff1f0; }
|
||||
.note-icon { flex-shrink: 0; margin: 2rpx 10rpx 0 0; }
|
||||
.note-content { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||||
.request-footer { margin-top: 22rpx; padding-top: 20rpx; border-top: 1rpx solid #eee; font-size: 22rpx; color: #aaa; }
|
||||
.detail-link { color: #0081ff; }
|
||||
.empty-state, .error-state { padding: 170rpx 60rpx 0; text-align: center; }
|
||||
.empty-image { width: 400rpx; height: 200rpx; }
|
||||
.empty-title, .error-title { margin-top: 18rpx; font-size: 31rpx; color: #666; }
|
||||
.empty-desc, .error-desc { margin-top: 12rpx; font-size: 25rpx; line-height: 1.6; color: #aaa; }
|
||||
.empty-button, .retry-button { width: 280rpx; height: 76rpx; margin-top: 30rpx; border-radius: 12rpx; font-size: 27rpx; line-height: 76rpx; color: #fff; background: #0081ff; }
|
||||
.empty-button::after { border: 0; }
|
||||
.retry-button::after { border: 0; }
|
||||
.error-icon { font-size: 90rpx; color: #c8cfdb; }
|
||||
.loading-icon { display: inline-block; margin-right: 10rpx; }
|
||||
.loading-text, .bottom-text { padding: 40rpx 0 60rpx; text-align: center; font-size: 24rpx; color: #aaa; }
|
||||
</style>
|
||||
@@ -79,6 +79,16 @@
|
||||
|
||||
<!-- 功能列表 -->
|
||||
<view class="metergasis">
|
||||
<view class="metergasis-li" hover-class="fengrui-li-hover" @tap="customRequests()">
|
||||
<view class="metergasis-li-img custom-request-icon flex justify-center align-center">
|
||||
<text class="cuIcon-writefill"></text>
|
||||
</view>
|
||||
<view class="metergasis-li-h">我的定制</view>
|
||||
<text class="metergasis-li-h2">查看需求审核及开发进度</text>
|
||||
<view class="metergasis-li-rgth">
|
||||
<image class="blogui-img" src="https://img.yidaima.cn/feast/more.svg" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="metergasis-li" hover-class="fengrui-li-hover" @tap="Signin()">
|
||||
<view class="metergasis-li-img">
|
||||
<image class="blogui-img" src="https://img.yidaima.cn/feast/qiandao.svg" mode="aspectFill">
|
||||
@@ -336,6 +346,19 @@
|
||||
this.$tab.navigateTo('/pages/mine/virtual_orders')
|
||||
}
|
||||
},
|
||||
customRequests(){
|
||||
var that = this
|
||||
if (!this.userid) {
|
||||
that.$refs.uToast.show({
|
||||
type: 'success',
|
||||
title: '',
|
||||
message: '请先授权登录',
|
||||
icon: false
|
||||
})
|
||||
}else{
|
||||
this.$tab.navigateTo('/pages/mine/custom_requests')
|
||||
}
|
||||
},
|
||||
Signin() {
|
||||
var that = this
|
||||
if (!this.userid) {
|
||||
@@ -478,6 +501,11 @@
|
||||
width: 49%;
|
||||
background-color: white;
|
||||
}
|
||||
.custom-request-icon {
|
||||
background-color: #eaf5ff;
|
||||
color: #0081ff;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
/* 列表没有数据 */
|
||||
.no-list-data {
|
||||
text-align: center;
|
||||
|
||||
@@ -1,77 +1,277 @@
|
||||
<template name="basics">
|
||||
<view>
|
||||
<scroll-view scroll-y class="page">
|
||||
<view class="response"
|
||||
style="height: 250upx;line-height: 400upx;font-size: 32rpx;font-weight: bold;text-align: center;">
|
||||
敬请期待更多类别</view>
|
||||
<view class="nav-list">
|
||||
<navigator hover-class="none" :url="'/pages/tool/' + item.name" class="nav-li" navigateTo :class="'bg-'+item.color"
|
||||
:style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" v-for="(item,index) in elements" :key="index">
|
||||
<view class="mt30 grid text-center bg-white" style="flex-direction: column; align-items: center;">
|
||||
<view class=" flex justify-center align-center" style="width: 100upx;height: 100upx;">
|
||||
<image class="grid-svg" style="width: 100%;height: 100%;" :src="item.cuIcon" mode="">
|
||||
</image>
|
||||
</view>
|
||||
<view style="font-weight: bold;margin-top: 16rpx;">{{item.title}}</view>
|
||||
<view style="font-size: 24rpx;color: #b1b1b1;">{{item.name}}</view>
|
||||
<template>
|
||||
<view class="custom-page">
|
||||
<view class="custom-content">
|
||||
<view class="service-card">
|
||||
<view class="service-head">
|
||||
<view class="service-icon"><text class="cuIcon-writefill"></text></view>
|
||||
<view class="service-content">
|
||||
<view class="service-title">提交项目需求</view>
|
||||
<view class="service-desc">填写名称和核心需求,平台审核后进入开发流程</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
<view class="flow-row">
|
||||
<view class="flow-item"><text class="flow-number">1</text><text>提交需求</text></view>
|
||||
<text class="flow-line"></text>
|
||||
<view class="flow-item"><text class="flow-number">2</text><text>平台审核</text></view>
|
||||
<text class="flow-line"></text>
|
||||
<view class="flow-item"><text class="flow-number">3</text><text>查看进度</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-tabbar-height"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="form-card">
|
||||
<view class="form-title-row">
|
||||
<view class="form-title"><text class="cuIcon-titles title-icon"></text>填写需求</view>
|
||||
</view>
|
||||
|
||||
<view class="field-label">项目名称<text class="required">*</text></view>
|
||||
<view class="input-box">
|
||||
<input v-model="form.projectName" maxlength="30" placeholder="例如:校园二手交易小程序" placeholder-class="input-placeholder" />
|
||||
<text class="word-count">{{ projectNameLength }}/30</text>
|
||||
</view>
|
||||
|
||||
<view class="field-label field-label-space">技术栈<text class="required">*</text></view>
|
||||
<view v-if="techStacks.length" class="tech-stack-options">
|
||||
<view
|
||||
v-for="item in techStacks"
|
||||
:key="item.id"
|
||||
class="tech-stack-option"
|
||||
:class="{'tech-stack-selected': form.techStackId === item.id}"
|
||||
@tap="selectTechStack(item.id)"
|
||||
>{{ item.name }}</view>
|
||||
</view>
|
||||
<view v-else class="tech-stack-empty">{{ techStackLoading ? '正在加载技术栈...' : '暂无可选技术栈,请联系南音' }}</view>
|
||||
|
||||
<view class="field-label field-label-space">项目需求<text class="required">*</text></view>
|
||||
<view class="textarea-box">
|
||||
<textarea v-model="form.requirementContent" maxlength="500" placeholder="请写清楚谁来使用、主要解决什么问题,以及希望有哪些核心功能。" placeholder-class="input-placeholder" />
|
||||
<text class="word-count textarea-count">{{ requirementLength }}/500</text>
|
||||
</view>
|
||||
|
||||
<view class="price-card">
|
||||
<view class="price-header">
|
||||
<view class="price-title"><text class="cuIcon-moneybagfill price-title-icon"></text>定制费用说明</view>
|
||||
<view class="price-stage">先看演示再购买</view>
|
||||
</view>
|
||||
<view class="price-item">
|
||||
<view class="price-content">
|
||||
<view class="price-name">提交需求</view>
|
||||
<view class="price-desc">审核未通过自动退回,审核通过后不退</view>
|
||||
</view>
|
||||
<view class="price-value points-value">99<text>积分</text></view>
|
||||
</view>
|
||||
<view class="price-item">
|
||||
<view class="price-content">
|
||||
<view class="price-name">获取源码</view>
|
||||
<view class="price-desc">交付完整源码,含1次本地部署服务;项目可能继续在小程序内发布</view>
|
||||
</view>
|
||||
<view class="price-value"><text>¥</text>99</view>
|
||||
</view>
|
||||
<view class="price-item">
|
||||
<view class="price-content">
|
||||
<view class="price-name">独家买断</view>
|
||||
<view class="price-desc">交付完整源码,含1次本地部署服务和1次集中修改;项目不再发布到小程序</view>
|
||||
</view>
|
||||
<view class="price-value"><text>¥</text>299</view>
|
||||
</view>
|
||||
<view class="price-tip"><text class="cuIcon-infofill"></text>项目开发完成后先查看演示,满意后再选择源码交付方式</view>
|
||||
<view class="service-note">
|
||||
<view class="service-note-title">服务说明</view>
|
||||
<view>两种方案均包含交付后30天内原需求范围内的Bug修复。本地部署是指协助在1台电脑上完成运行环境配置、数据库导入及项目启动,不包含服务器上线。修改服务仅限原需求范围内调整,新增功能需另行评估。</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rule-box">
|
||||
<text class="cuIcon-info rule-icon"></text>
|
||||
<view>提交时直接扣除99积分;审核不通过将自动退回,审核通过后不再退还。</view>
|
||||
</view>
|
||||
|
||||
<button class="submit-button" :disabled="submitting" @tap="handleSubmit">
|
||||
{{ submitting ? '正在提交...' : '提交需求 · 99积分' }}
|
||||
</button>
|
||||
<view class="agreement">点击提交即表示你已了解积分扣除与退回规则</view>
|
||||
</view>
|
||||
|
||||
<view class="my-custom-entry" @tap="goMyCustom">
|
||||
<view class="entry-left">
|
||||
<text class="cuIcon-form entry-icon"></text>
|
||||
<view>
|
||||
<view class="entry-title">我的定制</view>
|
||||
<view class="entry-desc">查看需求审核及开发进度</view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="cuIcon-right entry-arrow"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="cu-tabbar-height"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createCustomRequest, getUser, listCustomTechStacks } from '@/api/app/index.js'
|
||||
|
||||
export default {
|
||||
name: "basics",
|
||||
data() {
|
||||
return {
|
||||
elements: [{
|
||||
title: '资源库',
|
||||
name: 'resource',
|
||||
color: 'cyan',
|
||||
cuIcon: 'https://img.yidaima.cn/zyk.png'
|
||||
},
|
||||
{
|
||||
title: '手机软件',
|
||||
name: 'phone',
|
||||
color: 'orange',
|
||||
cuIcon: 'https://img.yidaima.cn/sjrj.png'
|
||||
},
|
||||
{
|
||||
title: '电脑软件 ',
|
||||
name: 'software',
|
||||
color: 'mauve',
|
||||
cuIcon: 'https://img.yidaima.cn/dnrj.png'
|
||||
}
|
||||
],
|
||||
};
|
||||
submitPoints: 99,
|
||||
userId: null,
|
||||
integral: 0,
|
||||
submitting: false,
|
||||
techStackLoading: false,
|
||||
techStacks: [],
|
||||
form: { projectName: '', techStackId: null, requirementContent: '' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
projectNameLength() { return (this.form.projectName || '').length },
|
||||
requirementLength() { return (this.form.requirementContent || '').length }
|
||||
},
|
||||
onShow() {
|
||||
console.log("success")
|
||||
const userInfo = uni.getStorageSync('userInfo') || {}
|
||||
this.userId = userInfo.userId || null
|
||||
if (this.userId) this.loadIntegral()
|
||||
else this.integral = 0
|
||||
this.loadTechStacks()
|
||||
},
|
||||
methods: {
|
||||
loadTechStacks() {
|
||||
this.techStackLoading = true
|
||||
listCustomTechStacks().then(response => {
|
||||
this.techStacks = response.data || []
|
||||
if (!this.techStacks.some(item => item.id === this.form.techStackId)) this.form.techStackId = null
|
||||
}).finally(() => { this.techStackLoading = false })
|
||||
},
|
||||
selectTechStack(id) { this.form.techStackId = id },
|
||||
loadIntegral() {
|
||||
getUser(this.userId).then(response => {
|
||||
this.integral = response && response.user ? Number(response.user.integral || 0) : 0
|
||||
})
|
||||
},
|
||||
goMyCustom() {
|
||||
if (this.ensureLogin()) this.$tab.navigateTo('/pages/mine/custom_requests')
|
||||
},
|
||||
ensureLogin() {
|
||||
if (this.userId) return true
|
||||
uni.showModal({
|
||||
title: '请先登录',
|
||||
content: '登录后才能提交和查看定制需求。',
|
||||
confirmText: '去登录',
|
||||
success: res => { if (res.confirm) uni.switchTab({ url: '/pages/mine/index' }) }
|
||||
})
|
||||
return false
|
||||
},
|
||||
validateForm() {
|
||||
const projectName = (this.form.projectName || '').trim()
|
||||
const requirementContent = (this.form.requirementContent || '').trim()
|
||||
if (projectName.length < 2) {
|
||||
uni.showToast({ title: '项目名称至少填写2个字', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!this.form.techStackId) {
|
||||
uni.showToast({ title: '请选择技术栈', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (requirementContent.length < 20) {
|
||||
uni.showToast({ title: '项目需求至少填写20个字', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
this.form.projectName = projectName
|
||||
this.form.requirementContent = requirementContent
|
||||
return true
|
||||
},
|
||||
handleSubmit() {
|
||||
if (this.submitting || !this.ensureLogin() || !this.validateForm()) return
|
||||
if (this.integral < this.submitPoints) {
|
||||
uni.showModal({
|
||||
title: '积分不足',
|
||||
content: '当前有' + this.integral + '积分,提交需求需要99积分。',
|
||||
confirmText: '去获取',
|
||||
success: res => { if (res.confirm) uni.switchTab({ url: '/pages/mine/index' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
this.submitRequest()
|
||||
},
|
||||
submitRequest() {
|
||||
this.submitting = true
|
||||
createCustomRequest(this.form).then(response => {
|
||||
this.integral = Math.max(this.integral - this.submitPoints, 0)
|
||||
this.form.projectName = ''
|
||||
this.form.techStackId = null
|
||||
this.form.requirementContent = ''
|
||||
uni.showModal({
|
||||
title: '提交成功',
|
||||
content: '需求单号:' + (response.data ? response.data.requestNo : '') + ',可在“我的定制”查看状态。',
|
||||
showCancel: false,
|
||||
confirmText: '查看需求',
|
||||
success: () => { this.$tab.navigateTo('/pages/mine/custom_requests') }
|
||||
})
|
||||
}).finally(() => { this.submitting = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
page {
|
||||
background-color: #F5F5F5;;
|
||||
}
|
||||
.nav-li {
|
||||
/* padding: 30upx; */
|
||||
border-radius: 24upx;
|
||||
width: 30%;
|
||||
margin: 0 1% 20upx;
|
||||
/* background-image: url(https://i.imgtg.com/2022/12/15/Dsef6.jpg); */
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
background-color: #FFFFFF;
|
||||
z-index: 1;
|
||||
}
|
||||
page { min-height: 100%; background: #f7f7f7; }
|
||||
.custom-page { min-height: 100vh; }
|
||||
.custom-content { padding: 28rpx 28rpx 10rpx; }
|
||||
.service-card { padding: 28rpx; border: 1rpx solid #d9efff; border-radius: 20rpx; background: linear-gradient(135deg, #f0f9ff, #e7f5ff); }
|
||||
.service-head { display: flex; align-items: center; }
|
||||
.service-icon { display: flex; flex-shrink: 0; align-items: center; justify-content: center; width: 82rpx; height: 82rpx; border-radius: 50%; font-size: 42rpx; color: #fff; background: linear-gradient(135deg, #0081ff, #60c2ff); }
|
||||
.service-content { flex: 1; min-width: 0; margin-left: 20rpx; }
|
||||
.service-title { font-size: 34rpx; font-weight: 600; color: #222; }
|
||||
.service-desc { margin-top: 8rpx; font-size: 23rpx; line-height: 1.55; color: #788895; }
|
||||
.flow-row { display: flex; align-items: center; margin-top: 26rpx; padding-top: 22rpx; border-top: 1rpx solid rgba(0, 129, 255, .12); }
|
||||
.flow-item { display: flex; align-items: center; font-size: 23rpx; color: #596c7c; white-space: nowrap; }
|
||||
.flow-number { display: flex; align-items: center; justify-content: center; width: 36rpx; height: 36rpx; margin-right: 8rpx; border-radius: 50%; font-size: 20rpx; color: #0081ff; background: #fff; }
|
||||
.flow-line { flex: 1; height: 1rpx; margin: 0 12rpx; background: #c5e5fb; }
|
||||
.price-card { margin-top: 30rpx; padding: 24rpx; border: 1rpx solid #edf0f2; border-radius: 16rpx; background: #fafbfc; }
|
||||
.price-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; }
|
||||
.price-title { display: flex; align-items: center; font-size: 30rpx; font-weight: 600; color: #222; }
|
||||
.price-title-icon { margin-right: 12rpx; font-size: 34rpx; color: #ff9700; }
|
||||
.price-stage { padding: 6rpx 12rpx; border-radius: 8rpx; font-size: 20rpx; color: #0081ff; background: #edf7ff; }
|
||||
.price-item { display: flex; align-items: center; min-height: 94rpx; border-bottom: 1rpx solid #f1f1f1; }
|
||||
.price-content { flex: 1; min-width: 0; padding: 16rpx 20rpx 16rpx 0; }
|
||||
.price-name { font-size: 27rpx; font-weight: 500; color: #333; }
|
||||
.price-desc { margin-top: 6rpx; font-size: 21rpx; line-height: 1.45; color: #999; }
|
||||
.price-value { flex-shrink: 0; font-size: 34rpx; font-weight: 600; color: #e76f1a; }
|
||||
.price-value text { margin-right: 2rpx; font-size: 22rpx; font-weight: 500; }
|
||||
.points-value { color: #0081ff; }
|
||||
.points-value text { margin: 0 0 0 5rpx; }
|
||||
.price-tip { display: flex; align-items: flex-start; margin-top: 18rpx; font-size: 21rpx; line-height: 1.5; color: #7b8791; }
|
||||
.price-tip text { margin: 2rpx 10rpx 0 0; color: #0081ff; }
|
||||
.service-note { margin-top: 18rpx; padding: 18rpx 20rpx; border-radius: 12rpx; font-size: 21rpx; line-height: 1.65; color: #856829; background: #fff8e8; }
|
||||
.service-note-title { margin-bottom: 5rpx; font-size: 23rpx; font-weight: 600; color: #7a5917; }
|
||||
.my-custom-entry { display: flex; align-items: center; justify-content: space-between; margin-top: 20rpx; padding: 22rpx 26rpx; border-radius: 18rpx; background: #fff; box-shadow: 0 5rpx 16rpx rgba(50, 50, 50, .035); }
|
||||
.entry-left { display: flex; align-items: center; }
|
||||
.entry-icon { margin-right: 18rpx; font-size: 42rpx; color: #0081ff; }
|
||||
.entry-title { font-size: 28rpx; font-weight: 500; color: #333; }
|
||||
.entry-desc { margin-top: 5rpx; font-size: 22rpx; color: #999; }
|
||||
.entry-arrow { font-size: 30rpx; color: #bbb; }
|
||||
.form-card { margin-top: 24rpx; padding: 30rpx; border-radius: 20rpx; background: #fff; box-shadow: 0 6rpx 18rpx rgba(50, 50, 50, .04); }
|
||||
.form-title-row { display: flex; align-items: center; justify-content: space-between; }
|
||||
.form-title { font-size: 34rpx; font-weight: 600; color: #222; }
|
||||
.title-icon { margin-right: 5rpx; font-size: 40rpx; color: #0081ff; }
|
||||
.field-label { margin-top: 32rpx; font-size: 28rpx; font-weight: 500; color: #333; }
|
||||
.field-label-space { margin-top: 28rpx; }
|
||||
.required { margin-left: 5rpx; color: #e54d42; }
|
||||
.tech-stack-options { display: flex; flex-wrap: wrap; margin: 2rpx -8rpx -8rpx; }
|
||||
.tech-stack-option { box-sizing: border-box; margin: 12rpx 8rpx 0; padding: 14rpx 20rpx; border: 1rpx solid #e3e8ed; border-radius: 10rpx; font-size: 24rpx; line-height: 1.35; color: #65727d; background: #f8fafb; }
|
||||
.tech-stack-selected { border-color: #0081ff; color: #0081ff; background: #edf7ff; box-shadow: 0 0 0 1rpx rgba(0, 129, 255, .08); }
|
||||
.tech-stack-empty { margin-top: 14rpx; padding: 22rpx; border-radius: 12rpx; text-align: center; font-size: 23rpx; color: #999; background: #f8f8f8; }
|
||||
.input-box, .textarea-box { position: relative; box-sizing: border-box; width: 100%; margin-top: 14rpx; border: 1rpx solid #ededed; border-radius: 14rpx; background: #f8f8f8; }
|
||||
.input-box { height: 90rpx; padding: 0 100rpx 0 22rpx; }
|
||||
.input-box input { height: 88rpx; font-size: 28rpx; color: #222; }
|
||||
.textarea-box { min-height: 250rpx; padding: 22rpx 22rpx 50rpx; }
|
||||
.textarea-box textarea { width: 100%; height: 190rpx; font-size: 28rpx; line-height: 1.65; color: #242739; }
|
||||
.input-placeholder { color: #aaa; }
|
||||
.word-count { position: absolute; right: 20rpx; bottom: 28rpx; font-size: 21rpx; color: #aaa; }
|
||||
.textarea-count { bottom: 16rpx; }
|
||||
.rule-box { display: flex; align-items: flex-start; margin-top: 24rpx; padding: 18rpx 20rpx; border-radius: 12rpx; font-size: 23rpx; line-height: 1.65; color: #8b671d; background: #fff8e8; }
|
||||
.rule-icon { margin: 2rpx 12rpx 0 0; color: #ff9700; }
|
||||
.submit-button { margin-top: 30rpx; height: 90rpx; border: 0; border-radius: 12rpx; font-size: 30rpx; font-weight: 600; line-height: 90rpx; color: #fff; background: #0081ff; box-shadow: 0 8rpx 18rpx rgba(0, 129, 255, .18); }
|
||||
.submit-button::after { border: 0; }
|
||||
.submit-button[disabled] { opacity: .62; }
|
||||
.agreement { margin-top: 18rpx; text-align: center; font-size: 21rpx; color: #aaa; }
|
||||
</style>
|
||||
|
||||
17
utils/customRequest.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const STATUS_CONFIG = {
|
||||
0: { text: '待审核', className: 'status-pending', icon: 'cuIcon-timefill', description: '需求已经提交,请耐心等待审核。' },
|
||||
1: { text: '审核中', className: 'status-reviewing', icon: 'cuIcon-search', description: '工作人员正在查看和评估你的需求。' },
|
||||
2: { text: '已接单', className: 'status-accepted', icon: 'cuIcon-roundcheckfill', description: '需求已通过审核,等待进入开发。' },
|
||||
3: { text: '开发中', className: 'status-developing', icon: 'cuIcon-settingsfill', description: '项目正在开发,可关注下方进度说明。' },
|
||||
4: { text: '已完成', className: 'status-completed', icon: 'cuIcon-roundcheckfill', description: '项目已开发完成,可以查看演示成果。' },
|
||||
5: { text: '审核未通过', className: 'status-rejected', icon: 'cuIcon-roundclosefill', description: '本次需求暂时无法承接,请查看未通过原因。' }
|
||||
}
|
||||
|
||||
export function getCustomRequestStatus(status) {
|
||||
return STATUS_CONFIG[Number(status)] || {
|
||||
text: '未知状态',
|
||||
className: 'status-unknown',
|
||||
icon: 'cuIcon-infofill',
|
||||
description: ''
|
||||
}
|
||||
}
|
||||
3
vue.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
transpileDependencies: [/[/\\]uview-ui[/\\]/]
|
||||
}
|
||||