fix: 修复首页空白/失效外链/云函数越权,补齐缺失页面与种子数据
## 阻断性缺陷 - list.vue 是 0 字节空文件、slist.vue 与 search/search.vue 从未存在, 而前者是 tabBar 首页、后者是 tabBar「搜索」页 —— 开屏即白屏。 按 .nvue 原型与详情页契约重建三页(CSS 渐变主视觉、分类筛选、搜索历史/热搜/联想)。 - parse-image-url.js 对空封面调 undefined.startsWith 直接抛错,列表页整页崩。 - 云函数目录缺 uni-cms-articles / uni-cms-categories / uni-cms-unlock-record schema 与 schema.ext.js,线上内容渲染与解锁逻辑无配置可用。 ## 越权与数据一致性 - uni-cms-articles:del/update/add 全部无鉴权,未登录即可删任意文章、 改他人文章作者与阅读量。补 login + 作者归属校验,作者与计数改为服务端取值。 - comments.likeComment/relikeComment:直接采信客户端传入的 user_id, 可冒名点赞刷计数。改为以令牌为准,并纳入事务。 - comments.updateComment:对数组取 .author_id,权限判断恒失败; 字段名 updateTime 与 ip_location 类型与 schema 不符。 - comments.deleteComment:`!root_id === 0` 优先级错误导致计数恒不减; 且误更新 uni-cms-articles、按不存在的 type 字段删点赞明细产生孤儿数据。 - cms-articles-like/collect:查重条件混入本次请求时间戳,防重永远失效, 可无限重复刷计数;补唯一索引并事务化。 - cms-vote:读-改-写票数导致并发丢票,记录与统计非原子;改为事务 + 原子自增。 - cms-articles-log:忽略传入 user_id 直接返回全表,泄露全站浏览记录。 - article_info:get() 使用未定义变量必崩;读接口全部无鉴权。 - user-info:公开资料接口可查任意用户 last_login_ip。 ## 资源与数据 - 全项目清空失效的签名外链(expire_at 均为 2025-03,必然 403), 改为本地生成资源:6 套文章模板、8 个编辑器图标、2 张文章配图。 - 新增分类 / 模板 / 礼物 / 热搜词种子数据,并在 db_init.json 登记, 同时补上点赞、收藏、投票、浏览日志的唯一索引。 ## 功能 - 草稿箱:预览页拆出「发布」与「存为草稿」,作品列表按状态筛选并显示徽标。 原实现有 4 个 tab 但只有 1 个有内容,且 article_status 在 UI 上无体现。 - 编辑中断恢复:接上原本空实现的「编辑草稿」回调,区分新建与编辑已有文章。 ## 工具 - tools/audit-project.js:编码 / 页面路由 / 云调用 / 云函数鉴权 / 敏感信息检查 - tools/check-vue.js:SFC 脚本语法(词法扫描处理 import·export 与条件编译) - tools/verify.js:一键验证;两个检查器各带自测,防止"永远通过" - tools/gen-*.py:模板与图标资源生成脚本
This commit is contained in:
+39
-13
@@ -120,7 +120,7 @@
|
||||
mode="scaleToFill"
|
||||
width="100rpx"
|
||||
height="100rpx"
|
||||
src="https://qnycdn.mymoyu.top/static/icon/stop.png">
|
||||
src="/static/editor-icons/stop.png">
|
||||
</cloud-image>
|
||||
</view>
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
|
||||
<script>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onShow, onReady, onHide, onUnload } from '@dcloudio/uni-app'
|
||||
import { onLoad, onShow, onReady, onHide, onUnload } from '@dcloudio/uni-app'
|
||||
import cloudImage from "@/components/cloud-image.vue"
|
||||
|
||||
const uniCloudStorageExtCo = uniCloud.importObject("ext-storage-co")
|
||||
@@ -204,17 +204,20 @@
|
||||
const delPopup = ref(null)
|
||||
const popup = ref(null)
|
||||
const saveInterval = ref(null)
|
||||
// 有值表示在编辑一篇已存在的文章(带 id 进入)
|
||||
const editingId = ref("")
|
||||
|
||||
const is_vote = ref("https://qnycdn.mymoyu.top/static/icon/is_vote.png")
|
||||
const not_image = ref("https://qnycdn.mymoyu.top/static/icon/not_image.png")
|
||||
// 图标改为本地静态资源:原先的外链依赖第三方域名与签名,失效即整块空白
|
||||
const is_vote = ref("/static/editor-icons/is_vote.png")
|
||||
const not_image = ref("/static/editor-icons/not_image.png")
|
||||
const selectIndex = ref(0)
|
||||
|
||||
const cmsType = ref([
|
||||
{ type: "text", text: "文字", src: "https://qnycdn.mymoyu.top/static/icon/text.png" },
|
||||
{ type: "video", text: "视频", src: "https://qnycdn.mymoyu.top/static/icon/video.png" },
|
||||
{ type: "image", text: "图片", src: "https://qnycdn.mymoyu.top/static/icon/image.png" },
|
||||
{ type: "vote", text: "投票", src: "https://qnycdn.mymoyu.top/static/icon/vote.png" },
|
||||
{ type: "title", text: "小标题", src: "https://qnycdn.mymoyu.top/static/icon/title.png" },
|
||||
{ type: "text", text: "文字", src: "/static/editor-icons/text.png" },
|
||||
{ type: "video", text: "视频", src: "/static/editor-icons/video.png" },
|
||||
{ type: "image", text: "图片", src: "/static/editor-icons/image.png" },
|
||||
{ type: "vote", text: "投票", src: "/static/editor-icons/vote.png" },
|
||||
{ type: "title", text: "小标题", src: "/static/editor-icons/title.png" },
|
||||
])
|
||||
|
||||
const cms = reactive({
|
||||
@@ -233,23 +236,39 @@
|
||||
clearTimeout(saveInterval.value)
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
// 从「我的作品」进入时带 id,用于区分"编辑已有文章"与"新建"
|
||||
editingId.value = (options && options.id) || ""
|
||||
})
|
||||
|
||||
onReady(() => {
|
||||
let storedCms = uni.getStorageSync("cms")
|
||||
if (storedCms && ((storedCms.cmsLst && storedCms.cmsLst.length > 0) || storedCms.title || storedCms.title_html)) {
|
||||
const storedCms = uni.getStorageSync("cms")
|
||||
const hasDraft = storedCms && (
|
||||
(storedCms.cmsLst && storedCms.cmsLst.length > 0) ||
|
||||
storedCms.title ||
|
||||
storedCms.title_html
|
||||
)
|
||||
// 从「我的作品」带 id 进来是编辑已有文章,不是未完成的草稿,
|
||||
// 此时弹"草稿未完成"会误导用户。只有新建流程才提示。
|
||||
const editingExisting = !!(editingId && editingId.value)
|
||||
if (hasDraft && !editingExisting) {
|
||||
alertDialog.value.open()
|
||||
}
|
||||
saveInterval.value = setInterval(saveCms, 10000)
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
let storedCms = uni.getStorageSync("cms")
|
||||
const storedCms = uni.getStorageSync("cms")
|
||||
if (storedCms) {
|
||||
Object.assign(cms, storedCms)
|
||||
}
|
||||
})
|
||||
|
||||
function saveCms() {
|
||||
uni.setStorageSync("cms", cms)
|
||||
// 定时保存只在有实际内容时落盘,避免空编辑器把上一次的草稿覆盖成空
|
||||
const hasContent = (cms.cmsLst && cms.cmsLst.length > 0) || cms.title || cms.title_html
|
||||
if (!hasContent) return
|
||||
uni.setStorageSync("cms", JSON.parse(JSON.stringify(cms)))
|
||||
}
|
||||
|
||||
function open() {
|
||||
@@ -469,10 +488,16 @@
|
||||
alertDialog.value.close()
|
||||
}
|
||||
|
||||
// 「编辑草稿」:保留本地草稿(onShow 已把内容灌进 cms),直接进入编辑
|
||||
async function dialogConfirm() {
|
||||
alertDialog.value.close()
|
||||
}
|
||||
|
||||
// 「放弃草稿」:清空本地草稿并重置编辑器
|
||||
async function dialogClose() {
|
||||
await discardDraft()
|
||||
}
|
||||
|
||||
async function addItem(type) {
|
||||
if (type === "text") {
|
||||
addTextItem()
|
||||
@@ -580,6 +605,7 @@
|
||||
delPopup,
|
||||
popup,
|
||||
saveInterval,
|
||||
editingId,
|
||||
is_vote,
|
||||
not_image,
|
||||
selectIndex,
|
||||
|
||||
+94
-59
@@ -4,13 +4,20 @@
|
||||
title="预览"
|
||||
leftText="取消"
|
||||
left-icon="left"
|
||||
right-text="完成"
|
||||
right-text="发布"
|
||||
backgroundColor="#ffffff"
|
||||
color="#000000"
|
||||
@clickRight="success()"
|
||||
@clickRight="saveArticle(1)"
|
||||
@clickLeft="back()">
|
||||
</uni-nav-bar>
|
||||
|
||||
|
||||
<!-- 存草稿不发布:草稿仅在「我的作品」中可见 -->
|
||||
<view class="draft-bar">
|
||||
<button class="draft-btn" :loading="saving" :disabled="saving" @click="saveArticle(0)">
|
||||
存为草稿
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="v-preview" v-if="temp && temp.temptele_src">
|
||||
<image :src="temp.temptele_src" alt="" class="img" mode="widthFix" />
|
||||
</view>
|
||||
@@ -229,6 +236,7 @@
|
||||
const popFrom = ref('bottom')
|
||||
const list = ref(new Array(20).fill(0))
|
||||
const currentTemplate = ref("")
|
||||
const saving = ref(false)
|
||||
|
||||
const tabbarText = ref([
|
||||
{ text: "模板" },
|
||||
@@ -340,63 +348,69 @@
|
||||
return formatDate(new Date(), 'yyyy-MM-dd HH:mm')
|
||||
}
|
||||
|
||||
async function success() {
|
||||
let storedCms = uni.getStorageSync("cms")
|
||||
let id = storedCms._id
|
||||
let title = storedCms.title
|
||||
let title_html = storedCms.title_html
|
||||
let title_delta = storedCms.title_delta
|
||||
let temp_id = currentTemplate.value
|
||||
let edit_type = "mobile"
|
||||
let view_count = 0
|
||||
let article_status = 1
|
||||
let user_id = userInfo.value._id
|
||||
let cmsLst = storedCms.cmsLst
|
||||
let excerpt = ""
|
||||
let res = await uniCloud.importObject("user-info").getIP({ uid: userInfo.value._id })
|
||||
let last_modify_ip = res.code === 200 ? res.data.last_login_ip : ""
|
||||
/**
|
||||
* 保存文章
|
||||
* @param {Number} articleStatus 1 发布,0 存草稿
|
||||
*/
|
||||
async function saveArticle(articleStatus) {
|
||||
if (saving.value) return
|
||||
|
||||
if (id) {
|
||||
let query = {
|
||||
id,
|
||||
title: storedCms.title,
|
||||
user_id,
|
||||
title_html: storedCms.title_html,
|
||||
title_delta: storedCms.title_delta,
|
||||
thumbnail: storedCms.thumbnail,
|
||||
p_type: storedCms.p_type,
|
||||
category_id: storedCms.category_id,
|
||||
temp_id,
|
||||
edit_type,
|
||||
view_count,
|
||||
cmsLst: storedCms.cmsLst,
|
||||
excerpt,
|
||||
last_modify_ip,
|
||||
article_status,
|
||||
}
|
||||
await uniCloud.importObject("uni-cms-articles").update_cms_articles(query)
|
||||
} else {
|
||||
let query = {
|
||||
title: storedCms.title,
|
||||
user_id,
|
||||
title_html: storedCms.title_html,
|
||||
title_delta: storedCms.title_delta,
|
||||
thumbnail: storedCms.thumbnail,
|
||||
p_type: storedCms.p_type,
|
||||
category_id: storedCms.category_id,
|
||||
temp_id,
|
||||
edit_type,
|
||||
view_count,
|
||||
cmsLst: storedCms.cmsLst,
|
||||
excerpt,
|
||||
last_modify_ip,
|
||||
article_status,
|
||||
}
|
||||
await uniCloud.importObject("uni-cms-articles").add_cms_articles(query)
|
||||
const storedCms = uni.getStorageSync("cms")
|
||||
if (!storedCms) {
|
||||
return uni.showToast({ title: '内容已丢失,请重新编辑', icon: 'none' })
|
||||
}
|
||||
if (!storedCms.title || !storedCms.title.trim()) {
|
||||
return uni.showToast({ title: '请先填写标题', icon: 'none' })
|
||||
}
|
||||
// 草稿允许只有标题,发布必须有正文
|
||||
const hasContent = Array.isArray(storedCms.cmsLst) && storedCms.cmsLst.length > 0
|
||||
if (articleStatus === 1 && !hasContent) {
|
||||
return uni.showToast({ title: '正文不能为空', icon: 'none' })
|
||||
}
|
||||
|
||||
uni.setStorageSync("cms", "")
|
||||
uni.switchTab({ url: "/pages/my/my" })
|
||||
saving.value = true
|
||||
try {
|
||||
// 归属与 IP 由服务端从登录态与请求上下文获取,这里不再传 user_id
|
||||
const query = {
|
||||
title: storedCms.title,
|
||||
title_html: storedCms.title_html,
|
||||
title_delta: storedCms.title_delta,
|
||||
thumbnail: storedCms.thumbnail,
|
||||
p_type: storedCms.p_type,
|
||||
category_id: storedCms.category_id,
|
||||
temp_id: currentTemplate.value,
|
||||
edit_type: "mobile",
|
||||
cmsLst: storedCms.cmsLst,
|
||||
excerpt: storedCms.excerpt || "",
|
||||
article_status: articleStatus,
|
||||
}
|
||||
|
||||
let res
|
||||
if (storedCms._id) {
|
||||
res = await uniCloud.importObject("uni-cms-articles")
|
||||
.update_cms_articles({ ...query, id: storedCms._id })
|
||||
} else {
|
||||
res = await uniCloud.importObject("uni-cms-articles").add_cms_articles(query)
|
||||
}
|
||||
|
||||
if (!res || res.code !== 200) {
|
||||
throw new Error((res && res.msg) || '保存失败')
|
||||
}
|
||||
|
||||
uni.setStorageSync("cms", "")
|
||||
uni.showToast({
|
||||
title: articleStatus === 1 ? '发布成功' : '已存为草稿',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: "/pages/my/my" })
|
||||
}, 800)
|
||||
} catch (e) {
|
||||
console.error('保存文章失败:', e)
|
||||
uni.showToast({ title: e.message || '保存失败,请重试', icon: 'none' })
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function back() {
|
||||
@@ -439,7 +453,8 @@
|
||||
radioChange,
|
||||
formatDate,
|
||||
formatTime,
|
||||
success,
|
||||
saving,
|
||||
saveArticle,
|
||||
back,
|
||||
}
|
||||
}
|
||||
@@ -447,7 +462,27 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
.draft-bar {
|
||||
padding: 16rpx 20rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.draft-btn {
|
||||
font-size: 28rpx;
|
||||
line-height: 72rpx;
|
||||
height: 72rpx;
|
||||
color: #c11c1f;
|
||||
background-color: #fff;
|
||||
border: 1rpx solid #c11c1f;
|
||||
border-radius: 36rpx;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
+109
-43
@@ -15,7 +15,7 @@
|
||||
<view class="">
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
@click="editItem(selectIndex)"
|
||||
@click="editItem(selectItem)"
|
||||
:show-extra-icon="true"
|
||||
:extra-icon="iconList.edit"
|
||||
clickable="true"
|
||||
@@ -23,7 +23,7 @@
|
||||
</uni-list>
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
@click="settingItem(selectIndex)"
|
||||
@click="settingItem()"
|
||||
:show-extra-icon="true"
|
||||
:extra-icon="iconList.setting"
|
||||
clickable="true"
|
||||
@@ -31,7 +31,7 @@
|
||||
</uni-list>
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
@click="deleteItem(selectIndex)"
|
||||
@click="deleteItem()"
|
||||
:show-extra-icon="true"
|
||||
:extra-icon="iconList.delete"
|
||||
clickable="true"
|
||||
@@ -45,11 +45,10 @@
|
||||
|
||||
</u-popup>
|
||||
|
||||
<view class="" v-if="current === 1">
|
||||
<view class="container" style="display: flex;flex-wrap: wrap;">
|
||||
<view class=""
|
||||
style="box-sizing: border-box;width: 50%;border-radius: 12rpx;" v-for="(item, index) in cms_list">
|
||||
<uni-card margin="5" spacing="0" @click="editItem(index)">
|
||||
<view class="list-wrap">
|
||||
<view class="container" v-if="filteredList.length">
|
||||
<view class="card-wrap" v-for="item in filteredList" :key="item._id">
|
||||
<uni-card margin="5" spacing="0" @click="editItem(item)">
|
||||
<cloud-image
|
||||
width="100%"
|
||||
height="200rpx"
|
||||
@@ -57,22 +56,20 @@
|
||||
:src="Array.isArray(item.thumbnail) && item.thumbnail.length > 0?item.thumbnail[0]:''">
|
||||
</cloud-image>
|
||||
<text class="uni-body">
|
||||
{{ item.title }}
|
||||
{{ item.title || '(无标题)' }}
|
||||
</text>
|
||||
<view
|
||||
slot="actions"
|
||||
class="card-actions">
|
||||
|
||||
<view
|
||||
class="card-actions-item">
|
||||
<text
|
||||
class="card-actions-item-text">
|
||||
阅读量 {{ item.view_count }}
|
||||
<view slot="actions" class="card-actions">
|
||||
<view class="card-actions-item">
|
||||
<text class="status-tag" :class="item.article_status === 1 ? 'published' : 'draft'">
|
||||
{{ item.article_status === 1 ? '已发布' : '草稿' }}
|
||||
</text>
|
||||
</view>
|
||||
<view
|
||||
class="card-actions-item"
|
||||
@click.stop="selectMore(index)">
|
||||
<view class="card-actions-item">
|
||||
<text class="card-actions-item-text">
|
||||
阅读 {{ item.view_count || 0 }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="card-actions-item" @click.stop="selectMore(item)">
|
||||
<uni-icons type="more-filled" size="18" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
@@ -80,6 +77,9 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="empty" v-else>
|
||||
<text class="empty-text">{{ emptyText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -98,12 +98,14 @@
|
||||
uPopup
|
||||
},
|
||||
setup() {
|
||||
const list = ref(['动态', '作品', '相册', '收藏'])
|
||||
const current = ref(1)
|
||||
// 只保留真实存在的两种状态:草稿(article_status=0)与已发布(=1)。
|
||||
// 原实现有 4 个 tab,但只有第 2 个有内容,其余点开是空白。
|
||||
const list = ref(['已发布', '草稿'])
|
||||
const current = ref(0)
|
||||
const show = ref(false)
|
||||
const selectIndex = ref(0)
|
||||
const selectItem = ref(null)
|
||||
const cms_list = ref([])
|
||||
|
||||
|
||||
const iconList = {
|
||||
delete: { color: '#f55', size: '22', type: 'closeempty' },
|
||||
setting: { color: '#888', size: '22', type: 'gear-filled' },
|
||||
@@ -112,6 +114,16 @@
|
||||
|
||||
const userInfo = computed(() => store.userInfo)
|
||||
|
||||
// 0 = 已发布,1 = 草稿
|
||||
const filteredList = computed(() => {
|
||||
const want = current.value === 1 ? 0 : 1
|
||||
return cms_list.value.filter((it) => (it.article_status || 0) === want)
|
||||
})
|
||||
|
||||
const emptyText = computed(() =>
|
||||
current.value === 1 ? '还没有草稿' : '还没有发布过文章'
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
if (!userInfo.value._id) {
|
||||
uni.showToast({ title: '请先登录', icon: 'none' })
|
||||
@@ -135,9 +147,10 @@
|
||||
current.value = index
|
||||
}
|
||||
|
||||
function selectMore(index) {
|
||||
// 按对象引用定位,避免列表经过筛选后下标与原始数组错位
|
||||
function selectMore(item) {
|
||||
show.value = true
|
||||
selectIndex.value = index
|
||||
selectItem.value = item
|
||||
}
|
||||
|
||||
function close() {
|
||||
@@ -148,19 +161,31 @@
|
||||
show.value = true
|
||||
}
|
||||
|
||||
async function deleteItem(index) {
|
||||
let res = await uniCloud.importObject("uni-cms-articles").del_cms_articles({ id: cms_list.value[index]._id })
|
||||
if (res.code === 200) {
|
||||
cms_list.value.splice(index, 1)
|
||||
}
|
||||
async function deleteItem() {
|
||||
const target = selectItem.value
|
||||
if (!target) return
|
||||
close()
|
||||
|
||||
try {
|
||||
const res = await uniCloud.importObject("uni-cms-articles")
|
||||
.del_cms_articles({ id: target._id })
|
||||
if (res && res.code === 200) {
|
||||
const idx = cms_list.value.findIndex((it) => it._id === target._id)
|
||||
if (idx !== -1) cms_list.value.splice(idx, 1)
|
||||
uni.showToast({ title: '已删除', icon: 'none' })
|
||||
} else {
|
||||
uni.showToast({ title: (res && res.msg) || '删除失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('删除文章失败:', e)
|
||||
uni.showToast({ title: '删除失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function editItem(index) {
|
||||
let cms = cms_list.value[index]
|
||||
if (!cms) return
|
||||
uni.setStorageSync("cms", cms)
|
||||
await toCmsEdit(cms._id)
|
||||
async function editItem(item) {
|
||||
if (!item) return
|
||||
uni.setStorageSync("cms", item)
|
||||
await toCmsEdit(item._id)
|
||||
}
|
||||
|
||||
async function toCmsEdit(id) {
|
||||
@@ -169,10 +194,11 @@
|
||||
})
|
||||
}
|
||||
|
||||
function settingItem(index) {
|
||||
let cms = cms_list.value[index]
|
||||
if (!cms) return
|
||||
uni.setStorageSync("cms", cms)
|
||||
function settingItem() {
|
||||
const target = selectItem.value
|
||||
if (!target) return
|
||||
uni.setStorageSync("cms", target)
|
||||
close()
|
||||
uni.navigateTo({ url: "/pages2/editCms/editSetting" })
|
||||
}
|
||||
|
||||
@@ -180,8 +206,10 @@
|
||||
list,
|
||||
current,
|
||||
show,
|
||||
selectIndex,
|
||||
selectItem,
|
||||
cms_list,
|
||||
filteredList,
|
||||
emptyText,
|
||||
iconList,
|
||||
userInfo,
|
||||
sectionChange,
|
||||
@@ -201,11 +229,49 @@
|
||||
.page {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
.list-wrap {
|
||||
min-height: 40vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-wrap {
|
||||
box-sizing: border-box;
|
||||
width: 50%;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
font-size: 22rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.status-tag.published {
|
||||
color: #18b566;
|
||||
background-color: rgba(24, 181, 102, 0.1);
|
||||
}
|
||||
|
||||
.status-tag.draft {
|
||||
color: #f29100;
|
||||
background-color: rgba(242, 145, 0, 0.12);
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 160rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.custom-cover {
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
maxlength="11" placeholder="请输入手机号"></uni-easyinput>
|
||||
<uni-easyinput clearable type="number" class="input-box" :inputBorder="false" v-model="formData.code" maxlength="6"
|
||||
placeholder="请输入验证码">
|
||||
<template slot="right">
|
||||
<qk-send-sms-code ref="shortCode" code-type="bind" :phone="formData.phone"></qk-send-sms-code>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<qk-send-sms-code ref="shortCode" scene="bind-mobile-by-sms" :phone="formData.phone"></qk-send-sms-code>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
<button class="send-btn-box" type="primary" @click="submit">绑定</button>
|
||||
</view>
|
||||
@@ -49,28 +49,29 @@
|
||||
/**
|
||||
* 完成并提交
|
||||
*/
|
||||
submit() {
|
||||
uniCloud.callFunction({
|
||||
name:'uni-id-cf',
|
||||
data:{
|
||||
action:'bind_mobile_by_sms',
|
||||
params:{
|
||||
"mobile": this.formData.phone,
|
||||
"code": this.formData.code
|
||||
},
|
||||
},
|
||||
success: ({result}) => {
|
||||
console.log(result);
|
||||
this.setUserInfo({"mobile":result.mobile})
|
||||
uni.showToast({
|
||||
title: result.msg,
|
||||
icon: 'none'
|
||||
});
|
||||
if (result.code === 0) {
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
async submit() {
|
||||
if (!/^1\d{10}$/.test(this.formData.phone)) {
|
||||
return uni.showToast({ title: '手机号格式错误', icon: 'none' });
|
||||
}
|
||||
if (!this.formData.code) {
|
||||
return uni.showToast({ title: '请输入验证码', icon: 'none' });
|
||||
}
|
||||
try {
|
||||
const uniIdCo = uniCloud.importObject('uni-id-co')
|
||||
await uniIdCo.bindMobileBySms({
|
||||
mobile: this.formData.phone,
|
||||
code: this.formData.code
|
||||
});
|
||||
this.setUserInfo({ mobile: this.formData.phone })
|
||||
uni.showToast({ title: '绑定成功', icon: 'none' });
|
||||
setTimeout(() => uni.navigateBack(), 800);
|
||||
} catch (e) {
|
||||
console.error('绑定失败:', e);
|
||||
uni.showToast({
|
||||
title: e.errMsg || '绑定失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user