first commit

master
王文杰 10 months ago
parent 03510a4ef9
commit 2f57502257

16
.gitignore vendored

@ -0,0 +1,16 @@
######################################################################
# Build Tools
/unpackage/*
/node_modules/*
######################################################################
# Development Tools
/.idea/*
/.vscode/*
/.hbuilderx/*
package-lock.json
yarn.lock

@ -0,0 +1,36 @@
<script>
import config from './config'
import store from '@/store'
import { getToken } from '@/utils/auth'
export default {
onLaunch: function() {
this.initApp()
},
methods: {
//
initApp() {
//
this.initConfig()
//
//#ifdef H5
this.checkLogin()
//#endif
},
initConfig() {
this.globalData.config = config
},
checkLogin() {
if (!getToken()) {
this.$tab.reLaunch('/pages/login')
}
}
}
}
</script>
<style lang="scss">
@import '@/static/scss/index.scss';
@import '@/uni_modules/uview-ui/index.scss'
</style>

@ -0,0 +1,21 @@
MIT License
Copyright © 2025 长江云息数字科技 出品
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,11 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 统计数据
export function homeTjApi(params) {
return request({
url: '/app-api/app/task/produce/statistic',
method: 'get',
params
})
}

@ -0,0 +1,66 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password) {
const data = {
username,
password
}
return request({
'url': '/admin-api/system/auth/login',
headers: {
isToken: false
},
'method': 'post',
'data': data
})
}
// 注册方法
export function register(data) {
return request({
url: '/admin-api/register',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo(userId) {
const url = `/app-api/app/user/${userId}`
return request({
'url': url,
'method': 'get'
})
}
// 通过用户名获取租户id
export function getUserId(name) {
const url = `/admin-api/system/tenant/get-tenantId-by-userName?name=${name}`
return request({
'url': url,
'method': 'get'
})
}
// 退出方法
export function logout() {
return request({
'url': '/admin-api/system/auth/logout',
'method': 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
'url': '/captchaImage',
headers: {
isToken: false
},
method: 'get',
timeout: 20000
})
}

@ -0,0 +1,41 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
params: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return upload({
url: '/system/user/profile/avatar',
name: data.name,
filePath: data.filePath
})
}

@ -0,0 +1,34 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 详情数据
export function produceDetailApi(params) {
return request({
url: '/app-api/app/task/produce',
method: 'get',
params
})
}
// 报工
export function produceReportApi(data) {return request({
url: '/app-api/app/task/produce/report',
method: 'post',
data
})
}
// 领料接口
export function produceRecieveApi(data) {return request({
url: '/app-api/app/task/produce/receive',
method: 'post',
data
})
}
// 开始/结束任务
export function produceOperateApi(data) {return request({
url: '/app-api/app/task/produce/operate',
method: 'post',
data
})
}

@ -0,0 +1,12 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 任务列表数据
export function taskListApi(params) {
return request({
url: '/app-api/app/task/produces',
method: 'get',
params
})
}

@ -0,0 +1,115 @@
<template>
<view class="drawer">
<uni-drawer ref="showLeft" mode="left" :width="340">
<view class="table">
<uni-table ref="table" border stripe emptyText="暂无更多数据">
<uni-tr>
<uni-th width="100" align="center">物料名称</uni-th>
<uni-th width="100" align="center">规格</uni-th>
<uni-th align="center">计划领料数量</uni-th>
</uni-tr>
<uni-tr v-for="(item, index) in detailList" :key="index">
<uni-td align="center">
<view class="name">{{ item.productName }}</view>
</uni-td>
<uni-td align="center">{{ item.spec }}</uni-td>
<uni-td align="center">
<uni-number-box type="number" :max="item.receiveAmount" min="0" :value="item.amount" />
</uni-td>
</uni-tr>
</uni-table>
</view>
<view class="footer">
<view @click="closeDrawer" class="item close">关闭</view>
<view @click="handelSubmit" class="item submit">提交</view>
</view>
</uni-drawer>
</view>
</template>
<script>
export default {
name: "GoodDrawer",
props: {
detailList: {
type: Array,
required: false,
default: () => {
return []
},
}
},
data() {
return {
loading: false
}
},
methods: {
closeDrawer() {
this.$emit('close')
},
handleBlur(item) {
const obj = this.detailList.find(e => {
return e.id == item.id
})
obj.amount = obj.amount > obj.receiveAmount ? obj.receiveAmount : item.amount;
debugger
},
handelSubmit() {
const detailList = this.detailList.map(e => {
const obj = {
id: e.id,
productId: e.productId,
amount: e.amount
}
return obj
})
this.$emit('submit', detailList)
}
},
}
</script>
<style lang="scss" scoped>
.drawer {
width: 100%;
position: relative;
.table {
.uni-input {
border-bottom: 2rpx solid #D5D6DB;
}
}
.footer {
margin: 30px 0;
width: 100%;
position: absolute;
bottom: 0rpx;
display: flex;
flex-direction: row;
justify-content: space-around;
.item {
flex: 1;
border: 2rpx solid #D5D6DB;
text-align: center;
font-size: 16rpx;
border-radius: 10rpx;
padding: 20rpx 20rpx;
margin: 0 20rpx;
&.close {
background-color: #D5D6DB;
color: #fff;
}
&.submit {
background-color: #FF7D00;
color: #fff;
}
}
}
}
</style>

@ -0,0 +1,209 @@
<template>
<view class="task-card">
<uni-card padding="0" spacing="0" marginTop="10">
<view slot="title">
<view class="headerbox">
<view class="title">派工单编号 {{info.code}}</view>
<view class="option">
<text class="status" :class="info.status">{{statusMap[info.status]}}</text>
<!-- <uni-icons type="trash" size="20" @click="removeClick"></uni-icons> -->
</view>
</view>
</view>
<view class="content">
<view class="subject">计划消耗时间: {{info.predictWorkTime}} 工时</view>
<view class="info">
<view class="info_item">产品名称: {{info.productName}}</view>
<view class="info_item">工序名称: {{info.procedureName}}</view>
<view class="info_item u-flex-column flex flex--direction">
<view style="margin-right: 20rpx;">派工数量: {{info.processingProductAmount}}</view>
<view>已报工数量: {{info.reportAmount}}</view>
</view>
<view class="info_item">任务编号: {{info.produceProcessingTaskOrderCode}}</view>
<view class="info_item" v-if="info.startWorkTime">: {{info.startWorkTime | formatDate}} {{info.endWorkTime | formatDate}}</view>
<view class="view-detail" @click="taskInfoClick(info)"></view>
</view>
</view>
</uni-card>
</view>
</template>
<script>
export default {
name: "TaskCard",
props: {
info: {
type: Object,
required: false,
default: () => {
return {
id: 90569010,
title: "#30任务名称",
status: 'RECEIVED',
hours: 80,
productName: "xxx产品",
number: 30,
creator: '管理员',
createtime: '2023-10-01 09:58:51',
pointer: '小王',
finishtime: '2023-10-11 19:58:51',
}
}
},
dict: {
type: Object,
required: false,
default: () => {
return {
statusMap: {
'RECEIVED': "已接单",
'PROCESSING': "进行中",
'FINISHED': "已完成"
},
}
}
}
},
data() {
return {
// statusMap: this.dict.statusMap
}
},
computed: {
statusMap() {
return this.$store.state.user.statusMap || {};
},
},
//
filters: {
formatDate: function(value) {
var date = new Date();
date.setTime(value);
var month = date.getMonth() + 1;
var hours = date.getHours();
if (hours < 10)
hours = "0" + hours;
var minutes = date.getMinutes();
if (minutes < 10)
minutes = "0" + minutes;
var time = date.getFullYear() + "-" + month + "-" + date.getDate() +
" " + hours + ":" + minutes;
return time;
}
},
methods: {
//
removeClick() {
this.$refs.msg.show({
type: 'default',
message: "删除功能暂未开发~",
});
},
// /
actionsClick(type) {
console.log("操作类型:" + type);
},
//
taskInfoClick(obj) {
const id = obj.id
const status = obj.status
uni.navigateTo({
url: `/pages/task-detail/index?id=${id}&status=${status}&code=${this.info.code}`
});
}
},
}
</script>
<style lang="scss" scoped>
.task-card {
width: 100%;
.headerbox {
display: flex;
align-items: center;
padding: 0rpx 20rpx;
height: 40px;
border-bottom: 1px solid #f2f2f2;
.title {
flex: 3;
font-size: 14px;
color: #333;
}
.option {
flex: 1;
text-align: right;
.status {
font-size: 12px;
color: #999;
margin-right: 5px;
vertical-align: text-top;
padding: 4rpx 6rpx;
border-radius: 5rpx;
&.RECEIVED {
color: #00B42A;
background-color: #E8FFEA;
}
&.PROCESSING {
color: #FF7D00;
background-color: #FFF7E8;
}
&.FINISHED {
color: #fff;
background-color: #5386E4;
}
}
}
}
.content {
position: relative;
padding: 5px 10px;
border-bottom: 2px solid #f2f2f2;
.subject {
background-color: #FFF7E8;
border: 1px solid #FFF7E8;
color: #FF7D00;
border-radius: 5px;
padding: 10rpx;
}
.info {
margin: 5px 0;
background-color: #ededed;
padding: 5px 10px;
border-radius: 3px;
&_item {
font-size: 12px;
color: #666;
margin-bottom: 5px;
}
}
.view-detail {
position: absolute;
right: 20rpx;
bottom: 30rpx;
border-radius: 8rpx;
padding: 8rpx 12rpx;
color: #356899;
border: 1px solid #356899;
}
}
.card-actions {
display: flex;
justify-content: space-between;
padding: 10px;
.card-actions-item {
margin: 0 5px;
width: 100px;
text-align: center;
}
}
}
</style>

@ -0,0 +1,25 @@
// 应用全局配置
module.exports = {
baseUrl: 'http://222.71.165.187:9090',
// 应用信息
appInfo: {
// 应用名称
name: "HL-app",
// 应用版本
version: "1.1.0",
// 应用logo
logo: "../static/images/login-logo.png",
// 官方网站
site_url: "http://www.chanko.cn/",
// 政策协议
agreements: [{
title: "隐私政策",
url: "http://www.chanko.cn/"
},
{
title: "用户服务协议",
url: "http://www.chanko.cn/"
}
]
}
}

@ -0,0 +1,21 @@
import Vue from 'vue'
import App from './App'
import store from './store' // store
import plugins from './plugins' // plugins
import './permission' // permission
import uView from '@/uni_modules/uview-ui'
Vue.use(plugins)
Vue.use(uView)
Vue.config.productionTip = false
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()

@ -0,0 +1,69 @@
{
"name" : "合立报工移动端",
"appid" : "__UNI__E171CB7",
"description" : "",
"versionName" : "1.1.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {},
"sdkConfigs" : {}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "wxa29fe397274614b5",
"setting" : {
"urlCheck" : false,
"es6" : true,
"minified" : true,
"postcss" : true
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true
},
"vueVersion" : "2",
"h5" : {
"template" : "static/index.html",
"devServer" : {
"port" : 9090,
"https" : false
},
"title" : "heli-App",
"router" : {
"mode" : "hash",
"base" : "./"
}
}
}

@ -0,0 +1,135 @@
{
"pages": [
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "合立报工"
}
},{
"path": "pages/login",
"style": {
"navigationBarTitleText": "登录"
}
}, {
"path": "pages/register",
"style": {
"navigationBarTitleText": "注册"
}
},
{
"path": "pages/task-detail/index",
"style": {
"navigationBarTitleText": "任务详情"
}
},
{
"path": "pages/bg-detail/index",
"style": {
"navigationBarTitleText": "报工详情"
}
},
{
"path": "pages/task-list/index",
"style": {
"navigationBarTitleText": "任务列表"
}
},
{
"path": "pages/task-center/index",
"style": {
"navigationBarTitleText": "任务中心"
}
},
{
"path": "pages/news/index",
"style": {
"navigationBarTitleText": "消息"
}
},
{
"path": "pages/mine/index",
"style": {
"navigationBarTitleText": "我的"
}
}, {
"path": "pages/mine/avatar/index",
"style": {
"navigationBarTitleText": "修改头像"
}
}, {
"path": "pages/mine/info/index",
"style": {
"navigationBarTitleText": "个人信息"
}
}, {
"path": "pages/mine/info/edit",
"style": {
"navigationBarTitleText": "编辑资料"
}
}, {
"path": "pages/mine/pwd/index",
"style": {
"navigationBarTitleText": "修改密码"
}
}, {
"path": "pages/mine/setting/index",
"style": {
"navigationBarTitleText": "应用设置"
}
}, {
"path": "pages/mine/help/index",
"style": {
"navigationBarTitleText": "常见问题"
}
}, {
"path": "pages/mine/about/index",
"style": {
"navigationBarTitleText": "关于我们"
}
}, {
"path": "pages/common/webview/index",
"style": {
"navigationBarTitleText": "浏览网页"
}
}, {
"path": "pages/common/textview/index",
"style": {
"navigationBarTitleText": "浏览文本"
}
}],
"tabBar": {
"color": "#000000",
"selectedColor": "#000000",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_.png",
"text": "首页"
}, {
"pagePath": "pages/task-center/index",
"iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png",
"text": "任务中心"
},
// {
// "pagePath": "pages/news/index",
// "iconPath": "static/images/tabbar/news.png",
// "selectedIconPath": "static/images/tabbar/news_.png",
// "text": "消息"
// },
{
"pagePath": "pages/mine/index",
"iconPath": "static/images/tabbar/mine.png",
"selectedIconPath": "static/images/tabbar/mine_.png",
"text": "我的"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#FFFFFF"
}
}

@ -0,0 +1,523 @@
<template>
<view class="detail">
<view class="base-info module">
<view class="title">派工单编号 #33</view>
<view class="cont">
<view class="item">
<view class="label">产品状态</view>
<view class="val yjd">{{statusMap[detailInfo.status]}}</view>
</view>
<view class="item">
<view class="label">产品名称</view>
<view class="val">{{detailInfo.productName}}</view>
</view>
<view class="item">
<view class="label">派工工序</view>
<view class="val">{{detailInfo.procedureName}}</view>
</view>
<view class="item">
<view class="label">任务编号</view>
<view class="val">{{detailInfo.code}}</view>
</view>
<view class="item">
<view class="label">完成时限</view>
<view class="val">{{detailInfo.startWorkTime | formatDate}}
{{detailInfo.endWorkTime | formatDate}}</view>
</view>
<view class="item">
<view class="label">派工数量</view>
<view class="val">{{detailInfo.processingProductAmount}}</view>
</view>
<view class="item">
<view class="label">预计工时</view>
<view class="val">{{detailInfo.predictWorkTime}}</view>
</view>
<view class="item">
<view class="label">总报工产量</view>
<view class="val">{{detailInfo.reportAmount}}</view>
</view>
<view class="item">
<view class="label">总实际工时</view>
<view class="val">{{detailInfo.workTime}}</view>
</view>
</view>
</view>
<block v-if="isStaff">
<view class="module bgInfo">
<view class="item">
<view class="label">派工产量</view>
<view class="val">{{detailInfo.processingProductAmount}}</view>
</view>
<view class="item">
<view class="label">总报工产量</view>
<view class="val">{{detailInfo.reportAmount}}</view>
</view>
<view class="item">
<view class="label">剩余数量</view>
<view class="val">{{reportAmountMax}}</view>
</view>
</view>
<view class="pg-info module">
<view class="title">报工</view>
<view class="cont">
<view class="item">
<view class="label">生产部门</view>
<view class="val">{{userInfo.deptName}}</view>
</view>
<view class="item">
<view class="label">生产人员</view>
<view class="val">{{userInfo.nickname}}</view>
</view>
<view class="item" v-if="detailInfo.workStatus == 'END'">
<view class="label">报工完成数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="reportAmount" />
<!-- <input class="uni-input" type="number" v-model="reportAmount" placeholder="请输入数量" /> -->
</view>
</view>
</view>
</view>
</block>
<block v-else>
<view class="pg-info module">
<view class="title">报工</view>
<view class="cont">
<view class="item">
<view class="label">生产部门</view>
<view class="val">{{userInfo.deptName}}</view>
</view>
<view class="item">
<view class="label">生产人员</view>
<view class="val">{{userInfo.nickname}}</view>
</view>
<view class="item" v-if="detailInfo.workStatus == 'END'">
<view class="label">报工完成数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="reportAmount" />
</view>
</view>
</view>
</view>
<view class="pg-info module" v-if="detailInfo.workStatus == 'END'">
<view class="title">质检信息</view>
<view class="cont">
<view class="item">
<view class="label">合格数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="qualifiedAmount" />
<!-- <input class="uni-input" type="number" v-model="qualifiedAmount" placeholder="请输入数量" /> -->
</view>
</view>
<view class="item">
<view class="label">不合格数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="unqualifiedAmount" />
<!-- <input class="uni-input" type="number" v-model="unqualifiedAmount" placeholder="请输入数量" /> -->
</view>
</view>
<view class="item">
<view class="label">报废数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="scrapAmount" />
<!-- <input class="uni-input" type="number" v-model="scrapAmount" placeholder="请输入数量" /> -->
</view>
</view>
<view class="item">
<view class="label">返修数量</view>
<view class="val">
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="repairAmount" />
<!-- <input class="uni-input" type="number" v-model="repairAmount" placeholder="请输入数量" /> -->
</view>
</view>
</view>
</view>
</block>
<block v-if="isStaff">
<block v-if="detailInfo.workStatus == 'END'">
<view class="pg-info module">
<view class="title">领料退回量</view>
<view class="cont">
<view class="item" v-for="item in llArr" :key="item.id">
<view class="label">{{item.productName}}</view>
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="item.num" />
<!-- <input class="uni-input val" type="number" v-model="item.num" placeholder="请输入数量" /> -->
</view>
</view>
</view>
<view class="pg-info module">
<view class="title">加工损耗量</view>
<view class="cont">
<view class="item" v-for="item in tlArr" :key="item.id">
<view class="label">{{item.productName}}</view>
<uni-number-box type="number" :max="reportAmountMax" min="0" v-model="item.num" />
<!-- <input class="uni-input val input" type="number" v-model="item.num" placeholder="请输入数量" /> -->
</view>
</view>
</view>
</block>
<view class="action">
<view class="start item" v-if="detailInfo.workStatus == 'DEFAULT'" @click="handleStart"></view>
<view class="end item" v-if="detailInfo.workStatus == 'START'" @click="handleEnd"></view>
<view class="tjbg item" v-if="detailInfo.workStatus == 'END'" @click="handleBg"></view>
</view>
</block>
<block v-else>
<view class="action">
<view class="start item" v-if="detailInfo.workStatus == 'DEFAULT'" @click="handleStart"></view>
<view class="end item" v-if="detailInfo.workStatus == 'START'" @click="handleEnd"></view>
<view class="tjbg item" v-if="detailInfo.workStatus == 'END'" @click="handleBg"></view>
</view>
</block>
</view>
</template>
<script>
import {
getToken
} from '@/utils/auth'
import {
produceDetailApi,
produceOperateApi,
produceReportApi
} from '@/api/task-detail'
export default {
components: {},
data() {
return {
id: '',
status: '',
reportAmount: 0,
detailInfo: {},
statusText: '已开工',
llArr: [],
tlArr: [],
qualifiedAmount: 0,
unqualifiedAmount: 0,
scrapAmount: 0,
repairAmount: 0
};
},
computed: {
userInfo() {
return this.$store.state.user.userInfo || {};
},
isLogin() {
return !!getToken()
},
statusMap() {
return this.$store.state.user.statusMap || {};
},
isStaff() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType == 'PROCESS'
},
isQC() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType == 'QC'
},
produceGroupType() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType
},
reportAmountMax() {
return this.detailInfo.processingProductAmount - this.detailInfo.reportAmount
}
},
//
filters: {
formatDate: function(value) {
var date = new Date();
date.setTime(value);
var month = date.getMonth() + 1;
var hours = date.getHours();
if (hours < 10)
hours = "0" + hours;
var minutes = date.getMinutes();
if (minutes < 10)
minutes = "0" + minutes;
var time = date.getFullYear() + "-" + month + "-" + date.getDate() +
" " + hours + ":" + minutes;
return time;
}
},
onShow() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/login'
})
}
},
onLoad(option) {
this.status = option.status
this.id = option.id
this.statusText = this.statusMap[this.status] || '已开工',
this.initData()
},
methods: {
handleSQ() {
this.$refs.drawer.$refs.showLeft.open()
},
handleStart() {
const params = {
operate: 'START',
taskId: this.id,
taskType: this.produceGroupType
}
produceOperateApi(params).then(res => {
const {
code,
data,
msg
} = res
uni.navigateTo({
url: `/pages/bg-detail/index?id=${this.id}&status=${this.status}`
});
})
},
handleEnd() {
const params = {
operate: 'END',
taskId: this.id,
taskType: this.produceGroupType
}
produceOperateApi(params).then(res => {
const {
code,
data,
msg
} = res
uni.navigateTo({
url: `/pages/bg-detail/index?id=${this.id}&status=${this.status}`
});
})
},
//
handleBg() {
let params = {}
if (this.isStaff) {
const processDetailList = []
this.detailInfo.detailList.forEach(e => {
const objLl = this.llArr.find(q => q.id == e.id)
const objTl = this.tlArr.find(q => q.id == e.id)
const obj = {
id: e.id,
productId: e.productId,
returnAmount: objLl.num,
lossAmount: objTl.num
}
processDetailList.push(obj)
})
params = {
taskType: this.produceGroupType,
taskId: this.id,
reportAmount: this.reportAmount,
processDetailList
}
} else {
const qcDetail = {
qualifiedAmount: this.qualifiedAmount,
unqualifiedAmount: this.unqualifiedAmount,
scrapAmount: this.scrapAmount,
repairAmount: this.repairAmount
}
params = {
taskType: this.produceGroupType,
taskId: this.id,
reportAmount: this.reportAmount,
qcDetail
}
}
produceReportApi(params).then(res => {
const {
code,
data,
msg
} = res
uni.navigateTo({
url: `/pages/task-list/index`
});
})
},
initData() {
const taskType = this.$store.state.user.userInfo.produceGroupType
const params = {
id: this.id,
taskType
}
produceDetailApi(params).then(res => {
const {
code,
data,
msg
} = res
this.llArr = data.detailList.map(e => {
const obj = {
id: e.id,
productId: e.productId,
productName: e.productName,
num: 0
}
return obj
})
this.tlArr = data.detailList.map(e => {
const obj = {
id: e.id,
productId: e.productId,
productName: e.productName,
num: 0
}
return obj
})
this.detailInfo = data
})
}
}
}
</script>
<style lang="scss" scoped>
.detail {
width: 100%;
height: 100%;
background: #fff;
.module {
margin: 20rpx;
padding: 20rpx;
background: #fff;
border-radius: 20rpx;
box-shadow: 0px 0px 8px 0px rgba(161, 161, 177, 0.12);
.title {
font-size: 28rpx;
font-weight: 600;
padding-bottom: 8px;
color: #0D0D26;
border-bottom: 1px solid #eaeef1;
}
.cont {
background: #FAFAFD;
padding: 20rpx;
margin: 20rpx 0 10rpx;
.item {
margin: 20rpx 0;
display: flex;
.label {
color: #95969D;
margin-right: 20rpx;
font-size: 28rpx;
width: 140rpx;
&.name {
color: #356899;
font-size: 36rpx;
}
}
.val {
color: #0D0D26;
font-size: 28rpx;
&.yjd {
background: #E8FFEA;
color: #356899;
font-size: 24rpx;
padding: 6rpx 10rpx;
}
}
.uni-input {
border-bottom: 1px solid #95969D;
padding-bottom: 10rpx;
}
}
}
&.bgInfo {
display: flex;
justify-content: space-around;
.item {
flex: 1;
text-align: center;
.label {
font-size: 24rpx;
color: #95969D;
}
.val {
font-size: 32rpx;
color: #0D0D26;
margin-top: 10rpx;
}
}
}
}
.popup {
.table {
width: 400rpx;
}
}
.action {
border-top: 1px solid #95969D;
padding: 20rpx 0;
width: 100%;
margin: 40rpx auto;
display: flex;
justify-content: space-between;
align-items: center;
.item {
flex: 1;
color: #fff;
margin: 0 40rpx;
padding: 10px 0;
font-weight: 600;
border-radius: 20rpx;
font-size: 32rpx;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
&.bg {
background-color: #409eff;
}
&.llsq {
background-color: #FF7D00;
}
&.next {
background-color: #356899;
}
&.start {
background-color: #FF7D00;
}
&.end {
background-color: #356899;
}
&.tjbg {
background-color: #409eff;
}
}
}
}
</style>

@ -0,0 +1,43 @@
<template>
<view>
<uni-card class="view-title" :title="title">
<text class="uni-body view-content">{{ content }}</text>
</uni-card>
</view>
</template>
<script>
export default {
data() {
return {
title: '',
content: ''
}
},
onLoad(options) {
this.title = options.title
this.content = options.content
uni.setNavigationBarTitle({
title: options.title
})
}
}
</script>
<style scoped>
page {
background-color: #ffffff;
}
.view-title {
font-weight: bold;
}
.view-content {
font-size: 26rpx;
padding: 12px 5px 0;
color: #333;
line-height: 24px;
font-weight: normal;
}
</style>

@ -0,0 +1,34 @@
<template>
<view v-if="params.url">
<web-view :webview-styles="webviewStyles" :src="`${params.url}`"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
params: {},
webviewStyles: {
progress: {
color: "#FF3333"
}
}
}
},
props: {
src: {
type: [String],
default: null
}
},
onLoad(event) {
this.params = event
if (event.title) {
uni.setNavigationBarTitle({
title: event.title
})
}
}
}
</script>

@ -0,0 +1,295 @@
<template>
<view class="container">
<!-- 导航栏 -->
<view class="module-tongji">
<view class="title">统计</view>
<view class="module-cont">
<view class="left" @click="handleTJclick('RECEIVED')">
<view class="hd">
<view class="text1">已接单</view>
<view class="text2">{{tjData.RECEIVED}}<text class="text3"> </text></view>
</view>
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/yjd.png"></image>
</view>
<view class="right">
<view class="item" @click="handleTJclick('PROCESSING')">
<view class="hd">
<view class="text1">进行中</view>
<view class="text2">{{tjData.PROCESSING}}<text class="text3"> </text></view>
</view>
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/jxz.png"></image>
</view>
<view class="item" @click="handleTJclick('FINISHED')">
<view class="hd">
<view class="text1">已完成</view>
<view class="text2">{{tjData.FINISHED}}<text class="text3"> </text></view>
</view>
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/dwc.png"></image>
</view>
</view>
</view>
</view>
<view class="module-task">
<view class="title">任务</view>
<view class="module-cont">
<view class="item" @click="handleTaskclick">
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/task-center.png"></image>
<text class="name">任务中心</text>
</view>
<view class="item" @click="handleTaskKg">
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/yjkg.png"></image>
<text class="name">一键开工</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { getToken } from '@/utils/auth'
import {
homeTjApi,
} from '@/api/home'
import {
taskListApi
} from '@/api/task-list'
export default {
name: 'index',
components: {},
data() {
return {
tjData: {
RECEIVED: 0,
PROCESSING: 0,
FINISHED: 0
}
}
},
computed: {
userInfo() {
return this.$store.state.user.userInfo || {};
},
produceGroupType() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType
}
// isLogin() {
// return !!getToken()
// }
},
onLoad() {
console.log("页面数据加载完成");
},
onShow() {
},
onReady() {
// console.log(uni.$u.getPx('18rpx')); // 750(rpx) 1rpx = 0.5px
console.log("页面渲染完成");
const isLogin = getToken()
if (isLogin) {
this.initData()
}
},
methods: {
//
handleTJclick(status) {
const url = '/pages/task-list/index?' + 'status=' + status
this.$tab.navigateTo(url)
},
//
handleTaskclick() {
const url = '/pages/task-center/index'
this.$tab.switchTab(url)
},
getKGlist(status) {
const params = {
pageNo: 1,
pageSize: 10,
taskType: this.produceGroupType,
status
}
return taskListApi(params)
},
//
handleTaskKg() {
this.getKGlist('PROCESSING').then(res => {
const { code, data, msg } = res
if (data.list && data.list.length) {
const id = data.list[0].id
const url = `/pages/bg-detail/index?id=${id}&status=RECEIVED`
this.$tab.navigateTo(url)
} else {
this.getKGlist('RECEIVED').then(res2 => {
const { code, data, msg } = res2
if (data.list && data.list.length) {
const id = data.list[0].id
const url = `/pages/bg-detail/index?id=${id}&status=RECEIVED`
this.$tab.navigateTo(url)
} else {
this.$modal.showToast("任务中心没有已接单任务,请联系管理员分派~");
}
})
}
})
},
initData() {
const taskType = this.$store.state.user.userInfo.produceGroupType
const params = {
taskType
}
homeTjApi(params).then(res => {
const user = res.data
this.tjData = {
...this.tjData,
...user
}
}).catch(error => {
reject(error)
})
}
}
}
</script>
<style lang="scss" scoped>
//
.container ::v-deep {
height: 100vh;
background-color: #f2f2f2;
.module-tongji {
background-color: #fff;
margin: 20rpx;
padding: 20rpx;
border-radius: 10rpx;
box-sizing: border-box;
box-shadow: 0px 0px 20rpx 0px rgba(0, 0, 0, 0.15);
.title {
padding-bottom: 8rpx;
font-size: 16px;
font-weight: 600;
color: #666666;
border-bottom: 2rpx solid #f2f2f2;
}
.module-cont {
display: flex;
width: 100%;
justify-content: space-around;
align-items: center;
.left {
width: 320rpx;
height: 260rpx;
padding: 20rpx;
background: #F4F6F8;
border-radius: 10rpx;
position: relative;
margin-right: 20rpx;
.hd {
.text1 {
color: #0D0D26;
font-size: 28rpx;
}
.text2 {
color: #0D0D26;
margin-top: 6rpx;
font-size: 32rpx;
}
.text3 {
color: #0D0D26;
font-size: 20rpx;
margin-left: 6rpx;
}
}
.img {
width: 80px;
height: 60px;
position: absolute;
right: 0;
bottom: 0rpx;
}
}
.right {
width: 320rpx;
.item {
background: #F4F6F8;
height: 120rpx;
width: 314rpx;
margin: 10px 0;
padding: 10px;
border-radius: 10rpx;
position: relative;
.hd {
.text1 {
color: #0D0D26;
font-size: 28rpx;
}
.text2 {
color: #0D0D26;
font-size: 32rpx;
margin-top: 6rpx;
}
.text3 {
color: #0D0D26;
font-size: 20rpx;
margin-left: 6rpx;
}
}
.img {
position: absolute;
right: 0;
bottom: 0rpx;
width: 32px;
height: 23px;
}
}
}
}
}
.module-task {
background-color: #fff;
margin: 20rpx;
padding: 20rpx;
border-radius: 10rpx;
box-sizing: border-box;
box-shadow: 0px 0px 20rpx 0px rgba(0, 0, 0, 0.15);
.title {
padding-bottom: 8rpx;
font-size: 16px;
font-weight: 600;
color: #666666;
border-bottom: 2rpx solid #f2f2f2;
}
.module-cont {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
margin: 0 40rpx;
.item {
box-sizing: content-box;
padding: 36rpx 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-right: 40rpx;
.img {
width: 50px;
height: 50px;
}
.name {
margin-top: 20rpx;
color: #666666;
}
}
}
}
}
</style>

@ -0,0 +1,213 @@
<template>
<view class="normal-login-container">
<view class="logo-content align-center justify-center flex">
<image style="width: 160rpx;height: 160rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
</image>
</view>
<view class="login-form-content">
<view class="input-item flex align-center">
<view class="iconfont icon-user icon"></view>
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入用户名称" maxlength="30" />
</view>
<view class="input-item flex align-center">
<view class="iconfont icon-password icon"></view>
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入登录密码"
maxlength="20" />
</view>
<view class="action-btn">
<button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button>
</view>
<view class="reg text-center" v-if="register">
<text class="text-grey1">没有账号</text>
<text @click="handleUserRegister" class="text-blue">立即注册</text>
</view>
<view class="xieyi text-center">
<text class="text-grey1">登录即代表同意</text>
<text @click="handleUserAgrement" class="text-blue">用户协议</text>
<text @click="handlePrivacy" class="text-blue">隐私协议</text>
</view>
</view>
</view>
</template>
<script>
import {
getCodeImg
} from '@/api/login'
export default {
data() {
return {
codeUrl: "",
captchaEnabled: true,
//
register: false,
globalConfig: getApp().globalData.config,
loginForm: {
username: "",
password: "",
// username: "changjiang",
// password: "1qaz@WSX",
// username: "shengdan",
// password: "1qaz@WSX"
}
}
},
created() {
// this.getCode()
},
methods: {
//
handleUserRegister() {
this.$tab.redirectTo(`/pages/register`)
},
//
handlePrivacy() {
let site = this.globalConfig.appInfo.agreements[0]
this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
},
//
handleUserAgrement() {
let site = this.globalConfig.appInfo.agreements[1]
this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
},
//
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = 'data:image/gif;base64,' + res.img
this.loginForm.uuid = res.uuid
}
})
},
//
async handleLogin() {
// if (this.loginForm.username === "") {
// this.$modal.msgError("")
// } else if (this.loginForm.password === "") {
// this.$modal.msgError("")
// } else if (this.loginForm.code === "" && this.captchaEnabled) {
// this.$modal.msgError("")
// } else {
// this.$modal.loading("...")
// this.pwdLogin()
// }
if (this.loginForm.username === "") {
this.$modal.msgError("请输入您的账号")
} else if (this.loginForm.password === "") {
this.$modal.msgError("请输入您的密码")
} else {
this.$modal.loading("登录中,请耐心等待...")
this.getUserId()
}
},
getUserId() {
this.$store.dispatch('GetUserId', this.loginForm).then(() => {
this.pwdLogin()
}).catch((e) => {
console.error(e)
})
},
//
async pwdLogin() {
this.$store.dispatch('Login', this.loginForm).then((res) => {
this.$modal.closeLoading()
this.loginSuccess(res.userId)
}).catch((e) => {
console.error(e)
// if (this.captchaEnabled) {
// this.getCode()
// }
})
},
//
loginSuccess(userId) {
//
this.$store.dispatch('GetInfo', userId).then(res => {
this.$tab.reLaunch('/pages/index')
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.normal-login-container {
width: 100%;
.logo-content {
width: 100%;
font-size: 21px;
text-align: center;
padding-top: 15%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
}
}
.login-form-content {
text-align: center;
margin: 10px auto;
margin-top: 15%;
width: 80%;
.input-item {
margin: 20px auto;
background-color: #f5f6f7;
height: 45px;
border-radius: 20px;
.icon {
font-size: 38rpx;
margin-left: 10px;
color: #999;
}
.input {
width: 100%;
font-size: 14px;
line-height: 20px;
text-align: left;
padding-left: 15px;
}
}
.login-btn {
margin-top: 40px;
height: 45px;
}
.reg {
margin-top: 15px;
}
.xieyi {
color: #333;
margin-top: 20px;
}
.login-code {
height: 38px;
float: right;
.login-code-img {
height: 38px;
position: absolute;
margin-left: 10px;
width: 200rpx;
}
}
}
}
</style>

@ -0,0 +1,75 @@
<template>
<view class="about-container">
<view class="header-section text-center">
<image style="width: 150rpx;height: 150rpx;" src="/static/logo200.png" mode="widthFix">
</image>
<uni-title type="h2" title="合立报工小程序"></uni-title>
</view>
<view class="content-section">
<view class="menu-list">
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>版本信息</view>
<view class="text-right">v{{version}}</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>官方邮箱</view>
<view class="text-right">heli@xx.com</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>服务热线</view>
<view class="text-right">400-999-9999</view>
</view>
</view>
<view class="list-cell list-cell-arrow">
<view class="menu-item-box">
<view>公司网站</view>
<view class="text-right">
<uni-link :href="url" :text="url" showUnderLine="false"></uni-link>
</view>
</view>
</view>
</view>
</view>
<view class="copyright">
<view>Copyright &copy; 2025 长江云息数字科技 出品.</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
url: getApp().globalData.config.appInfo.site_url,
version: getApp().globalData.config.appInfo.version
}
}
}
</script>
<style lang="scss">
page {
background-color: #f8f8f8;
}
.copyright {
margin-top: 50rpx;
text-align: center;
line-height: 60rpx;
color: #999;
}
.header-section {
display: flex;
padding: 30rpx 0 0;
flex-direction: column;
align-items: center;
}
</style>

@ -0,0 +1,631 @@
<template>
<view class="container">
<view class="page-body uni-content-info">
<view class='cropper-content'>
<view v-if="isShowImg" class="uni-corpper" :style="'width:'+cropperInitW+'px;height:'+cropperInitH+'px;background:#000'">
<view class="uni-corpper-content" :style="'width:'+cropperW+'px;height:'+cropperH+'px;left:'+cropperL+'px;top:'+cropperT+'px'">
<image :src="imageSrc" :style="'width:'+cropperW+'px;height:'+cropperH+'px'"></image>
<view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove" @touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd"
:style="'left:'+cutL+'px;top:'+cutT+'px;right:'+cutR+'px;bottom:'+cutB+'px'">
<view class="uni-cropper-view-box">
<view class="uni-cropper-dashed-h"></view>
<view class="uni-cropper-dashed-v"></view>
<view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-tr" data-drag="topTight"></view>
<view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove" @touchend.stop="dragEnd"></view>
<view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view>
<view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-lt" data-drag="leftTop"></view>
</view>
</view>
</view>
</view>
</view>
<view class='cropper-config'>
<button type="primary reverse" @click="getImage" style='margin-top: 30rpx;'> 选择头像 </button>
<button type="warn" @click="getImageInfo" style='margin-top: 30rpx;'> 提交 </button>
</view>
<canvas canvas-id="myCanvas" :style="'position:absolute;border: 1px solid red; width:'+imageW+'px;height:'+imageH+'px;top:-9999px;left:-9999px;'"></canvas>
</view>
</view>
</template>
<script>
import config from '@/config'
import store from "@/store"
import { uploadAvatar } from "@/api/system/user"
const baseUrl = config.baseUrl
let sysInfo = uni.getSystemInfoSync()
let SCREEN_WIDTH = sysInfo.screenWidth
let PAGE_X, // x
PAGE_Y, // y
PR = sysInfo.pixelRatio, // dpi
T_PAGE_X, // x
T_PAGE_Y, // Y
CUT_L, // left
CUT_T, // top
CUT_R, //
CUT_B, //
CUT_W, //
CUT_H, //
IMG_RATIO, //
IMG_REAL_W, //
IMG_REAL_H, //
DRAFG_MOVE_RATIO = 1, //,
INIT_DRAG_POSITION = 100, //
DRAW_IMAGE_W = sysInfo.screenWidth //
export default {
/**
* 页面的初始数据
*/
data() {
return {
imageSrc: store.getters.avatar,
isShowImg: false,
//
cropperInitW: SCREEN_WIDTH,
cropperInitH: SCREEN_WIDTH,
//
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH,
// left top
cropperL: 0,
cropperT: 0,
transL: 0,
transT: 0,
//
scaleP: 0,
imageW: 0,
imageH: 0,
//
cutL: 0,
cutT: 0,
cutB: SCREEN_WIDTH,
cutR: '100%',
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: DRAFG_MOVE_RATIO
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
this.loadImage()
},
methods: {
setData: function (obj) {
let that = this
Object.keys(obj).forEach(function (key) {
that.$set(that.$data, key, obj[key])
})
},
getImage: function () {
var _this = this
uni.chooseImage({
success: function (res) {
_this.setData({
imageSrc: res.tempFilePaths[0],
})
_this.loadImage()
},
})
},
loadImage: function () {
var _this = this
uni.getImageInfo({
src: _this.imageSrc,
success: function success(res) {
IMG_RATIO = 1 / 1
if (IMG_RATIO >= 1) {
IMG_REAL_W = SCREEN_WIDTH
IMG_REAL_H = SCREEN_WIDTH / IMG_RATIO
} else {
IMG_REAL_W = SCREEN_WIDTH * IMG_RATIO
IMG_REAL_H = SCREEN_WIDTH
}
let minRange = IMG_REAL_W > IMG_REAL_H ? IMG_REAL_W : IMG_REAL_H
INIT_DRAG_POSITION = minRange > INIT_DRAG_POSITION ? INIT_DRAG_POSITION : minRange
//
if (IMG_RATIO >= 1) {
let cutT = Math.ceil((SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - INIT_DRAG_POSITION)) / 2)
let cutB = cutT
let cutL = Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH + INIT_DRAG_POSITION) / 2)
let cutR = cutL
_this.setData({
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH / IMG_RATIO,
// left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
//
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
} else {
let cutL = Math.ceil((SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO)) / 2)
let cutR = cutL
let cutT = Math.ceil((SCREEN_WIDTH - INIT_DRAG_POSITION) / 2)
let cutB = cutT
_this.setData({
cropperW: SCREEN_WIDTH * IMG_RATIO,
cropperH: SCREEN_WIDTH,
// left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
//
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
}
_this.setData({
isShowImg: true
})
uni.hideLoading()
}
})
},
// touchStart
contentStartMove(e) {
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
// touchMove
contentMoveing(e) {
var _this = this
var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
//
if (dragLengthX > 0) {
if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL
} else {
if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR
}
if (dragLengthY > 0) {
if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT
} else {
if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB
}
this.setData({
cutL: this.cutL - dragLengthX,
cutT: this.cutT - dragLengthY,
cutR: this.cutR + dragLengthX,
cutB: this.cutB + dragLengthY
})
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
contentTouchEnd() {
},
//
getImageInfo() {
var _this = this
uni.showLoading({
title: '图片生成中...',
})
//
const ctx = uni.createCanvasContext('myCanvas')
ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H)
ctx.draw(true, () => {
// * canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W
var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H
var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W
var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H
uni.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW,
destHeight: canvasH,
quality: 0.5,
canvasId: 'myCanvas',
success: function (res) {
uni.hideLoading()
let data = {name: 'avatarfile', filePath: res.tempFilePath}
uploadAvatar(data).then(response => {
store.commit('SET_AVATAR', baseUrl + response.imgUrl)
uni.showToast({ title: "修改成功", icon: 'success' })
uni.navigateBack()
})
}
})
})
},
// touchStart
dragStart(e) {
T_PAGE_X = e.touches[0].pageX
T_PAGE_Y = e.touches[0].pageY
CUT_L = this.cutL
CUT_R = this.cutR
CUT_B = this.cutB
CUT_T = this.cutT
},
// touchMove
dragMove(e) {
var _this = this
var dragType = e.target.dataset.drag
switch (dragType) {
case 'right':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_R + dragLength < 0) dragLength = -CUT_R
this.setData({
cutR: CUT_R + dragLength
})
break
case 'left':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_L - dragLength < 0) dragLength = CUT_L
if ((CUT_L - dragLength) > (this.cropperW - this.cutR)) dragLength = CUT_L - (this.cropperW - this.cutR)
this.setData({
cutL: CUT_L - dragLength
})
break
case 'top':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_T - dragLength < 0) dragLength = CUT_T
if ((CUT_T - dragLength) > (this.cropperH - this.cutB)) dragLength = CUT_T - (this.cropperH - this.cutB)
this.setData({
cutT: CUT_T - dragLength
})
break
case 'bottom':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLength < 0) dragLength = -CUT_B
this.setData({
cutB: CUT_B + dragLength
})
break
case 'rightBottom':
var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B
if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R
let cutB = CUT_B + dragLengthY
let cutR = CUT_R + dragLengthX
this.setData({
cutB: cutB,
cutR: cutR
})
break
default:
break
}
}
}
}
</script>
<style>
/* pages/uni-cropper/index.wxss */
.uni-content-info {
/* position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block;
align-items: center;
flex-direction: column; */
}
.cropper-config {
padding: 20rpx 40rpx;
}
.cropper-content {
min-height: 750rpx;
width: 100%;
}
.uni-corpper {
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
box-sizing: border-box;
}
.uni-corpper-content {
position: relative;
}
.uni-corpper-content image {
display: block;
width: 100%;
min-width: 0 !important;
max-width: none !important;
height: 100%;
min-height: 0 !important;
max-height: none !important;
image-orientation: 0deg !important;
margin: 0 auto;
}
/* 移动图片效果 */
.uni-cropper-drag-box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: move;
background: rgba(0, 0, 0, 0.6);
z-index: 1;
}
/* 内部的信息 */
.uni-corpper-crop-box {
position: absolute;
background: rgba(255, 255, 255, 0.3);
z-index: 2;
}
.uni-corpper-crop-box .uni-cropper-view-box {
position: relative;
display: block;
width: 100%;
height: 100%;
overflow: visible;
outline: 1rpx solid #69f;
outline-color: rgba(102, 153, 255, .75)
}
/* 横向虚线 */
.uni-cropper-dashed-h {
position: absolute;
top: 33.33333333%;
left: 0;
width: 100%;
height: 33.33333333%;
border-top: 1rpx dashed rgba(255, 255, 255, 0.5);
border-bottom: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 纵向虚线 */
.uni-cropper-dashed-v {
position: absolute;
left: 33.33333333%;
top: 0;
width: 33.33333333%;
height: 100%;
border-left: 1rpx dashed rgba(255, 255, 255, 0.5);
border-right: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 四个方向的线 为了之后的拖动事件*/
.uni-cropper-line-t {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
top: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: n-resize;
}
.uni-cropper-line-t::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-r {
position: absolute;
display: block;
background-color: #69f;
top: 0;
right: 0rpx;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: e-resize;
}
.uni-cropper-line-r::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-line-b {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
bottom: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: s-resize;
}
.uni-cropper-line-b::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-l {
position: absolute;
display: block;
background-color: #69f;
top: 0;
left: 0;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: w-resize;
}
.uni-cropper-line-l::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-point {
width: 5rpx;
height: 5rpx;
background-color: #69f;
opacity: .75;
position: absolute;
z-index: 3;
}
.point-t {
top: -3rpx;
left: 50%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-tr {
top: -3rpx;
left: 100%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-r {
top: 50%;
left: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-rb {
left: 100%;
top: 100%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
cursor: n-resize;
width: 36rpx;
height: 36rpx;
background-color: #69f;
position: absolute;
z-index: 1112;
opacity: 1;
}
.point-b {
left: 50%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-bl {
left: 0%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-l {
left: 0%;
top: 50%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-lt {
left: 0%;
top: 0%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
/* 裁剪框预览内容 */
.uni-cropper-viewer {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.uni-cropper-viewer image {
position: absolute;
z-index: 2;
}
</style>

@ -0,0 +1,112 @@
<template>
<view class="help-container">
<view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title">
<view class="text-title">
<view :class="item.icon"></view>{{ item.title }}
</view>
<view class="childList">
<view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover"
@click="handleText(child)">
<view class="text-item">{{ child.title }}</view>
<view class="line" v-if="zindex !== item.childList.length - 1"></view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: [{
icon: 'iconfont icon-github',
title: '合立报工问题',
childList: [{
title: '合立报工开源吗?',
content: '开源'
}, {
title: '合立报工可以商用吗?',
content: '可以'
}, {
title: '合立报工官网地址多少?',
content: 'http://ruoyi.vip'
}, {
title: '合立报工文档地址多少?',
content: 'http://doc.ruoyi.vip'
}]
},
{
icon: 'iconfont icon-help',
title: '其他问题',
childList: [{
title: '如何退出登录?',
content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录',
}, {
title: '如何修改用户头像?',
content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像',
}, {
title: '如何修改登录密码?',
content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码',
}]
}
]
}
},
methods: {
handleText(item) {
this.$tab.navigateTo(`/pages/common/textview/index?title=${item.title}&content=${item.content}`)
}
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #f8f8f8;
}
.help-container {
margin-bottom: 100rpx;
padding: 30rpx;
}
.list-title {
margin-bottom: 30rpx;
}
.childList {
background: #ffffff;
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
border-radius: 16rpx;
margin-top: 10rpx;
}
.line {
width: 100%;
height: 1rpx;
background-color: #F5F5F5;
}
.text-title {
color: #303133;
font-size: 32rpx;
font-weight: bold;
margin-left: 10rpx;
.iconfont {
font-size: 16px;
margin-right: 10rpx;
}
}
.text-item {
font-size: 28rpx;
padding: 24rpx;
}
.question {
color: #606266;
font-size: 28rpx;
}
</style>

@ -0,0 +1,247 @@
<template>
<view class="mine-container" :style="{height: `${windowHeight}px`}">
<view class="header-section">
<view class="header-people">
<view class="left">
<image class="img" mode="aspectFit" :src="userInfo.avatar"></image>
<view class="people-info">
<view class="name">{{userInfo.nickname || '默认name'}}</view>
<view class="iphone">{{userInfo.mobile || '默认122'}}</view>
</view>
</view>
<view class="right">
</view>
</view>
<view class="future">
<image class="img" mode="aspectFit" src="http://118.195.155.9:8112/hl/mine-future.png"></image>
</view>
<view class="logout">
<view class="title" v-if="!isLogin" @click="handleLogin"></view>
<view class="title" v-else @click="handleLogout">退</view>
</view>
</view>
</view>
</template>
<script>
import { getToken } from '@/utils/auth'
import storage from "@/utils/storage";
export default {
components: {
},
data() {
return {
current: 1,
// name: this.$store.state.user.userInfo.name || 'name',
// mobile: this.$store.state.user.userInfo.mobile || '111',
version: getApp().globalData.config.appInfo.version
};
},
computed: {
userInfo() {
return this.$store.state.user.userInfo || {};
},
avatar() {
return this.$store.state.user.avatar;
},
windowHeight() {
return uni.getSystemInfoSync().windowHeight - 50;
},
isLogin() {
return !!getToken()
}
},
methods: {
handleToInfo() {
this.$modal.showToast("模块建设中~");
// this.$tab.navigateTo("/pages/mine/info/index");
},
handleToEditInfo() {
this.$modal.showToast("模块建设中~");
// this.$tab.navigateTo("/pages/mine/info/edit");
},
handleToSetting() {
this.$tab.navigateTo("/pages/mine/setting/index");
},
handleToLogin() {
this.$tab.reLaunch("/pages/login");
},
handleToAvatar() {
this.$tab.navigateTo("/pages/mine/avatar/index");
},
handleLogin() {
this.$tab.reLaunch("/pages/login");
},
handleLogout() {
this.$modal.confirm("确定注销并退出系统吗?").then(() => {
this.$store.dispatch("LogOut").then(() => {
this.$tab.reLaunch("/pages/index");
});
});
},
handleHelp() {
// this.$modal.showToast("~");
this.$tab.navigateTo("/pages/login");
},
handleAbout() {
this.$modal.showToast("模块建设中~");
// this.$tab.navigateTo("/pages/mine/about/index");
},
handleBuilding() {
this.$modal.showToast("模块建设中~");
}
}
};
</script>
<style lang="scss" scoped>
.mine-container {
width: 100%;
height: 100%;
position: relative;
.header-section {
padding: 16px 16px 0;
.header-people {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 50px;
.left {
display: flex;
flex: 1;
justify-content: flex-start;
align-items: center;
.img {
width: 80rpx;
height: 80rpx;
background-color: #fff;
border-radius: 50%;
margin-right: 10px;
}
.people-info {
.name {
color: #0D0D26;
font-weight: 500;
font-size: 32rpx;
}
.iphone {
margin-top: 6px;
font-size: 14px;
color: #95969D;
}
}
}
.right {
padding: 4px 10px;
border-radius: 10px;
text-align: center;
display: flex;
align-items: center;
.img {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: red;
margin-right: 10px;
}
.vip {
color: #0D0D26;
}
}
}
.header-info {
background-color: #fff;
padding: 16px 10px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
.item {
text-align: center;
.num {
margin-bottom: 4px;
color: #0D0D26;
font-size: 18px;
font-weight: 500;
font-family: Source Han Sans;
}
.txt {
color: #95969D;
font-size: 12px;
font-family: Source Han Sans;
}
&.warn {
.num {
margin-bottom: 4px;
color: #E30000;
font-size: 18px;
}
.txt {
color: #E30000;
font-size: 12px;
}
}
}
}
}
.future {
min-height: 400rpx;
.img {
width: 100vw;
height: 538rpx;
}
}
.logout {
width: 412rpx;
margin: 60rpx auto;
background: #356899;
padding: 10px 20rpx;
border-radius: 10rpx;
text-align: center;
.title {
color: #fff;
font-size: 28rpx;
font-weight: 500;
}
}
.content-section {
position: relative;
top: -50px;
.mine-actions {
margin: 15px 15px;
padding: 20px 0px;
border-radius: 8px;
background-color: white;
.action-item {
.icon {
font-size: 28px;
}
.text {
display: block;
font-size: 13px;
margin: 8px 0px;
}
}
}
}
}
</style>

@ -0,0 +1,127 @@
<template>
<view class="container">
<view class="example">
<uni-forms ref="form" :model="user" labelWidth="80px">
<uni-forms-item label="用户昵称" name="nickName">
<uni-easyinput v-model="user.nickName" placeholder="请输入昵称" />
</uni-forms-item>
<uni-forms-item label="手机号码" name="phonenumber">
<uni-easyinput v-model="user.phonenumber" placeholder="请输入手机号码" />
</uni-forms-item>
<uni-forms-item label="邮箱" name="email">
<uni-easyinput v-model="user.email" placeholder="请输入邮箱" />
</uni-forms-item>
<uni-forms-item label="性别" name="sex" required>
<uni-data-checkbox v-model="user.sex" :localdata="sexs" />
</uni-forms-item>
</uni-forms>
<button type="primary" @click="submit"></button>
</view>
</view>
</template>
<script>
import { getUserProfile } from "@/api/system/user"
import { updateUserProfile } from "@/api/system/user"
export default {
data() {
return {
user: {
nickName: "",
phonenumber: "",
email: "",
sex: ""
},
sexs: [{
text: '男',
value: "0"
}, {
text: '女',
value: "1"
}],
rules: {
nickName: {
rules: [{
required: true,
errorMessage: '用户昵称不能为空'
}]
},
phonenumber: {
rules: [{
required: true,
errorMessage: '手机号码不能为空'
}, {
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
errorMessage: '请输入正确的手机号码'
}]
},
email: {
rules: [{
required: true,
errorMessage: '邮箱地址不能为空'
}, {
format: 'email',
errorMessage: '请输入正确的邮箱地址'
}]
}
}
}
},
onLoad() {
this.getUser()
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
getUser() {
getUserProfile().then(response => {
this.user = response.data
})
},
submit(ref) {
this.$refs.form.validate().then(res => {
updateUserProfile(this.user).then(response => {
this.$modal.msgSuccess("修改成功")
})
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.example {
padding: 15px;
background-color: #fff;
}
.segmented-control {
margin-bottom: 15px;
}
.button-group {
margin-top: 15px;
display: flex;
justify-content: space-around;
}
.form-item {
display: flex;
align-items: center;
flex: 1;
}
.button {
display: flex;
align-items: center;
height: 35px;
line-height: 35px;
margin-left: 10px;
}
</style>

@ -0,0 +1,44 @@
<template>
<view class="container">
<uni-list>
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="昵称" :rightText="user.nickName" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'phone-filled'}" title="手机号码" :rightText="user.phonenumber" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'email-filled'}" title="邮箱" :rightText="user.email" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'auth-filled'}" title="岗位" :rightText="postGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'staff-filled'}" title="角色" :rightText="roleGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'calendar-filled'}" title="创建日期" :rightText="user.createTime" />
</uni-list>
</view>
</template>
<script>
import { getUserProfile } from "@/api/system/user"
export default {
data() {
return {
user: {},
roleGroup: "",
postGroup: ""
}
},
onLoad() {
this.getUser()
},
methods: {
getUser() {
getUserProfile().then(response => {
this.user = response.data
this.roleGroup = response.roleGroup
this.postGroup = response.postGroup
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
</style>

@ -0,0 +1,85 @@
<template>
<view class="pwd-retrieve-container">
<uni-forms ref="form" :value="user" labelWidth="80px">
<uni-forms-item name="oldPassword" label="旧密码">
<uni-easyinput type="password" v-model="user.oldPassword" placeholder="请输入旧密码" />
</uni-forms-item>
<uni-forms-item name="newPassword" label="新密码">
<uni-easyinput type="password" v-model="user.newPassword" placeholder="请输入新密码" />
</uni-forms-item>
<uni-forms-item name="confirmPassword" label="确认密码">
<uni-easyinput type="password" v-model="user.confirmPassword" placeholder="请确认新密码" />
</uni-forms-item>
<button type="primary" @click="submit"></button>
</uni-forms>
</view>
</template>
<script>
import { updateUserPwd } from "@/api/system/user"
export default {
data() {
return {
user: {
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
},
rules: {
oldPassword: {
rules: [{
required: true,
errorMessage: '旧密码不能为空'
}]
},
newPassword: {
rules: [{
required: true,
errorMessage: '新密码不能为空',
},
{
minLength: 6,
maxLength: 20,
errorMessage: '长度在 6 到 20 个字符'
}
]
},
confirmPassword: {
rules: [{
required: true,
errorMessage: '确认密码不能为空'
}, {
validateFunction: (rule, value, data) => data.newPassword === value,
errorMessage: '两次输入的密码不一致'
}
]
}
}
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
submit() {
this.$refs.form.validate().then(res => {
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
this.$modal.msgSuccess("修改成功")
})
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.pwd-retrieve-container {
padding-top: 36rpx;
padding: 15px;
}
</style>

@ -0,0 +1,78 @@
<template>
<view class="setting-container" :style="{height: `${windowHeight}px`}">
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleToPwd">
<view class="menu-item-box">
<view class="iconfont icon-password menu-icon"></view>
<view>修改密码</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleToUpgrade">
<view class="menu-item-box">
<view class="iconfont icon-refresh menu-icon"></view>
<view>检查更新</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleCleanTmp">
<view class="menu-item-box">
<view class="iconfont icon-clean menu-icon"></view>
<view>清理缓存</view>
</view>
</view>
</view>
<view class="cu-list menu">
<view class="cu-item item-box">
<view class="content text-center" @click="handleLogout">
<text class="text-black">退出登录</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
windowHeight: uni.getSystemInfoSync().windowHeight
}
},
methods: {
handleToPwd() {
this.$tab.navigateTo('/pages/mine/pwd/index')
},
handleToUpgrade() {
this.$modal.showToast('模块建设中~')
},
handleCleanTmp() {
this.$modal.showToast('模块建设中~')
},
handleLogout() {
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
this.$store.dispatch('LogOut').then(() => {
this.$tab.reLaunch('/pages/index')
})
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
background-color: #f8f8f8;
}
.item-box {
background-color: #FFFFFF;
margin: 30rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 10rpx;
border-radius: 8rpx;
color: #303133;
font-size: 32rpx;
}
</style>

@ -0,0 +1,112 @@
<template>
<view class="container">
<view class="news-list">
<view class="item" v-for="(item,index) in newsList" :key="item.id">
<view class="msg">{{item.msg}}</view>
<view class="time">{{item.time}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
newsList: [{
id: 1,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 2,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 3,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 4,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 5,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 6,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 7,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 8,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 9,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 10,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
},
{
id: 11,
msg: '您有新的工序质检,请及时处理',
time: '2022-07-09 15:00:00'
}
]
}
},
methods: {
backClick() {
uni.switchTab({
url: '/pages/index/index'
});
}
}
}
</script>
<style lang="scss" scoped>
.container {
background: #f9f9f9;
.news-list {
.item {
margin: 10px 10px;
border-radius: 4px;
padding: 10px 10px 8px;
background-color: #ffffff;
box-sizing: border-box;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15);
.msg {
font-size: 14px;
color: #333333;
font-weight: 600;
}
.time {
color: #666;
font-size: 12px;
}
}
}
}
</style>

@ -0,0 +1,195 @@
<template>
<view class="normal-login-container">
<view class="logo-content align-center justify-center flex">
<image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
</image>
<text class="title">合立报工移动端注册</text>
</view>
<view class="login-form-content">
<view class="input-item flex align-center">
<view class="iconfont icon-user icon"></view>
<input v-model="registerForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
</view>
<view class="input-item flex align-center">
<view class="iconfont icon-password icon"></view>
<input v-model="registerForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
</view>
<view class="input-item flex align-center">
<view class="iconfont icon-password icon"></view>
<input v-model="registerForm.confirmPassword" type="password" class="input" placeholder="请输入重复密码" maxlength="20" />
</view>
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
<view class="iconfont icon-code icon"></view>
<input v-model="registerForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
<view class="login-code">
<image :src="codeUrl" @click="getCode" class="login-code-img"></image>
</view>
</view>
<view class="action-btn">
<button @click="handleRegister()" class="register-btn cu-btn block bg-blue lg round">注册</button>
</view>
</view>
<view class="xieyi text-center">
<text @click="handleUserLogin" class="text-blue">使用已有账号登录</text>
</view>
</view>
</template>
<script>
import { getCodeImg, register } from '@/api/login'
export default {
data() {
return {
codeUrl: "",
captchaEnabled: true,
globalConfig: getApp().globalData.config,
registerForm: {
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: ''
}
}
},
created() {
this.getCode()
},
methods: {
//
handleUserLogin() {
this.$tab.navigateTo(`/pages/login`)
},
//
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = 'data:image/gif;base64,' + res.img
this.registerForm.uuid = res.uuid
}
})
},
//
async handleRegister() {
if (this.registerForm.username === "") {
this.$modal.msgError("请输入您的账号")
} else if (this.registerForm.password === "") {
this.$modal.msgError("请输入您的密码")
} else if (this.registerForm.confirmPassword === "") {
this.$modal.msgError("请再次输入您的密码")
} else if (this.registerForm.password !== this.registerForm.confirmPassword) {
this.$modal.msgError("两次输入的密码不一致")
} else if (this.registerForm.code === "" && this.captchaEnabled) {
this.$modal.msgError("请输入验证码")
} else {
this.$modal.loading("注册中,请耐心等待...")
this.register()
}
},
//
async register() {
register(this.registerForm).then(res => {
this.$modal.closeLoading()
uni.showModal({
title: "系统提示",
content: "恭喜你,您的账号 " + this.registerForm.username + " 注册成功!",
success: function (res) {
if (res.confirm) {
uni.redirectTo({ url: `/pages/login` });
}
}
})
}).catch(() => {
if (this.captchaEnabled) {
this.getCode()
}
})
},
//
registerSuccess(result) {
//
this.$store.dispatch('GetInfo').then(res => {
this.$tab.reLaunch('/pages/index')
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #ffffff;
}
.normal-login-container {
width: 100%;
.logo-content {
width: 100%;
font-size: 21px;
text-align: center;
padding-top: 15%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
}
}
.login-form-content {
text-align: center;
margin: 20px auto;
margin-top: 15%;
width: 80%;
.input-item {
margin: 20px auto;
background-color: #f5f6f7;
height: 45px;
border-radius: 20px;
.icon {
font-size: 38rpx;
margin-left: 10px;
color: #999;
}
.input {
width: 100%;
font-size: 14px;
line-height: 20px;
text-align: left;
padding-left: 15px;
}
}
.register-btn {
margin-top: 40px;
height: 45px;
}
.xieyi {
color: #333;
margin-top: 20px;
}
.login-code {
height: 38px;
float: right;
.login-code-img {
height: 38px;
position: absolute;
margin-left: 10px;
width: 200rpx;
}
}
}
}
</style>

@ -0,0 +1,183 @@
<template>
<view class="task-center">
<view class="menu">
<uni-segmented-control :current="currentIndex" :values="menuList" @clickItem="handleMenuChange"
:styleType="menuObj.styleType" :activeColor="menuObj.activeColor">
</uni-segmented-control>
</view>
<!-- <view class="search">
<uni-search-bar v-model="keyword" @blur="onSearch" @clear="onClear" cancelButton="false"
placeholder="请输入搜索内容">
</uni-search-bar>
</view> -->
<view class="dataList">
<view v-for="(item,index) in dataList" :key="index">
<task-card :info="item"></task-card>
</view>
<view v-show="isLoadMore">
<uni-load-more :status="loadStatus" ></uni-load-more>
</view>
</view>
</view>
</template>
<script>
import { getToken } from '@/utils/auth'
import taskCard from '@/components/task-card/task-card.vue'
import {
taskListApi
} from '@/api/task-list'
export default {
name: "Task-list",
components: {
taskCard
},
data() {
return {
menuList: ['已接单', '进行中', '已完成'],
currentIndex: 0,
menuObj: {
activeColor: '#007aff',
styleType: 'button',
current: 1
},
titleObj: {
'pg': '派工任务',
'bg': '报工任务',
'zj': '质检任务',
'list': '任务列表'
},
tabObj: {
'pg': ['未开工', '已开工'],
'bg': ['未报工', '部分报工', '完成'],
'zj': ['未完成', '已完成']
},
pageNo: 1,
pageSize: 10,
isLoadMore:false, //
loadStatus:'loading', //more-loading-nomore-
dataList: [],
mapStatus: [
{
id: 0,
name: 'RECEIVED'
},
{
id: 1,
name: 'PROCESSING'
},
{
id: 2,
name: 'FINISHED'
}
],
keyword: ''
}
},
computed: {
isLogin() {
return !!getToken()
}
},
onLoad(option) {
// const type = option.type || 'pg'
// uni.setNavigationBarTitle({
// title: this.titleObj[type]
// })
// this.menuList = this.tabObj[type]
this.status = option.status
const obj = this.mapStatus.find(e => e.name == option.status)
this.currentIndex = obj.id
},
onShow() {
if (!this.isLogin) {
uni.navigateTo({ url: '/pages/login' })
} else {
this.getData()
}
},
onReachBottom() {
if(!this.isLoadMore){ //
this.isLoadMore = true
this.pageNo +=1
this.getData()
}
},
methods: {
handleMenuChange(e) {
if (this.currentIndex !== e.currentIndex) {
const obj = {
0: 'RECEIVED',
1: 'PROCESSING',
2: 'FINISHED'
}
this.status = obj[e.currentIndex]
this.currentIndex = e.currentIndex
this.dataList = []
this.pageNo = 1
this.getData(this.currentIndex)
}
},
onSearch() {
this.getData(this.currentIndex, this.keyword)
},
onClear() {},
//
getData() {
const _this = this
_this.isLoadMore = true
const taskType = this.$store.state.user.userInfo.produceGroupType
const params = {
pageNo: this.pageNo,
pageSize: this.pageSize,
taskType,
status: this.status
}
taskListApi(params).then(res => {
const { code, data, msg } = res
if (data.list.length) {
data.list.forEach(e => {
e.status = this.status
})
this.dataList.push(...data.list)
if (data.list < this.pageSize) {
this.loadStatus = 'nomore'
this.isLoadMore = true
} else {
this.isLoadMore = false
}
} else {
this.isLoadMore = true
this.loadStatus = 'nomore'
}
}).catch(error => {
this.isLoadMore = false
if (this.pageNo >1) {
this.pageNo -=1
}
reject(error)
})
}
}
}
</script>
<style lang="scss" scoped>
.task-center {
.menu {
margin: 10px 14px;
}
.search {
margin: 10px 4px;
}
.dataList {
width: 100%;
}
}
</style>

@ -0,0 +1,421 @@
<template>
<view class="detail">
<view class="base-info module">
<view class="title">派工单编号 #{{code}}</view>
<view class="cont">
<view class="item">
<view class="label">产品状态</view>
<view class="val yjd">{{statusMap[detailInfo.status]}}</view>
</view>
<view class="item">
<view class="label">产品名称</view>
<view class="val">{{detailInfo.productName}}</view>
</view>
<view class="item">
<view class="label">派工工序</view>
<view class="val">{{detailInfo.procedureName}}</view>
</view>
<view class="item">
<view class="label">任务编号</view>
<view class="val">{{detailInfo.code}}</view>
</view>
<view class="item">
<view class="label">完成时限</view>
<view class="val" v-if="detailInfo.startWorkTime">
{{detailInfo.startWorkTime | formatDate}} {{detailInfo.endWorkTime | formatDate}}
</view>
</view>
<view class="item">
<view class="label">派工数量</view>
<view class="val">{{detailInfo.processingProductAmount}}</view>
</view>
<view class="item">
<view class="label">预计工时</view>
<view class="val">{{detailInfo.predictWorkTime}}</view>
</view>
<view class="item">
<view class="label">总报工产量</view>
<view class="val">{{detailInfo.reportAmount}}</view>
</view>
<view class="item">
<view class="label">总实际工时</view>
<view class="val">{{detailInfo.workTime}}</view>
</view>
</view>
</view>
<view class="pg-info module" v-if="isQC">
<view class="cont">
<view class="item">
<view class="label">合格数量</view>
<view class="val">
{{ detailInfo.qualifiedAmount || 0 }}
</view>
</view>
<view class="item">
<view class="label">不合格数量</view>
<view class="val">
{{ detailInfo.unqualifiedAmount || 0 }}
</view>
</view>
<view class="item">
<view class="label">报废数量</view>
<view class="val">
{{ detailInfo.scrapAmount || 0 }}
</view>
</view>
<view class="item">
<view class="label">返修数量</view>
<view class="val">
{{ detailInfo.repairAmount || 0 }}
</view>
</view>
</view>
</view>
<view class="module" v-if="detailInfo.reportList && detailInfo.reportList.length">
<view class="title">历史报工明细</view>
<view class="cont" v-for="item in detailInfo.reportList" :key="item.id">
<view class="item">
<view class="label">生产开始时间</view>
<view class="val">{{item.startTime | formatDate}}</view>
</view>
<view class="item">
<view class="label">生产结束时间</view>
<view class="val">{{item.endTime | formatDate}}</view>
</view>
<view class="item">
<view class="label">报工产量</view>
<view class="val">{{item.reportAmount}}</view>
</view>
<view class="item">
<view class="label">实际工时</view>
<view class="val">{{item.realWorkTime}}</view>
</view>
<block v-if="isQC">
<view class="item">
<view class="label">合格数量</view>
<view class="val">0</view>
</view>
<view class="item">
<view class="label">不合格数量</view>
<view class="val">1</view>
</view>
<view class="item">
<view class="label">报废数量</view>
<view class="val">2</view>
</view>
<view class="item">
<view class="label">返修数量</view>
<view class="val">3</view>
</view>
</block>
</view>
</view>
<block v-if="status !=='FINISHED'">
<block v-if="isStaff">
<good-drawer @close="closeDrawer" @submit="handleLQSubmit" ref="drawer" :detailList="detailList">
</good-drawer>
<view class="action">
<view class="llsq item" @click="handleSQ"></view>
<view class="next item" @click="handleNext"></view>
</view>
</block>
<block v-else>
<view class="action">
<view class="next item" @click="handleNext"></view>
</view>
</block>
</block>
</view>
</template>
<script>
import goodDrawer from '@/components/good-drawer/good-drawer.vue'
import {
getToken
} from '@/utils/auth'
import {
produceDetailApi,
produceOperateApi,
produceReportApi,
produceRecieveApi
} from '@/api/task-detail'
export default {
components: {
goodDrawer
},
data() {
return {
id: '',
code: 0,
status: '',
detailInfo: {},
detailList: [],
statusText: '已开工'
};
},
computed: {
isLogin() {
return !!getToken()
},
statusMap() {
return this.$store.state.user.statusMap || {};
},
isStaff() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType == 'PROCESS'
},
isQC() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType == 'QC'
},
produceGroupType() {
const produceGroupType = this.$store.state.user.userInfo.produceGroupType || '';
return produceGroupType
}
},
onShow() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/login'
})
}
},
onLoad(option) {
this.status = option.status
this.id = option.id
this.code = option.code
this.statusText = this.statusMap[this.status] || '已开工',
this.initData()
},
//
filters: {
formatDate: function(value) {
var date = new Date();
date.setTime(value);
var month = date.getMonth() + 1;
var hours = date.getHours();
if (hours < 10)
hours = "0" + hours;
var minutes = date.getMinutes();
if (minutes < 10)
minutes = "0" + minutes;
var time = date.getFullYear() + "-" + month + "-" + date.getDate() +
" " + hours + ":" + minutes;
return time;
}
},
methods: {
handleSQ() {
this.$refs.drawer.$refs.showLeft.open()
},
handleLQSubmit(detailList) {
const params = {
taskId: this.id,
detailList
}
produceRecieveApi(params).then(res => {
const {
code,
data,
msg
} = res
this.$refs.drawer.$refs.showLeft.close()
})
},
closeDrawer() {
this.$refs.drawer.$refs.showLeft.close()
},
handleNext() {
uni.navigateTo({
url: `/pages/bg-detail/index?id=${this.id}&status=${this.status}`
});
},
initData() {
const taskType = this.$store.state.user.userInfo.produceGroupType
const params = {
id: this.id,
taskType
}
produceDetailApi(params).then(res => {
const {
code,
data,
msg
} = res
this.detailInfo = data
const dataList = data.detailList
this.detailList = dataList.map(e => {
const obj = {
id: e.id,
productId: e.productId,
productName: e.productName,
spec: e.spec,
receiveAmount: e.receiveAmount,
amount: 1
}
return obj
})
})
}
}
}
</script>
<style lang="scss" scoped>
.detail {
width: 100%;
height: 100%;
background: #fff;
.module {
margin: 20rpx;
padding: 20rpx;
background: #fff;
border-radius: 20rpx;
box-shadow: 0px 0px 8px 0px rgba(161, 161, 177, 0.12);
.title {
font-size: 28rpx;
font-weight: 600;
padding-bottom: 8px;
color: #0D0D26;
border-bottom: 1px solid #eaeef1;
}
.cont {
background: #FAFAFD;
padding: 20rpx;
margin: 20rpx 0 10rpx;
.item {
margin: 20rpx 0;
display: flex;
// justify-content: space-between;
.label {
color: #95969D;
margin-right: 20rpx;
font-size: 28rpx;
&.name {
color: #356899;
font-size: 36rpx;
}
}
.val {
color: #0D0D26;
font-size: 28rpx;
&.yjd {
background: #E8FFEA;
color: #356899;
font-size: 24rpx;
padding: 6rpx 10rpx;
}
}
}
}
&.bgInfo {
display: flex;
justify-content: space-around;
.item {
flex: 1;
text-align: center;
.label {
font-size: 24rpx;
color: #95969D;
}
.val {
font-size: 32rpx;
color: #0D0D26;
margin-top: 4rpx;
}
}
}
}
.pg-info {
.cont {
display: flex;
.item {
flex: 1;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
.val {
margin-top: 20rpx;
}
}
}
}
.popup {
.table {
width: 400rpx;
}
}
.action {
border-top: 1px solid #95969D;
padding: 20rpx 0;
width: 100%;
margin: 40rpx auto;
display: flex;
justify-content: space-between;
align-items: center;
.item {
flex: 1;
color: #fff;
margin: 0 40rpx;
padding: 10px 0;
font-weight: 600;
border-radius: 20rpx;
font-size: 32rpx;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
&.bg {
background-color: #409eff;
}
&.llsq {
background-color: #FF7D00;
}
&.next {
background-color: #356899;
}
&.start {
background-color: #FF7D00;
}
&.end {
background-color: #356899;
}
&.tjbg {
background-color: #409eff;
}
}
}
}
</style>

@ -0,0 +1,166 @@
<template>
<view class="task-list">
<view class="menu">
<uni-segmented-control :current="currentIndex" :values="menuList" @clickItem="handleMenuChange"
:styleType="menuObj.styleType" :activeColor="menuObj.activeColor">
</uni-segmented-control>
</view>
<!-- <view class="search">
<uni-search-bar v-model="keyword" @blur="onSearch" @clear="onClear" cancelButton="false"
placeholder="请输入搜索内容">
</uni-search-bar>
</view> -->
<view class="dataList">
<view v-for="(item,index) in dataList" :key="index">
<task-card :info="item" :idx="index"></task-card>
</view>
<view v-show="isLoadMore">
<uni-load-more :status="loadStatus" ></uni-load-more>
</view>
</view>
</view>
</template>
<script>
import { getToken } from '@/utils/auth'
import taskCard from '@/components/task-card/task-card.vue'
import {
taskListApi
} from '@/api/task-list'
export default {
name: "Task-list",
components: {
taskCard
},
data() {
return {
menuList: ['已接单', '进行中', '已完成'],
currentIndex: 0,
menuObj: {
activeColor: '#007aff',
styleType: 'button',
current: 1
},
pageNo: 1,
pageSize: 10,
isLoadMore:false, //
loadStatus:'loading', //more-loading-nomore-
dataList: [],
mapStatus: [
{
id: 0,
name: 'RECEIVED'
},
{
id: 1,
name: 'PROCESSING'
},
{
id: 2,
name: 'FINISHED'
}
],
keyword: ''
}
},
computed: {
isLogin() {
return !!getToken()
}
},
onLoad(option) {
this.status = option.status || 'RECEIVED'
const obj = this.mapStatus.find(e => e.name == option.status)
this.currentIndex = obj.id
},
onShow() {
if (!this.isLogin) {
uni.navigateTo({ url: '/pages/login' })
} else {
this.getData()
}
},
onReachBottom() {
if(!this.isLoadMore){ //
this.isLoadMore = true
this.pageNo +=1
this.getData()
}
},
methods: {
handleMenuChange(e) {
if (this.currentIndex !== e.currentIndex) {
const obj = {
0: 'RECEIVED',
1: 'PROCESSING',
2: 'FINISHED'
}
this.status = obj[e.currentIndex]
this.currentIndex = e.currentIndex
this.dataList = []
this.pageNo = 1
this.getData()
}
},
onSearch() {
this.getData(this.keyword)
},
onClear() {},
//
getData(val= '') {
const _this = this
_this.isLoadMore = true
const taskType = this.$store.state.user.userInfo.produceGroupType
const params = {
pageNo: this.pageNo,
pageSize: this.pageSize,
taskType,
status: this.status
}
taskListApi(params).then(res => {
const { code, data, msg } = res
if (data.list.length) {
data.list.forEach(e => {
e.status = this.status
})
this.dataList.push(...data.list)
if (data.list < this.pageSize) {
this.loadStatus = 'nomore'
this.isLoadMore = true
} else {
this.isLoadMore = false
}
} else {
this.isLoadMore = true
this.loadStatus = 'nomore'
}
}).catch(error => {
this.isLoadMore = false
if (this.pageNo >1) {
this.pageNo -=1
}
reject(error)
})
}
}
}
</script>
<style lang="scss">
.task-list {
.menu {
margin: 10px 14px;
}
.search {
margin: 10px 4px;
}
.dataList {
width: 100%;
}
}
</style>

@ -0,0 +1,39 @@
import { getToken } from '@/utils/auth'
// 登录页面
const loginPage = "/pages/login"
// 页面白名单
const whiteList = [
'/pages/login', '/pages/register', '/pages/common/webview/index'
]
// 检查地址白名单
function checkWhite(url) {
const path = url.split('?')[0]
return whiteList.indexOf(path) !== -1
}
// 页面跳转验证拦截器
let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
list.forEach(item => {
uni.addInterceptor(item, {
invoke(to) {
// if (getToken()) {
// if (to.url === loginPage) {
// uni.reLaunch({ url: "/" })
// }
// return true
// } else {
// if (checkWhite(to.url)) {
// return true
// }
// uni.reLaunch({ url: loginPage })
// return false
// }
},
fail(err) {
console.log(err)
}
})
})

@ -0,0 +1,60 @@
import store from '@/store'
function authPermission(permission) {
const all_permission = "*:*:*"
const permissions = store.getters && store.getters.permissions
if (permission && permission.length > 0) {
return permissions.some(v => {
return all_permission === v || v === permission
})
} else {
return false
}
}
function authRole(role) {
const super_admin = "admin"
const roles = store.getters && store.getters.roles
if (role && role.length > 0) {
return roles.some(v => {
return super_admin === v || v === role
})
} else {
return false
}
}
export default {
// 验证用户是否具备某权限
hasPermi(permission) {
return authPermission(permission)
},
// 验证用户是否含有指定权限,只需包含其中一个
hasPermiOr(permissions) {
return permissions.some(item => {
return authPermission(item)
})
},
// 验证用户是否含有指定权限,必须全部拥有
hasPermiAnd(permissions) {
return permissions.every(item => {
return authPermission(item)
})
},
// 验证用户是否具备某角色
hasRole(role) {
return authRole(role)
},
// 验证用户是否含有指定角色,只需包含其中一个
hasRoleOr(roles) {
return roles.some(item => {
return authRole(item)
})
},
// 验证用户是否含有指定角色,必须全部拥有
hasRoleAnd(roles) {
return roles.every(item => {
return authRole(item)
})
}
}

@ -0,0 +1,14 @@
import tab from './tab'
import auth from './auth'
import modal from './modal'
export default {
install(Vue) {
// 页签操作
Vue.prototype.$tab = tab
// 认证对象
Vue.prototype.$auth = auth
// 模态框对象
Vue.prototype.$modal = modal
}
}

@ -0,0 +1,74 @@
export default {
// 消息提示
msg(content) {
uni.showToast({
title: content,
icon: 'none'
})
},
// 错误消息
msgError(content) {
uni.showToast({
title: content,
icon: 'error'
})
},
// 成功消息
msgSuccess(content) {
uni.showToast({
title: content,
icon: 'success'
})
},
// 隐藏消息
hideMsg(content) {
uni.hideToast()
},
// 弹出提示
alert(content, title) {
uni.showModal({
title: title || '系统提示',
content: content,
showCancel: false
})
},
// 确认窗体
confirm(content, title) {
return new Promise((resolve, reject) => {
uni.showModal({
title: title || '系统提示',
content: content,
cancelText: '取消',
confirmText: '确定',
success: function(res) {
if (res.confirm) {
resolve(res.confirm)
}
}
})
})
},
// 提示信息
showToast(option) {
if (typeof option === "object") {
uni.showToast(option)
} else {
uni.showToast({
title: option,
icon: "none",
duration: 2500
})
}
},
// 打开遮罩层
loading(content) {
uni.showLoading({
title: content,
icon: 'none'
})
},
// 关闭遮罩层
closeLoading() {
uni.hideLoading()
}
}

@ -0,0 +1,30 @@
export default {
// 关闭所有页面,打开到应用内的某个页面
reLaunch(url) {
return uni.reLaunch({
url: url
})
},
// 跳转到tabBar页面并关闭其他所有非tabBar页面
switchTab(url) {
return uni.switchTab({
url: url
})
},
// 关闭当前页面,跳转到应用内的某个页面
redirectTo(url) {
return uni.redirectTo({
url: url
})
},
// 保留当前页面,跳转到应用内的某个页面
navigateTo(url) {
return uni.navigateTo({
url: url
})
},
// 关闭当前页面,返回上一页面或多级页面
navigateBack() {
return uni.navigateBack()
}
}

@ -0,0 +1,29 @@
{
"appid": "wxa29fe397274614b5",
"compileType": "miniprogram",
"libVersion": "3.2.4",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"coverView": true,
"es6": true,
"postcss": true,
"minified": true,
"enhance": true,
"showShadowRootInWxmlPanel": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"condition": false
},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 4
}
}

@ -0,0 +1,7 @@
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "HL-App",
"setting": {
"compileHotReLoad": true
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,90 @@
@font-face {
font-family: "iconfont";
src: url('@/static/font/iconfont.ttf') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
display: inline-block;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-user:before {
content: "\e7ae";
}
.icon-password:before {
content: "\e8b2";
}
.icon-code:before {
content: "\e699";
}
.icon-setting:before {
content: "\e6cc";
}
.icon-share:before {
content: "\e739";
}
.icon-edit:before {
content: "\e60c";
}
.icon-version:before {
content: "\e63f";
}
.icon-service:before {
content: "\e6ff";
}
.icon-friendfill:before {
content: "\e726";
}
.icon-community:before {
content: "\e741";
}
.icon-people:before {
content: "\e736";
}
.icon-dianzan:before {
content: "\ec7f";
}
.icon-right:before {
content: "\e7eb";
}
.icon-logout:before {
content: "\e61d";
}
.icon-help:before {
content: "\e616";
}
.icon-github:before {
content: "\e628";
}
.icon-aixin:before {
content: "\e601";
}
.icon-clean:before {
content: "\e607";
}
.icon-refresh:before {
content: "\e604";
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="shortcut icon" type="image/x-icon" href="<%= BASE_URL %>static/favicon.ico">
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<noscript>
<strong>本站点必须要开启JavaScript才能运行.</strong>
</noscript>
<div id="app"></div>
</html>

File diff suppressed because one or more lines are too long

@ -0,0 +1,90 @@
.text-center {
text-align: center;
}
.font-13 {
font-size: 13px;
}
.font-12 {
font-size: 12px;
}
.font-11 {
font-size: 11px;
}
.text-grey1 {
color: #888;
}
.text-grey2 {
color: #aaa;
}
.list-cell-arrow::before {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #c0c0c0;
border-style: solid;
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
position: absolute;
top: 50%;
margin-top: -6px;
right: 30rpx;
}
.list-cell {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #fff;
color: #333;
padding: 26rpx 30rpx;
}
.list-cell:first-child {
border-radius: 8rpx 8rpx 0 0;
}
.list-cell:last-child {
border-radius: 0 0 8rpx 8rpx;
}
.list-cell::after {
content: '';
position: absolute;
border-bottom: 1px solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
.menu-item-box {
width: 100%;
display: flex;
align-items: center;
.menu-icon {
color: #007AFF;
font-size: 16px;
margin-right: 5px;
}
.text-right {
margin-left: auto;
margin-right: 34rpx;
color: #999;
}
}
}

@ -0,0 +1,6 @@
// global
@import "./global.scss";
// color-ui
@import "@/static/scss/colorui.css";
// iconfont
@import "@/static/font/iconfont.css";

@ -0,0 +1,10 @@
const getters = {
token: state => state.user.token,
statusMap: state => state.user.statusMap,
// avatar: state => state.user.avatar,
// name: state => state.user.name,
// roles: state => state.user.roles,
userInfo: state => state.user.userInfo,
// permissions: state => state.user.permissions
}
export default getters

@ -0,0 +1,15 @@
import Vue from 'vue'
import Vuex from 'vuex'
import user from '@/store/modules/user'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user
},
getters
})
export default store

@ -0,0 +1,167 @@
import config from '@/config'
import storage from '@/utils/storage'
import constant from '@/utils/constant'
import {
login,
logout,
getInfo,
getUserId
} from '@/api/login'
import {
getToken,
setToken,
setUserId,
removeToken,
removeUserId
} from '@/utils/auth'
const baseUrl = config.baseUrl
const user = {
state: {
token: getToken(),
statusMap: {
'RECEIVED': "已接单",
'PROCESSING': "进行中",
'FINISHED': "已完成"
},
// name: storage.get(constant.name),
// avatar: storage.get(constant.avatar),
// roles: storage.get(constant.roles),
// permissions: storage.get(constant.permissions),
userInfo: storage.get(constant.userInfo)
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
// SET_NAME: (state, name) => {
// state.name = name
// storage.set(constant.name, name)
// },
// SET_AVATAR: (state, avatar) => {
// state.avatar = avatar
// storage.set(constant.avatar, avatar)
// },
// SET_ROLES: (state, roles) => {
// state.roles = roles
// storage.set(constant.roles, roles)
// },
// SET_PERMISSIONS: (state, permissions) => {
// state.permissions = permissions
// storage.set(constant.permissions, permissions)
// },
SET_USER: (state, userInfo) => {
state.userInfo = userInfo
storage.set(constant.userInfo, userInfo)
}
},
actions: {
// 登录
GetUserId({
commit
}, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
getUserId(username).then(res => {
const {
code,
data,
msg
} = res
setUserId(data)
setTimeout(() => {
resolve()
})
}).catch(error => {
reject(error)
})
})
},
// 登录
Login({
commit
}, userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
// const code = userInfo.code
// const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(username, password).then(res => {
const {
code,
data,
msg
} = res
setToken(data.accessToken)
commit('SET_TOKEN', data.accessToken)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
GetInfo({
commit,
state
}, userId) {
return new Promise((resolve, reject) => {
getInfo(userId).then(res => {
const user = res.data
// const avatar = (user == null || user.avatar == "" || user.avatar == null) ?
// require("@/static/images/profile.jpg") : baseUrl + user.avatar
// const username = (user == null || user.username == "" || user.username ==
// null) ? "" : user.username
// if (res.roles && res.roles.length > 0) {
// commit('SET_ROLES', res.roles)
// commit('SET_PERMISSIONS', res.permissions)
// } else {
// commit('SET_ROLES', ['ROLE_DEFAULT'])
// }
// const newUser = {
// ...user,
// avatar,
// username
// }
commit('SET_USER', user)
// commit('SET_NAME', username)
// commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 退出系统
LogOut({
commit,
state
}) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_USER', {})
// commit('SET_ROLES', [])
// commit('SET_PERMISSIONS', [])
removeToken()
removeUserId()
storage.clean()
resolve()
}).catch(error => {
reject(error)
})
})
}
}
}
export default user

@ -0,0 +1,66 @@
/* 引入uView主题样式 */
@import '@/uni_modules/uview-ui/theme.scss';
/**
* uni-app
*/
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//
$uni-text-color-inverse:#fff;//
$uni-text-color-grey:#999;//
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//
/* 边框颜色 */
$uni-border-color:#e5e5e5;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; //
/* 文章场景相关 */
$uni-color-title: #2C405A; //
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; //
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; //
$uni-font-size-paragraph:15px;

@ -0,0 +1,33 @@
## 0.0.2-rc-52022-09-19
修复部分场景返回页面 导致HF调试器 隐藏的BUG
## 0.0.2-rc-42022-04-12
对vue3 进一步支持 修复vue3中 渲染未实时更新的问题
## 0.0.2-rc-32022-02-22
修复 vue3 app 端白屏问题
## 0.0.2-rc-22022-02-07
实例更改默认编码
## 0.0.2-rc-12022-02-07
优化插件能力
## 0.0.2-rc2022-01-27
- 新增 基于uni技术栈的请求重复发如有其他技术栈的需要可以进行插件扩展
- 新增 Storage 编辑
- 新增 AppData 预览
- 新增 页面栈信息预览
- 新增 插件功能,开发者可以根据需求进行扩展 (例如扩展:获取所有图片地址、)
- ui样式优化 增加设置箱 设置深浅色
## 0.0.1-rc.72022-01-13
修复 已知BUG
优化 换行显示
新增 log 类型删选与删除
## 0.0.1-rc.52021-09-16
优化命令执行
## 0.0.1-rc.42021-09-15
优化 vue3
## 0.0.1-rc.32021-09-14
默认 将 wx.request 替换为 uni.request
## 0.0.1-rc.22021-09-12
去除 nvue子窗口内容 更改为混入插入 全局按钮 HF调试器
## 0.0.1-rc.12021-09-10
更改样例
## 0.0.1-rc2021-09-10
第一个版本

@ -0,0 +1,180 @@
import {ConsoleData,RequestData,StorageData,AppDataClass,CurrentPagesClass} from './../data.js'
// #ifndef VUE3
import Vue from 'vue'
// #endif
/* 拦截日志文件 */
export class consoleInit {
DATA = []
NAME = 'Console'
consoleNameArr = ['log', 'error', 'info', 'warn']
componentsName='Console'
app = {}
constructor(arg) {
this.DATA = new ConsoleData()
this._init()
}
_init() {
const consoleNameArr = this.consoleNameArr
this.consoleArrFunc = consoleNameArr.map(item => console[item])
// global.$_log = this.consoleArrFunc[0]
consoleNameArr.map((item,index) => {
console[item] = this._record(item,this.consoleArrFunc[index])
})
this.app = this.$HFdebugging.options.app
// #ifdef VUE3
this._vue3Error(this.app)
window&&(window.$_log = this.consoleArrFunc[0])
// #endif
// #ifndef VUE3
this._vueError()
global.$_log = this.consoleArrFunc[0]
// #endif
}
_record(type,consoleFunc=()=>{}) {
return (...args) => {
this.addRecord(type,...args)
consoleFunc&&consoleFunc(...args);
}
}
addRecord(type,...args){
let time = this._getDate()
this.DATA.push({
time,
type,
objects: [...args]
})
}
_getDate() {
let d = new Date
let a = d.toString()
if(a.split(' ')[4]){
return a.split(' ')[4] + '.' + d.getMilliseconds()
}else{
return a
}
}
_vueError() {
let errorHandler
let warnHandler
if(typeof Vue.config.errorHandler == 'function'){
errorHandler = Vue.config.errorHandler
}
Vue.config.errorHandler = (...err) => {
errorHandler&&errorHandler(...err)
this.addRecord('error',...err)
throw err
}
if(typeof Vue.config.errorHandler == 'function'){
errorHandler = Vue.config.errorHandler
}
Vue.config.warnHandler = (...err) => {
warnHandler&&warnHandler(...err)
this.addRecord('warn',...err)
}
}
_vue3Error(app){
let errorHandler
let warnHandler
if(typeof app.config.errorHandler == 'function'){
errorHandler = app.config.errorHandler
}
app.config.errorHandler = (...err) => {
errorHandler&&errorHandler(...err)
this.addRecord('error',...err)
throw err
}
if(typeof app.config.errorHandler == 'function'){
errorHandler = app.config.errorHandler
}
app.config.warnHandler = (...err) => {
warnHandler&&warnHandler(...err)
this.addRecord('warn',...err)
}
}
}
/* 拦截请求 */
export class InterceptorRequest {
NAME='Request'
DATA = []
componentsName='InterceptorRequest'
constructor(arg) {
this.DATA = new RequestData()
this.init()
}
init() {
let that = this
wx.request = uni.request
uni.addInterceptor('request', {
invoke(args) {
// request 触发前拼接 url
const addInterceptorRequestData = {
Headers: {...args}
}
let _complete = args.complete;
args.complete = function (e) {
_complete && _complete(e)
addInterceptorRequestData.Preview = {...e}
that.DATA.push(addInterceptorRequestData)
}
},
})
}
addRequestData(addInterceptorRequestData={}){
this.DATA.push(addInterceptorRequestData)
}
}
/* 存储信息 */
export class StorageInit {
DATA = []
NAME = 'Storage'
componentsName='StorageInit'
constructor(){
this.DATA = new StorageData()
this._init()
}
_init() {
}
}
/* AppData */
export class AppDataInit{
DATA = []
NAME = 'AppData'
componentsName='AppData'
constructor(){
this.DATA = new AppDataClass()
this._init()
}
_init() {
}
}
/* AppData */
export class CurrentPagesInit{
DATA = []
NAME = 'CurrentPages'
componentsName='CurrentPages'
constructor(){
this.DATA = new CurrentPagesClass()
this._init()
}
_init() {
}
}

@ -0,0 +1,219 @@
// #ifdef VUE3
import { ref,reactive,computed } from 'vue'
// #endif
export class ConsoleData {
DATA = []
FILTRATE = {}
constructor(arg) {
this._isConsoleData = true
this.init()
}
init() {
this.DATA = [{
type: 'log',
objects: ["欢迎使用HF调试器~~~"]
}]
// #ifdef VUE3
this.DATA_REF = ref(this.DATA)
this.DATA = computed(()=>this.DATA_REF.value).value
this.FILTRATE_REF = ref(this.FILTRATE)
this.FILTRATE = computed(()=>this.FILTRATE_REF.value).value
// #endif
}
push(args) {
if (this.DATA.length > 512) {
this.DATA.shift()
}
this.DATA.push(args)
this.initFiltrate(args)
}
initFiltrate(args){
if(!this.FILTRATE[args.type]){
this.FILTRATE[args.type] = []
}
if (this.FILTRATE[args.type].length > 256) {
this.FILTRATE[args.type].shift()
}
this.FILTRATE[args.type].push(args)
}
filtrate(type){
if(!type)return this.DATA
return this.FILTRATE[type]||[]
}
eliminateAll(){
this.init()
this.FILTRATE={}
}
remove(type){
if(this.FILTRATE[type]){
this.FILTRATE[type] = []
}
}
}
export class RequestData {
DATA = []
constructor(arg) {
this._requestData = true
this.init()
}
init() {
this.DATA = []
// #ifdef VUE3
this.DATA_REF = ref([])
this.DATA = computed(()=>this.DATA_REF.value).value
// #endif
}
push(args) {
if (this.DATA.length > 512) {
this.DATA.shift()
}
this.DATA.push(args)
}
eliminateAll(){
this.DATA = [];
}
}
export class StorageData {
DATAC = []
constructor(arg) {
this._storageData = true
this.init()
}
init() {
this.DATAC = []
// #ifdef VUE3
this.DATA_REF = ref(this.DATAC)
this.DATAC = computed(()=>this.DATA_REF.value).value
// #endif
}
push(args) {
if (this.DATAC.length > 512) {
this.DATAC.shift()
}
this.DATAC.push(args)
}
eliminateAll(){
uni.clearStorageSync();
this.DATAC = [];
}
remove(key,index){
uni.removeStorageSync(key)
this.DATAC.splice(index,1)
}
edit(storageItem,storageIndex){
this.DATAC[storageIndex] = storageItem
uni.setStorageSync(storageItem.key,storageItem.obj)
}
get DATA() {
/* 获取storage */
let storageAllData = []
let that = this
uni.getStorageInfo({
success(res) {
res.keys.forEach(item => {
// storageAllData[item] = JSON.stringify(uni.getStorageSync(item))
storageAllData.push({
key: item,
obj: uni.getStorageSync(item)
})
})
that.DATAC = storageAllData
}
})
return this.DATAC
}
// 设置时更改 全局storageAllData
/* set DATA(){
return this.DATA
} */
}
export class AppDataClass {
DATAC = []
constructor(arg) {
this._appDataClass = true
this.init()
}
init() {
this.DATAC = []
// #ifdef VUE3
this.DATA_REF = ref(this.DATAC)
this.DATAC = computed(()=>this.DATA_REF.value).value
// #endif
}
push(args) {
if (this.DATAC.length > 512) {
this.DATAC.shift()
}
this.DATAC.push(args)
}
get DATA() {
/* 获取 */
let arr = [...getCurrentPages()].reverse()
// #ifndef VUE3
this.DATAC = arr.map(item=>item.$vm._data)
// #endif
// #ifdef VUE3
this.DATAC = arr.map(item=>item.$vm.$data)
// #endif
return this.DATAC
}
}
export class CurrentPagesClass {
DATAC = []
constructor(arg) {
this._appDataClass = true
this.init()
}
init() {
this.DATAC = []
// #ifdef VUE3
this.DATA_REF = ref(this.DATAC)
this.DATAC = computed(()=>this.DATA_REF.value).value
// #endif
}
push(args) {
if (this.DATAC.length > 512) {
this.DATAC.shift()
}
this.DATAC.push(args)
}
get DATA() {
/* 获取 */
var CurrentPages = getCurrentPages()
// #ifdef APP
let keyArr = ['_data','data','$refs','route','options']
CurrentPages = [...CurrentPages].map(item=>{
let a = {...item}
// a.$vm = JSON.parse(JSON.stringify(item.$vm,['$vm']))
a.$vm = "[Object,$vm]"
return a
})
// #endif
this.DATAC =[...CurrentPages].reverse()
return this.DATAC
}
}

@ -0,0 +1,248 @@
import Vue from "vue"
class ConsoleData {
request=[]
console=[
["log", ["欢迎使用HF调试器~~~"]]
]
consoleData={
log:[],
error:[]
}
storage= {}
URL= ""
constructor(arg) {
this._isConsoleData = true
this.console = [["log", ["欢迎使用HF调试器~~~"]]]
}
}
const CONSOLE_DATA = new ConsoleData()
const wx_request = wx.request
let view = null;
!function addInterceptorRequest() {
wx.request = uni.request
/* 拦截请求 */
uni.addInterceptor('request', {
invoke(args) {
// request 触发前拼接 url
const addInterceptorRequestData = {
Headers: {
data: args.data,
method: args.method,
responseType: args.responseType,
url: args.url
}
}
let _complete = args.complete;
args.complete = function(e) {
_complete && _complete(e)
addInterceptorRequestData.Preview = e
if (CONSOLE_DATA.request.length >= 1000) {
CONSOLE_DATA.request.shift()
}
CONSOLE_DATA.request.push(addInterceptorRequestData)
}
},
})
}()
function createView() {
let page = {},
onType = false
view = new plus.nativeObj.View('HF', {
bottom: '100px',
left: '60%',
height: '40px',
width: '100px',
zIndex:'999'
});
view.drawRect({
color: '#FF4A46',
radius: '5px'
}, {
top: '0px',
left: '0px',
width: '100%',
height: '100%'
});
view.drawText('HF调试器', {
top: '0px',
left: '0px',
width: '100%',
height: '100%'
}, {
size: '16px',
color: '#FFFFFF'
});
view.addEventListener("touchstart", (touch) => {
page = touch
})
view.addEventListener("touchmove", (touch) => {
if ((touch.pageY - 20 > 0 && touch.pageX - 50 > 0)
&& (Math.abs(touch.pageX - page.pageX) > 20
|| Math.abs(touch.pageY - page.pageY) > 20)) {
view.setStyle({
top: (touch.pageY - 20) + 'px',
left: (touch.pageX - 50) + 'px'
})
onType = true
} else {
onType = false
}
})
view.addEventListener("click", (e) => {
!onType && uni.$emit("HFshow")
})
console.log("")
}
function showHF() {
createView()
view.show()
}
/* 拦截日志文件 */
! function consoleInit() {
/* 点击事件 */
UniServiceJSBridge.subscribe("BNT_VIEW", () => {
uni.$emit("HFshow")
});
/* 移动事件 */
UniServiceJSBridge.subscribe("BNT_VIEW.ontouchend", (e) => {
// uni.$emit("HFshow")
uni.setStorageSync("pageXY", e)
});
let console_log = console.log
let console_error = console.error
console.log = function(...arg) {
if (CONSOLE_DATA.console.length >= 1000) {
CONSOLE_DATA.console.shift()
}
if (CONSOLE_DATA.consoleData.log.length >= 1000) {
CONSOLE_DATA.consoleData.log.shift()
}
CONSOLE_DATA.console.push(["log", [...arg]])
CONSOLE_DATA.consoleData.log.push(["log", [...arg]])
console_log(...arg)
}
console.error = function(...arg) {
if (CONSOLE_DATA.console.length >= 1000) {
CONSOLE_DATA.console.shift()
}
if (CONSOLE_DATA.consoleData.error.length >= 1000) {
CONSOLE_DATA.consoleData.error.shift()
}
CONSOLE_DATA.console.push(["error", [...arg]])
CONSOLE_DATA.consoleData.error.push(["error", [...arg]])
console_error(...arg)
}
// #ifndef VUE3
Vue.config.errorHandler = (...err) => {
CONSOLE_DATA.console.push(["error", [...err]])
CONSOLE_DATA.consoleData.error.push(["error", [...err]])
throw err
}
// #endif
// #ifdef APP
showHF()
// #endif
}()
/* 获取storage */
function getStorageAllSync() {
let storageAllData = {}
uni.getStorageInfo({
success(res) {
res.keys.forEach(item => {
storageAllData[item] = JSON.stringify(uni.getStorageSync(item))
})
CONSOLE_DATA.storage = storageAllData
}
})
}
uni.setStorageSync("test", "HF数据存储验证欢迎使用HF调试器")
uni.$on("HFshow", () => {
getStorageAllSync()
// getApp().globalData.CONSOLE_DATA = CONSOLE_DATA
console.log("EEglobalData")
if(getApp().$vm.$refs['HFDebugging']){
getApp().$vm.$refs['HFDebugging'].onClick()
return
}
const pages = getCurrentPages()
if (pages[pages.length - 1].route == 'uni_modules/HF-HF_debugging/pages/subnvue/HFconsole') {
uni.navigateBack({
delta: 1
})
} else {
uni.navigateTo({
url: "/uni_modules/HF-HF_debugging/pages/subnvue/HFconsole",
animationType: "slide-in-bottom"
})
}
})
// 存贮文件内容
/* function createWriter(){
return new Promise((resolve,reject)=>{
plus.io.requestFileSystem( plus.io.PRIVATE_DOC, function( fs ) {
// 可通过fs操作PUBLIC_DOWNLOADS文件系统
// ......
console.log("fs",fs)
fs.root.getFile('__CONSOLE_DATA__.js', {
create: true // 文件不存在则创建
}, fileEntry => {
// 文件在手机中的路径
console.log(fileEntry.fullPath)
fileEntry.createWriter(writer => {
// 写入文件成功完成的回调函数
writer.onwrite = e => {
resolve(e)
};
// 写入数据
writer.write("window.__CONSOLE_DATA__ = "+JSON.stringify(CONSOLE_DATA));
})
CONSOLE_DATA.URL = plus.io.convertLocalFileSystemURL(fileEntry.fullPath)
}, e => {
console.log("getFile failed: " + e.message);
});
}, function ( e ) {
reject("Request file system failed: " + e.message)
});
})
} */
function HFdebugging(app, {
wxRequest = true
}) {
if (!wxRequest) wx.request = wx_request
if (!app) return
/* addInterceptorRequest()
consoleInit() */
if (!app.config.errorHandler) {
app.config.errorHandler = (...err) => {
CONSOLE_DATA.console.push(["error", [...err]])
throw err
}
} else {
let errorHandler = app.config.errorHandler
app.config.errorHandler = (...err) => {
CONSOLE_DATA.console.push(["error", [...err]])
errorHandler(err)
throw err
}
}
}
export default {
CONSOLE_DATA,
HFdebugging,
view,
showHF,
getStorageAllSync
}

@ -0,0 +1,176 @@
/**
*
*/
import {consoleInit,InterceptorRequest,StorageInit,AppDataInit,CurrentPagesInit} from './PlugIn/index.js'
// #ifdef H5
import BntBoxConfirm from './../components/BntBox/index.js'
// #endif
import {information,HFDebuggingInformation } from './store.js'
const wx_request = wx.request
// consoleInit,AppDataInit,CurrentPagesInit,InterceptorRequest,StorageInit
let informationArr = [consoleInit,AppDataInit,CurrentPagesInit,InterceptorRequest,StorageInit]
export class HFdebugging {
wx_request = wx_request
view = null
/* 挂载的插件数据 */
information = []
/* 设置内容 */
settingData = {
invert:{
name:'深浅色',
type:'switch',
value:false,
}
}
// 选项
options={}
constructor(options={}) {
this.options = options
// #ifdef App
uni.onThemeChange((res)=>{
this.settingData.invert.value=(res.theme!='dark');
});
// #endif
this._init()
this._eventInit()
HFDebuggingInformation.push(this)
}
_init() {
if(this.options.plugIn&& this.options.plugIn.isArray()){
informationArr.map(item=>{
this.loadPlugIn(item)
})
}else{
informationArr.map(item=>{
this.loadPlugIn(item)
})
}
this.information = information
// #ifdef H5
BntBoxConfirm()
// #endif
// #ifdef APP
this.view = createView();
this.show();
// #endif
}
_eventInit(){
uni.$on("HFshow", () => {
const pages = getCurrentPages()
if (pages[pages.length - 1].route == 'uni_modules/HF-HF_debugging/pages/next/next') {
uni.navigateBack({
delta: 1
})
} else {
uni.navigateTo({
url: "/uni_modules/HF-HF_debugging/pages/next/next",
animationType: "slide-in-bottom"
})
this.view?.hide()
}
})
uni.$on("viewShow", () => {
this.show()
})
uni.$on("viewHide", () => {
this.hide()
})
}
show(){
this.view?.show()
}
hide() {
this.view?.hide()
}
// 挂在插件
loadPlugIn(PlugIn) {
PlugIn.prototype.$HFdebugging = this
information.push(new PlugIn())
}
// 筛选插件实例
getPlugIn(plugInName=''){
return this.information.filter(item=>item.NAME==plugInName)[0]
}
// 删除实例
removePlugIn(plugInName=''){
let index = this.information.findIndex(item=>item.NAME==plugInName)
if(index>-1){
this.information.splice(index,1)
}
}
}
function createView() {
let page = {},
onType = false
const view = new plus.nativeObj.View('HF', {
bottom: '100px',
left: '60%',
height: '40px',
width: '100px',
zIndex: '999'
});
view.drawRect({
color: '#FF4A46',
radius: '5px'
}, {
top: '0px',
left: '0px',
width: '100%',
height: '100%'
});
view.drawText('HF调试器', {
top: '0px',
left: '0px',
width: '100%',
height: '100%'
}, {
size: '16px',
color: '#FFFFFF'
});
view.addEventListener("touchstart", (touch) => {
page = touch
})
view.addEventListener("touchmove", (touch) => {
if ((touch.pageY - 20 > 0 && touch.pageX - 50 > 0) &&
(Math.abs(touch.pageX - page.pageX) > 20 ||
Math.abs(touch.pageY - page.pageY) > 20)) {
view.setStyle({
top: (touch.pageY - 20) + 'px',
left: (touch.pageX - 50) + 'px'
})
onType = true
} else {
onType = false
}
})
view.addEventListener("click", (e) => {
!onType && uni.$emit("HFshow")
})
return view
}

@ -0,0 +1,2 @@
export const information = []
export const HFDebuggingInformation = []

@ -0,0 +1,41 @@
export function isFunction(value) {
return Object.prototype.toString.call(value) == '[object Function]';
}
export function isNumber(value) {
return Object.prototype.toString.call(value) == '[object Number]';
}
export function isString(value) {
return Object.prototype.toString.call(value) == '[object String]';
}
export function isArray(value) {
return Object.prototype.toString.call(value) == '[object Array]';
}
export function isBoolean(value) {
return Object.prototype.toString.call(value) == '[object Boolean]';
}
export function isUndefined(value) {
return value === undefined;
}
export function isNull(value) {
return value === null;
}
export function isSymbol(value) {
return Object.prototype.toString.call(value) == '[object Symbol]';
}
export function isObject(value) {
return (
Object.prototype.toString.call(value) == '[object Object]'
||
// if it isn't a primitive value, then it is a common object
(
!isNumber(value) &&
!isString(value) &&
!isBoolean(value) &&
!isArray(value) &&
!isNull(value) &&
!isFunction(value) &&
!isUndefined(value) &&
!isSymbol(value)
)
);
}

@ -0,0 +1,51 @@
<template>
<view class="">
<view v-for="(item,index) in exData" :key="index" class="" >
<view class="flex" style="font-weight: 600;">
<text>{{exData.length-(index+1)}}AppData:</text>
<text @click.stop="openType==index?openType=-1:openType=index">{{openType==index?'':''}}</text>
</view>
<view class="bg_kuang">
<objTree v-if="openType==index" :objects="item"></objTree>
</view>
</view>
</view>
</template>
<script>
import objTree from './objTree.vue'
export default {
name: 'AppData',
components: {
objTree
},
props: {
livingExample: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
openType:1
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA
}
},
}
</script>
<style lang="scss">
.flex{
display: flex;
}
.bg_kuang{
border: #b8b9ff solid 1rpx;
}
</style>

@ -0,0 +1,41 @@
import BntBox from './index.vue'
let defaultOptions = {
show:true
};
let body = document.body,
bindPhone = document.createElement('div')
bindPhone.setAttribute('id', 'HFBntBox-id')
body.appendChild(bindPhone)
// #ifndef VUE3
import Vue from 'vue'
const VueComponent = Vue.extend(BntBox);
const BntBoxConfirm = function (options={}) {
const vm = new VueComponent().$mount('#HFBntBox-id');
Object.assign(vm,defaultOptions , options);
document.body.appendChild(vm.$el);
return
};
// #endif
// #ifdef VUE3
import { createApp,h } from 'vue'
const VueComponent = createApp({
render: () => {
return h(BntBox)
}})
const BntBoxConfirm = function (options={}) {
const vm = VueComponent.mount('#HFBntBox-id');
console.log("vm",vm)
// Object.assign(vm,defaultOptions , options);
document.body.appendChild(vm.$el);
return
};
// #endif
export default BntBoxConfirm;

@ -0,0 +1,59 @@
<template>
<view ref="HF" id="HF" class="" @click="onclick" @touchstart="ontouchstart" @touchmove="ontouchmove"
:style="{top:startY,left:startX}">
HF调试器
</view>
</template>
<script>
let onType = true
export default {
name: 'BntBox',
data() {
return {
startY: '90%',
startX: '60%',
start: {},
}
},
mounted() {
},
methods: {
onclick(e) {
uni.$emit("HFshow")
},
ontouchmove(touch) {
touch = touch.touches[0]
let page = this.start
if ((touch.pageY - 20 > 0 && touch.pageX - 50 > 0) &&
(Math.abs(touch.pageX - page.pageX) > 20 ||
Math.abs(touch.pageY - page.pageY) > 20)) {
this.startY = (touch.pageY + uni.upx2px(60) / 2) + 'px'
this.startX = (touch.pageX - uni.upx2px(180) / 2) + 'px'
onType = true
} else {
onType = false
}
},
ontouchstart(e) {
this.start = e.touches[0]
},
}
}
</script>
<style>
#HF {
text-align: center;
position: fixed;
border-radius: 10rpx;
background: #FF4A46;
color: #FFFFFF;
width: 180rpx;
height: 60rpx;
line-height: 60rpx;
z-index: 999;
left: 60%;
}
</style>

@ -0,0 +1,236 @@
<template>
<view >
<view :class="item.type" class="content" v-for="(item,index) in exDataFiltrate(type)" :key="index">
<text class="time">{{item.time}}</text>
<text class="text-type" >{{item.type}}</text>
<objTree :isShowKey="false" :objects="analysis(item.objects)" :isAt="true"></objTree>
</view>
<view class="" style="height: 200rpx;"></view>
<view class="content-bottom-view">
<scroll-view scroll-x="true" class="content-bottom">
<text :class="{hit:type==''}" @click="type=''">All</text>
<text :class="{hit:type==item}" @click="type=item" v-for="(item,index) in livingExample.consoleNameArr" :key="index" >{{item}}</text>
<text @click="eliminateAll">eliminateAll</text>
<text @click="remove">remove</text>
</scroll-view>
<view class="textarea-view">
<textarea v-model="evalJsCode" placeholder="请入指令(实验性的)" @confirm="confirm" />
<text @click="confirm" style="color: #FFFFFF;">{{'执行 \n 🛠'}} </text>
</view>
</view>
</view>
</template>
<script>
import objTree from './objTree.vue'
import * as tool from './../common/tool.js'
export default {
name: 'Console',
components: {
objTree
},
props: {
livingExample: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
type:'',
evalJsCode:''
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA
},
exDataFiltrate() {
return (type)=>this.livingExample.DATA.filtrate(type)
},
analysis(){
return (item)=>this.solveLogItem(item)
}
},
mounted() {
this.$emit("setScrollToLower")
},
methods:{
scrolltolower(e){
// console.log("e",e)
},
solveLogItem(k) {
// #ifndef VUE3
if(typeof k === 'object' && !k.toString().includes(' at ') )return k
// #endif
// #ifdef VUE3
if(typeof k === 'object')return k
// #endif
if(!k)return '';
const solve = (str) => {
const finalArr = [];
let next_speical = '';
const str_arr = str.split('---');
for(let i = 0; i < str_arr.length; i++) {
const str_item = str_arr[i];
if(str_item == 'UNDEFINED') {
finalArr.push(undefined);
} else if(str_item.indexOf('BEGIN:') == 0) {
next_speical = str_item.substr(6);
} else if(str_item.indexOf('END:') == 0) {
if(next_speical == str_item.substr(4)) {
next_speical = '';
}
} else {
switch(next_speical) {
case 'BOOLEAN':
finalArr.push(new Boolean(str_item) ? true : false);
break;
case 'NUMBER':
finalArr.push(parseFloat(str_item));
break;
case 'JSON':
finalArr.push(JSON.parse(str_item));
break;
default:
str_item&&finalArr.push(str_item);
break;
}
}
}
return finalArr
};
const atArr = (k[0]+'').split(' at ');
const obj_arr = atArr[0].split('---COMMA---');
const kArr = []
if(obj_arr.length > 1) {
for (let i = 0; i < obj_arr.length; i++){
kArr.push(...solve(obj_arr[i]))
}
}else {
kArr.push(...solve(obj_arr[0]));
}
kArr.push(' at '+atArr[1])
return kArr;
},
eliminateAll(){
this.livingExample.DATA.eliminateAll()
},
remove(){
this.livingExample.DATA.remove(this.type)
},
confirm() {
this.livingExample.addRecord('eval',(this.evalJsCode || 'undefined'))
let result = ''
let $content = ''
try {
result = eval.call(global, '(' + this.evalJsCode + ')');
} catch (e) {
try {
result = eval.call(global, this.evalJsCode);
} catch (e) {
this.livingExample.addRecord('error','eval-error:',e)
}
}
if (tool.isArray(result) || tool.isObject(result)) {
result = getApp()!=result?result:' isObject - getApp'
} else {
if (tool.isNull(result)) {
result = 'null';
} else if (tool.isUndefined(result)) {
result = 'undefined';
} else if (tool.isFunction(result)) {
result = 'function()'
} else if (tool.isString(result)) {
result = '"' + result + '"';
}
}
this.livingExample.addRecord('eval',(result || 'undefined'))
this.evalJsCode = ""
},
}
};
</script>
<style lang="scss">
.content{
display: flex;
flex-wrap: wrap;
width: 100%;
box-shadow: 0rpx 0rpx 1rpx #C0C0C0;
padding: 4rpx 0;
.time{
padding: 0 8rpx;
}
}
.log{
// color: ;
}
.error{
color: #d50000;
background: rgba($color: #7c3615, $alpha: .3);
box-shadow: 0 0 1rpx #d50000;
}
.warn{
color: #f8b251;
background: rgba($color: #c3a356, $alpha: .2);
box-shadow: 0 0 1rpx #f8b251;
}
.info{
color: #5099f8;
background: rgba($color: #5099f8, $alpha: .2);
box-shadow: 0 0 1rpx #2500f8;
}
.eval{
color: #aaaaff;
background: rgba($color: #aaaaff, $alpha: .2);
box-shadow: 0 0 1rpx #7979b5;
}
.text-type{
padding:0 6rpx;
/* border: 1rpx solid #3F536E;
border-radius: 8rpx;
background: #aaff7f; */
}
.content-bottom-view{
position: fixed;
z-index: 99;
bottom: 0rpx;
left: 0;
background: #FFFFFF;
.content-bottom{
width: 100vw;
height: 70rpx;
text{
padding: 4rpx 8rpx;
border: 1rpx solid #999999;
}
}
.textarea-view{
width: 100vw;
display: flex;
text{
width: 100rpx;
text-align: center;
line-height: 50rpx;
background: #FF4A46;
}
}
textarea{
width: calc(100vw - 100rpx);
max-height: 100rpx;
// background: #007AFF;
}
.hit{
background: #C8C7CC;
}
}
.flex{
display: flex;
flex-wrap: wrap;
}
</style>

@ -0,0 +1,51 @@
<template>
<view class="">
<view v-for="(item,index) in exData" :key="index" class="" >
<view class="flex" style="font-weight: 600;">
<text>{{exData.length-(index+1)}}页面栈:</text>
<text @click.stop="openType==index?openType=-1:openType=index">{{openType==index?'':''}}</text>
</view>
<view class="bg_kuang">
<objTree v-if="openType==index" :objects="item"></objTree>
</view>
</view>
</view>
</template>
<script>
import objTree from './objTree.vue'
export default {
name: 'CurrentPages',
components: {
objTree
},
props: {
livingExample: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
openType:1
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA
}
},
}
</script>
<style lang="scss">
.flex{
display: flex;
}
.bg_kuang{
border: #b8b9ff solid 1rpx;
}
</style>

@ -0,0 +1,151 @@
<template>
<view>
<!-- 背景 -->
<view class="mark" @click="onClickMack"></view>
<!-- 主体 -->
<view class="main" @click="setting=false" :class="{invert:settingData.invert.value}">
<!-- 标题 -->
<scroll-view class="headline-scroll-view" scroll-x="true">
<text :class="{hit:plugInId==index}" class="headline" @click="plugInId=index,setPlugInId(index)" v-for="(item,index) in plugInName" :key="index">{{item}}</text>
<text style="padding-right: 40rpx;"></text>
<text @click.stop="setting=!setting" class="setting">🔧</text>
</scroll-view>
<!-- 组件模板-->
<scroll-view :scroll-into-view="scrollToLowerId" :scroll-top="scrollTop" class="plug-in-scroll-view" scroll-y="true" @scrolltolower="scrolltolower" @scrolltoupper="scrolltoupper">
<component ref="informationComponents" :is="information[plugInId].componentsName" :livingExample="information[plugInId]"
@setScrollTop="setScrollTop" @setScrollToLower="setScrollToLower" ></component>
<text id="scroll-bot"></text>
</scroll-view>
<setting v-if="setting"></setting>
</view>
</view>
</template>
<script>
import {
HFDebuggingInformation,information
} from './../common/store.js'
import Console from './../components/Console.vue'
import StorageInit from './../components/StorageInit.vue'
import InterceptorRequest from './../components/InterceptorRequest.vue'
import setting from './../components/setting.vue'
import AppData from './../components/AppData.vue'
import CurrentPages from './../components/CurrentPages.vue'
export default {
name:'HFBox',
components: {
InterceptorRequest,
StorageInit,
Console,
setting,
AppData,
CurrentPages
},
data() {
return {
setting:false,
plugInId:uni.getStorageSync("plugInId")||0,
information,
plugInName: [],
componentsName: '',
scrollTop:'100%',
scrollToLowerId:'',
settingData:HFDebuggingInformation[0].settingData
}
},
created() {
this.plugInName = information.map((item,index) => {
return item.NAME
})
},
methods:{
scrolltolower(e){
if(this.$refs?.informationComponents?.scrolltolower){
this.$refs?.informationComponents?.scrolltolower(e)
}
},
scrolltoupper(e){
if(this.$refs?.informationComponents?.scrolltoupper){
this.$refs?.informationComponents?.scrolltoupper(e)
}
},
onClickMack(){
uni.$emit("viewShow")
uni.navigateBack({
delta: 1
})
},
setScrollTop(e){
this.scrollTop = e
},
setScrollToLower(){
this.scrollToLowerId = ''
this.$nextTick(()=>{
this.scrollToLowerId = 'scroll-bot'
})
},
setPlugInId(index){
uni.setStorageSync("plugInId",index)
}
}
};
</script>
<style lang="scss" scoped>
/* *{
font-size: 24rpx;
} */
.invert{
filter: invert(100%);
}
.mark {
position: fixed;
z-index: 998;
bottom: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, .3);
}
.main {
padding:20rpx 0rpx;
font-size: 24rpx;
position: fixed;
z-index: 9999;
bottom: 0;
left: 0;
width: 100vw;
height: 80vh;
background: #FFFFFF;
}
.headline-scroll-view{
// position: relative;
width: 100vw;
height: 44rpx;
}
.headline{
padding: 6rpx;
border: solid 1rpx #999999;
}
.hit{
background: #b1b1b1;
}
.plug-in-scroll-view{
width: 100vw;
height: calc(80vh - 50rpx);
}
.setting{
padding: 0 4rpx;
position: absolute;
right: 0;
top: 0;
border: 1rpx solid #999999;
}
#scroll-bot{
width: 100vw;
text-align: center;
}
</style>

@ -0,0 +1,209 @@
<template>
<view>
<text class="del-text" @click="onDel">🚫</text>
<text>🚫</text>
<view class="headline">
<text class="method-text">Method</text>
<text class="url-text">Url</text>
<text class="status-text">Status</text>
<text class="status-text">选项</text>
</view>
<view :class="{error:item.Preview.statusCode>200&&item.Preview.statusCode<500||!item.Preview.statusCode,warn:item.Preview.statusCode>500 }" class="content"
v-for="(item,index) in exData" :key="index">
<view @click="openIndex == index?openIndex=-1:openIndex=index" class="headline">
<text class="method-text">{{item.Headers.method}}</text>
<text class="url-text">{{item.Headers.url}}</text>
<text class="status-text">{{item.Preview.statusCode||(0+'\n[推测CORS]')}}</text>
<text @click.stop="showUp(item,index)" class="status-text">重发🆙</text>
</view>
<view v-if="openIndex == index" class="details-view">
<block>
<view @click="nthChild=0" class="">
<text class="fw600 link">Headers</text>
</view>
<view v-if="nthChild==0" class="details-top">
<view v-for="(ite,indx) of item.Headers" :key="indx" class="details">
<text>{{indx}}</text>
<text v-if="indx=='data'">{{JSON.stringify(ite,null,2)}}</text>
<text v-else>{{ite}}</text>
<text @click="copy(ite)">{{'📋'}}</text>
</view>
<!-- <view class="details">
<text>data-json-stringify</text>
<view class="body-json">
<objTree :objects="{body:item.Headers.data}"></objTree>
</view>
<text @click="copy(item.Headers.data)">{{'📋'}}</text>
</view> -->
</view>
</block>
<block>
<view @click="nthChild=1" class="">
<text class="fw600 link">Preview</text>
</view>
<view v-if="nthChild==1" class="details-top">
<view v-for="(ite,indx) of item.Preview" :key="indx" class="details">
<text>{{indx}}</text>
<text>{{ite}}</text>
<text @click="copy(ite)">{{'📋'}}</text>
</view>
<view v-if="item.Preview.statusCode>=200&&item.Preview.statusCode<400" class="details">
<text>body-json</text>
<view class="body-json">
<objTree :isShowKey="false" :objects="{body:item.Preview.data}"></objTree>
</view>
<text @click="copy(item.Preview.data)">{{'📋'}}</text>
</view>
</view>
</block>
<block v-if="item.Preview.statusCode>=500||(item.Preview.data+'').includes('<!DOCTYPE HTML PUBLIC')">
<view @click="nthChild=2" class="">
<text class="fw600 link">ServerHtml</text>
</view>
<view v-if="nthChild==2" class="details-top">
<rich-text v-html="item.Preview.data" :nodes="item.Preview.data"></rich-text>
</view>
</block>
</view>
</view>
</view>
</template>
<script>
import objTree from './objTree.vue'
export default {
name:"InterceptorRequest",
components:{
objTree
},
props:{
livingExample:{
type:Object,
default:()=>{
return {}
}
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA
},
exDataLength() {
return this.livingExample.DATA.DATA.length
},
analysis(){
return (item)=>this.solveLogItem(item)
}
},
data(){
return {
openIndex:0,
nthChild:0,
list:[]
}
},
mounted() {
this.$emit("setScrollToLower")
},
methods:{
copy(item){
uni.setClipboardData({
data:''+JSON.stringify(item),
success() {
uni.showToast({
title:"复制成功"
})
}
})
},
showUp(item,index){
uni.request({...item.Headers})
},
onDel(){
this.livingExample.DATA.init()
}
},
created() {
}
};
</script>
<style lang="scss">
.warn{
color: #f8b251;
background: rgba($color: #c3a356, $alpha: .2);
box-shadow: 0 0 1rpx #f8b251;
}
.error{
color: #d50000;
background: rgba($color: #7c3615, $alpha: .3);
box-shadow: 0 0 1rpx #d50000;
}
*{
word-break: break-all;
}
.headline{
width: 100vw;
display: flex;
justify-content: space-between;
border: 1rpx solid #303030;
text{
padding: 0 8rpx;
border-right: 1rpx solid #303030;
text-align: center;
font-weight: 600;
}
}
.method-text{
flex: 1;
}
.url-text{
flex: 3;
max-width: 50%;
text-align: right;
text-overflow: overflow;
}
.status-text{
flex: 1;
}
.fw600{
font-weight: 600;
}
.link{
margin-bottom: 4rpx;
width: 100%;
border-bottom: 2rpx solid #999999;
}
.details{
display: flex;
text{
border-bottom: 1rpx solid #999999;
border-right: 1rpx solid #999999;
&:nth-child(1){
flex: 1;
}
&:nth-child(2){
flex: 6;
}
}
.body-json{
flex: 6;
}
}
.details-view{
width: 100%;
}
.details-top{
border-top: 1rpx solid #999999;
}
.del-text{
position: fixed;
top: calc(20vh + 24rpx);
}
</style>

@ -0,0 +1,181 @@
<template>
<view>
<view class="">
<text @click="eliminateAll">🚫</text>
</view>
<view class="">
<!-- {{exData}} -->
<view class="details-top">
<view @click="openIndex==indx?openIndex=-1:openIndex=indx" v-for="(item,indx) in exData" :key="indx" class="details">
<text>{{item.key}}</text>
<text v-if="openIndex==indx">{{item.obj}}</text>
<text v-else style="max-height: 100rpx;overflow: hidden;text-overflow: ellipsis;">{{item.obj}}</text>
<text @click.stop="edit(item,indx)"> {{'✍'}} </text>
<text @click.stop="copy(item)">{{'📋'}} </text>
<text @click.stop="remove(item,indx)">{{'❌'}} </text>
</view>
</view>
</view>
<view v-if="editState" class="edit-view">
<text>key:</text>
<input type="text" v-model="storageItem.key" />
<text>obj:</text>
<textarea :value="analysis" placeholder="" @input="textAreaInput" />
<text class="bnt" @click.stop="editOK()">{{'💾'}}</text>
<text class="bnt" @click.stop="editState=false">{{'❎'}}</text>
<text>{{'待验证的'}}</text>
</view>
</view>
</template>
<script>
let textValue = ''
export default {
name:'StorageInit',
components:{
},
props:{
livingExample:{
type:Object,
default:()=>{
return {}
}
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA
},
analysis:{
get(){
return JSON.stringify(this.storageItem.obj)
},
set(val){
if(typeof val == 'string'){
try{
val = JSON.parse(val)
}catch(e){
}
}
return this.storageItem.obj = val
}
}
},
data(){
return {
openIndex:0,
storageItem:{},
storageIndex:-1,
editState:false,
}
},
created() {
},
methods:{
copy(item){
uni.setClipboardData({
data:''+ JSON.stringify(item),
success() {
uni.showToast({
title:"复制成功"
})
},
fail() {
uni.showToast({
title:"复制失败"
})
}
})
},
eliminateAll(){
this.livingExample.DATA.eliminateAll()
},
remove(item,index){
this.livingExample.DATA.remove(item.key,index)
},
edit(item,index){
this.storageItem = item
this.storageIndex = index
this.editState = true
},
editOK(){
this.analysis = textValue
this.livingExample.DATA.edit(this.storageItem,this.storageIndex)
this.editState = false
},
textAreaInput(e){
textValue = e.detail.value
}
}
};
</script>
<style lang="scss">
*{
word-break: break-all;
}
.details{
display: flex;
border-bottom: 1rpx solid #999999;
text{
border-right: 1rpx solid #999999;
&:nth-child(1){
flex: 1;
}
&:nth-child(2){
flex: 6;
}
}
view{
border-bottom: 1rpx solid #999999;
border-right: 1rpx solid #999999;
flex: 6;
}
}
.details-view{
width: 100%;
}
.details-top{
border-top: 1rpx solid #999999;
}
.edit-view{
box-sizing: border-box;
position: absolute;
padding: 20rpx;
top: 20rpx;
left: 10vw;
// margin: 0 auto;
width: 80vw;
max-height: 60vh;
background: #ffffff;
border: 1rpx solid #999999;
box-shadow: 0rpx 10rpx 30rpx #333333;
text{
padding: 8rpx 0;
font-weight: 600;
}
input{
margin: 20rpx 0;
width: 100%;
box-sizing: border-box;
border: 1rpx solid #999999;
}
textarea{
margin: 20rpx 0;
width: 100%;
box-sizing: border-box;
border: 1rpx solid #999999;
}
.bnt{
margin-right: 80rpx;
padding: 0 40rpx;
border: 1rpx solid #999999;
}
}
</style>

@ -0,0 +1,156 @@
<template>
<view>
<block v-if="isObjectsThesaurus">
<view v-for="(item,index) in objects" :key="index" class="flex">
<text v-if="isShowKey" class="colorfc98ff">{{index}}:</text>
<text v-if="isArray(item)" class="color7898ff">Array ({{item.length}})</text>
<text v-if="isThesaurus(item) === 1" :class="{link:isAt&&index==objectsLength}" >{{(item+'')||'null'}}</text>
<view v-else-if="isThesaurus(item) === 2" @click.stop="openFunc==(index+'func')?openFunc='':openFunc=(index+'func')" class="flex bg_kuang">
<text> {{openFunc!=(index+'func')?'❓':'⚡'}}</text>
<text class="colorfc98ff" v-if="openFunc!=(index+'func')">{{item.name+' '}}F()</text>
<text v-if="openFunc==(index+'func')" >{{item.toString()}}</text>
</view>
<view v-else class="flex bg_kuang" >
<text @click.stop="openType==index?openType=-1:openType=index">{{openType==index?'':''}}</text>
<!-- <text @click.stop="openType==index?openType=-1:openType=index" v-if="openType!=index" class="preview">{{JSON.stringify(item)}}</text> -->
<objTree v-if="openType==index && index!=='$vm'" :objects="item"></objTree>
<text v-if="openType==index && index=='$vm'" >[Object,$vm]</text>
<!-- <text @click.stop="setIsOpen(index)">{{isOpen(index)?'':''}}</text>
<objTree v-if="isOpen(index) && item!=='$vm'" :objects="item"></objTree>
<text v-if="isOpen(index) && item=='$vm'" >[$vm]</text> -->
</view>
</view>
</block>
<text v-else>{{objectType}}</text>
</view>
</template>
<script>
// import objTree from './objTree.vue'
import * as tool from './../common/tool.js'
const typeArr = ['boolean', 'undefined', 'number', 'string', 'null']
export default {
name: 'objTree',
/* components: {
objTree
}, */
props: {
objects: {
default: {}
},
isShowKey:{
type:Boolean,
default:true
},
isAt:{
type:Boolean,
default:false
}
},
data() {
return {
openType: -1,
openFunc:'',
isNull:true,
isObjectsThesaurus:false,
openTypeSet:new Set(),
objectsLength:-1,
objectsKeys:[]
}
},
computed: {
isThesaurus() {
this.isNull = false
return (k)=>this.thesaurus(k)
},
isType(){
return (k) => {
let type = typeof k;
if (typeArr.includes(type) || k === null || type === 'function') {
return type
} else if (type === 'function') {
return type
}else {
return ''
}
}
},
objectType(){
if(tool.isArray(this.objects)){
return '[]'
}else if(tool.isObject(this.objects)){
return '{}'
}else{
return '{}'
}
},
isArray(){
return (k)=>tool.isArray(k)
},
isOpen(){
const openTypeSet = this.openTypeSet
return (index)=>openTypeSet.has(index)
}
},
mounted() {
// this.analysisObjects()
this.objectsKeys = Object.keys(this.objects)
if(this.objectsKeys.length){
this.isObjectsThesaurus = true
}
//#ifdef APP
this.isAt && (this.objectsLength = this.objects.length-1)
// #endif
},
methods: {
thesaurus(k){
let type = typeof k;
if (typeArr.includes(type) || k === null) {
return 1
} else if (type === 'function') {
return 2
}else {
return 0
}
},
setIsOpen(index){
let openTypeSet = this.openTypeSet
if(openTypeSet.has(index)){
openTypeSet.delete(index)
}else{
openTypeSet.add(index)
}
this.openTypeSet = openTypeSet
}
}
};
</script>
<style lang="scss">
.inline-flex{
display: inline-flex;
flex-wrap: wrap;
}
.flex{
display: flex;
flex-wrap: wrap;
}
.bg_kuang{
border: #3F536E solid 1rpx;
}
.colorfc98ff{
color: #9e467c;
}
.color7898ff{
color: #7898ff;
}
.preview{
height: 30rpx;
text-overflow: ellipsis;
overflow: hidden;
}
.link{
color: #5500ff;
}
</style>

@ -0,0 +1,62 @@
<template>
<view @click.stop >
<view class="setting">
<text>这里是设置箱</text>
<text></text>
<text>🚫</text>
<br/>
<text>请期待更多设置</text>
<view v-for="(item,index) of HFDebuggingInformation.settingData" :key="index">
<block v-if="item.type == 'switch'" >
<text>{{item.name}}</text>
<switch class="switch" :checked="item.value" @change="switchFunc(item,index,$event)" />
</block>
<text>{{index}}:</text>
<text>{{item.value}}</text>
</view>
</view>
</view>
</template>
<script>
import {
HFDebuggingInformation
} from './../common/store.js'
export default {
name: 'setting',
components: {
},
props: {},
data() {
return {
HFDebuggingInformation
}
},
created() {
this.HFDebuggingInformation = HFDebuggingInformation[0]
},
methods:{
switchFunc(item,index,$event){
this.HFDebuggingInformation.settingData[index].value = !this.HFDebuggingInformation.settingData[index].value
}
}
};
</script>
<style lang="scss">
.setting {
position: fixed;
min-height: calc(80vh - 20rpx);
width: 100vw;
z-index: 999;
left: 0;
bottom: 0rpx;
background: #333333;
color: #FFFFFF;
}
.switch{
transform:scale(0.6)
}
</style>

@ -0,0 +1,84 @@
{
"id": "HF-HF_debugging",
"displayName": "uni_modules插件 - 类Vconsole APP端调试工具 - HF调试器",
"version": "0.0.2-rc-5",
"description": "类Vconsole调试工具 ",
"keywords": [
"辅助脚本",
"Vconsole",
"调试",
"",
"APP端调试工具"
],
"repository": "https://gitee.com/hf4514/hf_debugging",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "u"
},
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

@ -0,0 +1,38 @@
<template>
<view>
<HFBox></HFBox>
</view>
</template>
<script>
import HFBox from './../../components/HFBox.vue'
export default {
components:{
HFBox
},
data() {
return {
tets:'测试'
}
},
onShow() {
// ||getCurrentPages().lengt<=1
/* uni.navigateBack({
delta: 1
}) */
},
onBackPress(){
uni.$emit("viewShow")
},
methods: {
},
onHide() {
uni.$emit("viewShow")
}
}
</script>
<style>
</style>

@ -0,0 +1,429 @@
<template>
<view class="bg_HFconsole">
<view class="mark" @click="onMark"></view>
<view class="bg_kuang">
<view class="flex">
<text @click="onTlite(0)" :style="tliteIndex==0?'background-color: #ffaa7f;':''"
class="tlite-one">Log</text>
<text @click="onTlite(1)" :style="tliteIndex==1?'background-color: #ffaa7f;':''"
class="tlite-one">Network</text>
<text @click="onTlite(2)" :style="tliteIndex==2?'background-color: #ffaa7f;':''"
class="tlite-one">Storage</text>
</view>
<view v-if="tliteIndex==0" class="Log">
<scroll-view :scroll-into-view="log_scroll_bot" style="height: 1100rpx;" scroll-y="true">
<view :style="item[0]=='error'?'background-color: #ef918a;':''" class="item flex"
v-for="(item,index) in CONSOLE_DATA_LOG">
<text :style="item[0]=='error'?'background-color: #ef513c;':''"
class="item_name">{{item[0]}}</text>
<!-- <text class="flex item_cent">{{item[1]}}</text> -->
<text v-for="(it,ind) in item[1]" :key="ind" class="flex item_cent">{{JSONString(it)}}</text>
</view>
<view v-if="!CONSOLE_DATA_LOG.length" class="">
{{logType+'-'}}空~
</view>
<!-- style="background: #2C405A; width: 100%; justify-content: space-between;" -->
<view class="flex" >
<view class="flex" >
<view @click="logType = 'All',setLogScrollBot()" class="bnt-view" :class="{'bnt-hit':logType=='All'}">
All
</view>
<view @click="logType = 'Log',setLogScrollBot()" class="bnt-view" :class="{'bnt-hit':logType=='Log'}">
Log
</view>
<view @click="logType = 'Error',setLogScrollBot()" class="bnt-view" :class="{'bnt-hit':logType=='Error'}">
Error
</view>
</view>
<view @click="eliminate" class="bnt-view-1">
清除
</view>
</view>
<view class="log_scroll_bot flex" id="log_scroll_bot0">
<textarea v-model="valLog" @confirm="confirmLog" placeholder="可输入指令进行执行(实验性的)" />
<view class="" @click="confirmLog">执行</view>
</view>
</scroll-view>
</view>
<view v-if="tliteIndex==1" class="Network">
<scroll-view :scroll-into-view="log_scroll_bot" style="height: 1100rpx;" scroll-y="true">
<view :style="(+item.Preview.statusCode)>=400?'background:#c24346;':'background-color: #aaaa7f;'"
class="item flex Network_item" v-for="(item,index) in CONSOLE_DATA.request">
<text class="GET">{{index}}.</text>
<text :class="item.Headers.method">{{item.Headers.method}}</text>
<text class="GET">{{item.Preview.statusCode==undefined?'CORS ERR':item.Preview.statusCode}}</text>
<text class="URL" @click="onClickCent(item.Headers.url,index)">{{item.Headers.url}}</text>
<view class="requestInitData" @click="onClickCent(item.Headers,index.data)"
v-for="(it,ind) in requestInitData(item.Headers.data)">
<text class="">{{ind}}:</text>
<text class="">{{it}}</text>
</view>
<rich-text v-if="(+item.Preview.statusCode)>=400" class="preview_data"
v-html="item.Preview.data" style=""></rich-text>
<text v-else class="preview_data">{{item.Preview.data}}</text>
</view>
<view class="log_scroll_bot" id="log_scroll_bot1"></view>
</scroll-view>
</view>
<view v-if="tliteIndex==2" class="Storage">
<scroll-view :scroll-into-view="log_scroll_bot" style="height: 1100rpx;" scroll-y="true">
<view class="item_storage flex" v-for="(item,index) of CONSOLE_DATA.storage">
<text class="text_name">{{index}}</text>
<view @click="onClickCent(item,index)" class="text_name_cent">
<text>{{item}}</text>
</view>
</view>
<view class="log_scroll_bot" id="log_scroll_bot2"></view>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
import * as tool from './../../common/tool.js'
import HFTool from './../../common/index.js'
export default {
data() {
return {
valLog: "",
tliteIndex: -1,
CONSOLE_DATA:HFTool.CONSOLE_DATA,
/* CONSOLE_DATA: {
request: [],
console: [
["log", "欢迎使用HF调试器~~~"]
],
storage: {},
URL: "",
}, */
scrollTop: 0,
log_scroll_bot: '',
logType:'All'
}
},
computed:{
CONSOLE_DATA_LOG(){
if(this.logType == 'All'){
return HFTool.CONSOLE_DATA.console
}else if(this.logType == 'Log'){
return HFTool.CONSOLE_DATA.consoleData.log
}else{
return HFTool.CONSOLE_DATA.consoleData.error
}
}
},
/* watch:{
['CONSOLE_DATA.console'](){
this.log_scroll_bot = "log_scroll_bot"
this.$nextTick(() => {
this.log_scroll_bot = 'log_scroll_bot' + this.type
})
}
}, */
onShow() {
// ||getCurrentPages().lengt<=1
if (this.tliteIndex == -1) {
this.onTlite(0)
} else {
uni.navigateBack({
delta: 1
})
}
},
methods: {
JSONString(it){
try{
JSON.stringify(it)
return it
}catch(e){
return it.toString()
}
},
eliminate(){
HFTool.CONSOLE_DATA.consoleData={
log:[],
error:[]
}
HFTool.CONSOLE_DATA.console=[
["log", ["欢迎使用HF调试器~~~"]]
]
},
confirmLog() {
this.CONSOLE_DATA.console.push(["eval-cmd>", [this.valLog]])
let result = ''
let $content = ''
try {
result = eval.call(global, '(' + this.valLog + ')');
} catch (e) {
try {
result = eval.call(global, this.valLog);
} catch (e) {
;
}
}
if (tool.isArray(result) || tool.isObject(result)) {
result = getApp()!=result?result:'isObject - getApp'
} else {
if (tool.isNull(result)) {
result = 'null';
} else if (tool.isUndefined(result)) {
result = 'undefined';
} else if (tool.isFunction(result)) {
result = 'function()'
} else if (tool.isString(result)) {
result = '"' + result + '"';
}
}
HFTool.CONSOLE_DATA.console.push(["eval<", [result || 'undefined']])
this.valLog = ""
this.log_scroll_bot = 'log_scroll_bot'
this.$nextTick(() => {
this.log_scroll_bot = 'log_scroll_bot' + this.type
})
},
setLogScrollBot(){
this.log_scroll_bot = 'log_scroll_bot'
this.$nextTick(() => {
this.log_scroll_bot = 'log_scroll_bot0'
})
},
onMark() {
uni.navigateBack({
delta: 1
})
},
onTlite(type) {
if (!HFTool.CONSOLE_DATA) {
uni.navigateBack({
delta: 1
})
}
this.tliteIndex = type
// this.CONSOLE_DATA = HFTool.CONSOLE_DATA || this.CONSOLE_DATA
this.log_scroll_bot = 'log_scroll_bot'
this.$nextTick(() => {
this.log_scroll_bot = 'log_scroll_bot' + type
})
},
onClickCent(item, index) {
uni.setClipboardData({
data: '' + item,
success: function() {
uni.showToast({
title: "复制成功"
})
}
});
},
requestInitData(item) {
if (typeof item == 'String') {
let OBJ = {}
item.split("&").forEach(item => {
let itema = item.split("=")
OBJ[itema[0]] = itema[1]
})
return OBJ
}
return item
}
}
}
</script>
<style lang="scss">
page {
background-color: rgba(220, 38, 38, 0.0) !important;
}
view,
scroll-view,
swiper,
button,
input,
textarea,
label,
navigator,
image {
box-sizing: border-box;
}
.place {
width: 100%;
color: #007AFF;
}
.GET,
.POST,
.put,
.patch,
.head,
.delete {
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #00aa00 1px;
background-color: #55aa7f;
color: #ffffff;
border-radius: 8rpx;
}
.URL {
width: 100%;
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #ff5500 1px;
background-color: #ffaa7f;
color: #ffffff;
border-radius: 8rpx;
word-break: break-all;
}
.Network_item {
width: 100%;
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #005500 1px;
border-radius: 8rpx;
}
.requestInitData {
width: 100%;
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #aaff00 1px;
background-color: #df8d3a;
color: #ffffff;
border-radius: 8rpx;
}
.preview_data {
width: 100%;
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #aaff00 1px;
background-color: #FFFFFF;
border-radius: 8rpx;
}
.item_name {
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #00aa00 1px;
background-color: #55aa7f;
color: #ffffff;
border-radius: 8rpx;
}
.item_cent {
width: 90%;
padding: 8rpx;
white-space: wrap;
display: flex;
flex-wrap: wrap;
overflow: auto;
word-break: break-all;
}
.text_name {
margin-right: 6rpx;
margin-bottom: 9rpx;
padding: 8rpx;
border: #ff6a06 1px;
background-color: #ffaa00;
border-radius: 8rpx;
}
.text_name_cent {
padding: 8rpx;
border: #55aa00 1px;
background-color: #aaff7f;
border-radius: 8rpx;
white-space: wrap;
word-break: break-all;
}
.item_storage {
padding: 8rpx;
margin: 2rpx;
}
.mark {
position: fixed;
left: 0;
top: 0;
width: 750rpx;
height: 1920rpx;
background-color: #2F364E;
opacity: 0.3;
}
.flex {
display: flex;
flex-direction: row;
// flex-wrap: wrap;
}
.bg_HFconsole {
display: flex;
background-color: rgba(220, 38, 38, 0.0);
}
.bg_kuang {
position: fixed;
bottom: 0;
left: 0;
background-color: #FFFFFF;
height: 1200rpx;
width: 750rpx;
}
.tlite-one {
padding: 20rpx;
background-color: #e7e7e7;
border: 1px #9c9c9c;
}
.Log {}
.item {
padding: 8rpx 20rpx;
border: 1px #424242;
background-color: #e3e3e3;
flex-wrap: wrap;
}
.log_scroll_bot {
padding: 32rpx;
width: 750rpx;
min-height: 100rpx;
background-color: #ffffff;
}
.bnt-view{
background: #F1F1F1;
border: #55557f 2rpx solid;
padding: 18rpx 30rpx;
}
.bnt-view-1{
background: #ff5650;
border: #55557f 2rpx solid;
padding: 18rpx 40rpx;
// margin-left: 200rpx;
}
.bnt-hit{
background: #aaaa7f;
}
</style>

@ -0,0 +1,60 @@
<template>
<view class="bg" @touchstart="drawStart" @touchmove="drawMove" @touchend="drawEnd" >
<!-- <text @click="onClick" class="name">HF调试器</text> -->
<text @click="onClick" class="name">HF调试器</text>
</view>
</template>
<script>
export default {
data() {
return {
type:0
}
},
methods: {
onClick(){
uni.$emit("HFshow")
},
drawStart(event){
this.startX = event.touches[0].clientX;
},
drawMove(event){
/* const subNVue = uni.getSubNVueById('concat');
subNVue.setStyle({
"position": "fixed",
"right":event.touches[0].clientX,
"bottom":event.touches[0].clientY,
"width": "100%",
"height": "100%",
"background": "transparent"
}) */
},
drawEnd(event){
}
}
}
</script>
<style scoped>
.bg{
/* width: 100%;
height: 100%; */
}
.name{
border-radius: 10rpx;
position: fixed;
right: 0rpx;
bottom: 0rpx;
line-height: 80rpx;
text-align: center;
width: 200rpx;
height: 80rpx;
background-color: #FF4A46;
color: #FFFFFF;
}
</style>

@ -0,0 +1,333 @@
# HF-HF_debugging
## 0.0.2rc 更新的主要功能
- 新增 基于uni技术栈的请求重复发如有其他技术栈的需要可以进行插件扩展
- 新增 Storage 编辑
- 新增 AppData 预览
- 新增 页面栈信息预览
- 新增 插件功能,开发者可以根据需求进行扩展 (例如扩展:获取所有图片地址、)
- ui样式优化 增加设置箱 设置深浅色
## @注意 如果使用第三方请求拦截库 可能 Network 无请求信息
- 解决:
````JavaScript
// 本框架默认已将 wx.request 替换为 uni.request 已经适配大多数 第三方请求库
/* 0.0.1-rc.2 及一下版本 */
// 因为大部分的开平台库都是基于微信小程序标准开发的
// 这里已 flyio 为例
// 在 flyio 文件中全局搜索 wx.request 替换为 uni.request 即可拦截请求信息
````
## @注意 配置信息添加
```JavaScript
// main.js 文件示例
/* 注意当前是 0.0.2rc 及以上版本的设置
不再是直接引用就可以还需要 new 成一个实例
*/
import App from './App'
import {HFdebugging} from '@/uni_modules/HF-HF_debugging/common/next.js'
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
new HFdebugging()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
new HFdebugging({app});
return {
app
}
}
// #endif
```
``` jons5
// pages.json 添加如下页面信息
"pages":[
// ...
{
"path": "uni_modules/HF-HF_debugging/pages/next/next",
"style": {
"navigationStyle": "custom",
"backgroundColor": "transparent",
"app-plus": {
"animationType": "slide-in-bottom",
"background": "transparent",
"popGesture": "none"
}
}
},
]
```
## API 文档
### 组件说明
- BntBox HF调试器红色按钮组件 /uni_modules/HF-HF_debugging/components/BntBox/index.vue
- HFBox 调试面板组件 /uni_modules/HF-HF_debugging/components/HFBox.vue
- InterceptorRequest 请求组件 /uni_modules/HF-HF_debugging/components/InterceptorRequest.vue
- StorageInit 缓存组件 /uni_modules/HF-HF_debugging/components/StorageInit.vue
- Console 日志组件 /uni_modules/HF-HF_debugging/components/Console.vue
- setting 设置组件 /uni_modules/HF-HF_debugging/components/setting.vue
- AppData 页面AppData数据组件 /uni_modules/HF-HF_debugging/components/AppData.vue
- CurrentPages 页面栈组件 /uni_modules/HF-HF_debugging/components/CurrentPages.vue
- objTree 对象树状结构组件 /uni_modules/HF-HF_debugging/components/objTree.vue
### HFdebugging 实例中的API
- options 配置项
- view App 中HF调试按钮按钮实例
- information 插件实例列表
- settingData 设置项数据
- hide():void 隐藏按钮
- show():void 显示按钮
- loadPlugIn(PlugIn):void 挂在某插件实例
- getPlugIn(plugInName):PlugIn 获取某插件实例
- removePlugIn(plugInName):void 删除某插件实例
- wx_request wx.request 原始值
### Console 实例中的API
- addRecord(type:string,...args):void 添加指定的日志信息
```JavaScript
let HF = new HFdebugging();
let Console = HF.getPlugIn('Console');
Console.addRecord('log','日志信息');
Console.addRecord('warn','warn信息');
Console.addRecord('info','info信息');
Console.addRecord('error','error信息');
```
### 插件使用
- 调用new 后的实例方法 将插件实例进行挂载
```javaScript
/**
* 带 * ✳ 星号 为必存项
*
* */
let HF = new HFdebugging();
HF.loadPlugIn(MyPlugIn);
// MyPlugIn 必须是一个类
class MyPlugIn{ // 插件实例
DATA = [] // ✳
NAME = 'myPlugIn' // 插件名称 ✳
componentsName='myPlugIn' // vue 组件名称 需要全局引入组件 ✳
constructor(){
this.DATA = new MyPlugInClass() // 数据信息 ✳
this._init()
}
_init() {
// ...
// 拦截处理请求等
}
}
// MyPlugInClass 数据 必须是一个类
class MyPlugInClass { // 数据管理器
DATA = [] // ✳
constructor(arg) {
this._myPlugInData = true // ✳ 数据值判断
this.init()
}
init() {
this.DATA = []
}
push(args) {
if (this.DATA.length > 512) {
this.DATA.shift()
}
this.DATA.push(args)
}
eliminateAll(){
this.DATA = [];
}
// 可以使用 get 拦截请求 DATA 数据时进行处理
get DATA() { // 注意 get 后的变量名不能重复 否则报错 这是 this.DATA 需要更改为 变量名 例如DATAC
/* 获取storage */
let storageAllData = []
let that = this
uni.getStorageInfo({
success(res) {
res.keys.forEach(item => {
// storageAllData[item] = JSON.stringify(uni.getStorageSync(item))
storageAllData.push({
key: item,
obj: uni.getStorageSync(item)
})
})
that.DATAC = storageAllData
}
})
return this.DATAC
}
}
// 组件
// objTree 是一个树状结构组件 按需引入
// import objTree from './objTree.vue'
export default {
name: 'AppData',
// components: {
// objTree
// },
props: {
/**
* ✳ 每一个插件组件都会传递来一个 当前插件的实例 既 MyPlugIn
* 每一个插件实例的prototype下都存在 $HFdebugging 属性,
* $HFdebugging 便是 HFdebugging 的实例
* 例如 PlugIn.prototype.$HFdebugging
* 可以调用HFdebugging获取所有的 插件及配置项
* this.livingExample.$HFdebugging.options // 获取new HFdebugging 时传递的参数信息
* this.livingExample.$HFdebugging.view // HF调试器 按钮的实例
* this.livingExample.$HFdebugging.settingData // 设置信息
* this.livingExample.$HFdebugging.information // 所有的插件实例 是一个数组
* 如果不喜欢使用上述方法获取对用信息也可以引入 store 获取 类型均为数组
* import {HFDebuggingInformation,information} from '@/uni_modules/HF-HF_debugging/common/store'
*/
livingExample: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
openType:1
}
},
computed: {
exData() {
return this.livingExample.DATA.DATA // MyPlugIn 中的数据管理器,下的实际数据
}
},
methods:{
scrolltolower(e){}, // 来自父级的触底事件
scrolltoupper(e){}, // 来自父级的触顶事件
}
}
```
## @注意 一下为0.0.1的配置说明 如果使用第三方请求拦截库 可能 Network 无请求信息
- 解决:
````JavaScript
// 本框架默认已将 wx.request 替换为 uni.request 已经适配大多数 第三方请求库
// 如需取消默认替换请在 请调用HFdebugging(app,{wxRequest:false})
// 并在沿用0.0.1-rc.2 及一下版本版本方法替换
/* 0.0.1-rc.2 及一下版本 */
// 因为大部分的开平台库都是基于微信小程序标准开发的
// 这里已 flyio 为例
// 在 flyio 文件中全局搜索 wx.request 替换为 uni.request 即可拦截请求信息
````
## @注意 一下为0.0.1的配置说明 配置信息添加
```JavaScript
// main.js 文件示例
import App from './App'
// #ifdef APP
import {HFdebugging} from '@/uni_modules/HF-HF_debugging/common/index.js'
// #endif
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
HFdebugging(app)
return {
app
}
}
// #endif
```
``` jons5
// pages.json 添加如下页面信息
"pages":[
// ...
{
"path": "uni_modules/HF-HF_debugging/pages/subnvue/HFconsole",
"style": {
"navigationStyle": "custom",
"backgroundColor": "transparent",
"app-plus": {
"animationType": "slide-in-bottom",
"background": "transparent",
"popGesture": "none"
}
}
},
/* 注意 0.0.1-rc.1及一下版本需要添加 concat 文件 */
{
"path": "uni_modules/HF-HF_debugging/pages/subnvue/concat"
}
// ...
]
/* 注意 0.0.1-rc.1及一下版本需要添加一下内容 */
"globalStyle": {
// ...
"subNVues": [{
"id": "concat", // 唯一标识
"path": "uni_modules/HF-HF_debugging/pages/subnvue/concat", // 页面路径
"style": {
"position": "absolute",
"right": "80rpx",
"bottom": "120rpx",
"width": "200rpx",
"height": "80rpx",
"background": "transparent"
}
}]
// ...
}
```
## 如果有兴趣一起开发的可以在gitee上申请加入
## 未来计划
- [-] 优化 Vue3 环境错误拦截
- [-] 优化纯nvue环境的渲染
- [-] 优化插件管理系统
- [-] 欢迎在 评论区 提问 或 改进建议
- [-] ...等

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title></title>
<!--preload-links-->
<!--app-context-->
<style type="text/css">
</style>
</head>
<body>
<div id="app" ></div>
121212
<script src="__uniappes6.js"></script>
<script src="view.umd.min.js"></script>
<script src="app-view.js"></script>
<script type="text/javascript">
document.getElementById("app").innerHTML="DDDDDDDD"
var onType = false
var div = document.createElement('div');
var startX = 0
var startY = 0
let body = document.getElementsByTagName('body')
div.id = 'HF2';
div.innerText = 'HF调试器';
div.style.borderRadius = '5px';
div.style.backgroundColor = '#FF4A46';
div.style.color = '#FFFFFF';
div.style.width = '100px';
div.style.height = '40px';
div.style.position = 'fixed';
div.style.right = '0px';
div.style.bottom = '0px';
div.style.lineHeight='40px';
div.style.textAlign= 'center';
document.getElementsByTagName('body')[0].appendChild(div);
div.onclick = (e)=>{
UniViewJSBridge.publishHandler('BNT_VIEW',e);
};
</script>
</body>
</html>

@ -0,0 +1,33 @@
## 1.2.22023-01-28
- 修复 运行/打包 控制台警告问题
## 1.2.12022-09-05
- 修复 当 text 超过 max-num 时badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
## 1.1.72021-11-08
- 优化 升级ui
- 修改 size 属性默认值调整为 small
- 修改 type 属性,默认值调整为 errorinfo 替换 default
## 1.1.62021-09-22
- 修复 在字节小程序上样式不生效的 bug
## 1.1.52021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.42021-07-29
- 修复 去掉 nvue 不支持css 的 align-self 属性nvue 下不暂支持 absolute 属性
## 1.1.32021-06-24
- 优化 示例项目
## 1.1.12021-05-12
- 新增 组件示例地址
## 1.1.02021-05-12
- 新增 uni-badge 的 absolute 属性,支持定位
- 新增 uni-badge 的 offset 属性,支持定位偏移
- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
- 优化 uni-badge 属性 custom-style 支持以对象形式自定义样式
## 1.0.72021-05-07
- 修复 uni-badge 在 App 端数字小于10时不是圆形的bug
- 修复 uni-badge 在父元素不是 flex 布局时宽度缩小的bug
- 新增 uni-badge 属性 custom-style 支持自定义样式
## 1.0.62021-02-04
- 调整为uni_modules目录规范

@ -0,0 +1,268 @@
<template>
<view class="uni-badge--x">
<slot />
<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
class="uni-badge" @click="onClick()">{{displayValue}}</text>
</view>
</template>
<script>
/**
* Badge 数字角标
* @description 数字角标一般和其它控件列表9宫格等配合使用用于进行数量提示默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容
* @property {String} size = [normal|small] 角标内容
* @property {String} type = [info|primary|success|warning|error] 颜色类型
* @value info 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {String} inverted = [true|false] 是否无需背景颜色
* @property {Number} maxNum 展示封顶的数字值超过 99 显示 99+
* @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
* @value rightTop 右上
* @value rightBottom 右下
* @value leftTop 左上
* @value leftBottom 左下
* @property {Array[number]} offset 距定位角中心点的偏移量只有存在 absolute 属性时有效例如[-10, -10] 表示向外偏移 10px[10, 10] 表示向 absolute 指定的内偏移 10px
* @property {String} isDot = [true|false] 是否显示为一个小点
* @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge>
*/
export default {
name: 'UniBadge',
emits: ['click'],
props: {
type: {
type: String,
default: 'error'
},
inverted: {
type: Boolean,
default: false
},
isDot: {
type: Boolean,
default: false
},
maxNum: {
type: Number,
default: 99
},
absolute: {
type: String,
default: ''
},
offset: {
type: Array,
default () {
return [0, 0]
}
},
text: {
type: [String, Number],
default: ''
},
size: {
type: String,
default: 'small'
},
customStyle: {
type: Object,
default () {
return {}
}
}
},
data() {
return {};
},
computed: {
width() {
return String(this.text).length * 8 + 12
},
classNames() {
const {
inverted,
type,
size,
absolute
} = this
return [
inverted ? 'uni-badge--' + type + '-inverted' : '',
'uni-badge--' + type,
'uni-badge--' + size,
absolute ? 'uni-badge--absolute' : ''
].join(' ')
},
positionStyle() {
if (!this.absolute) return {}
let w = this.width / 2,
h = 10
if (this.isDot) {
w = 5
h = 5
}
const x = `${- w + this.offset[0]}px`
const y = `${- h + this.offset[1]}px`
const whiteList = {
rightTop: {
right: x,
top: y
},
rightBottom: {
right: x,
bottom: y
},
leftBottom: {
left: x,
bottom: y
},
leftTop: {
left: x,
top: y
}
}
const match = whiteList[this.absolute]
return match ? match : whiteList['rightTop']
},
dotStyle() {
if (!this.isDot) return {}
return {
width: '10px',
minWidth: '0',
height: '10px',
padding: '0',
borderRadius: '10px'
}
},
displayValue() {
const {
isDot,
text,
maxNum
} = this
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
}
},
methods: {
onClick() {
this.$emit('click');
}
}
};
</script>
<style lang="scss" >
$uni-primary: #2979ff !default;
$uni-success: #4cd964 !default;
$uni-warning: #f0ad4e !default;
$uni-error: #dd524d !default;
$uni-info: #909399 !default;
$bage-size: 12px;
$bage-small: scale(0.8);
.uni-badge--x {
/* #ifdef APP-NVUE */
// align-self: flex-start;
/* #endif */
/* #ifndef APP-NVUE */
display: inline-block;
/* #endif */
position: relative;
}
.uni-badge--absolute {
position: absolute;
}
.uni-badge--small {
transform: $bage-small;
transform-origin: center center;
}
.uni-badge {
/* #ifndef APP-NVUE */
display: flex;
overflow: hidden;
box-sizing: border-box;
font-feature-settings: "tnum";
min-width: 20px;
/* #endif */
justify-content: center;
flex-direction: row;
height: 20px;
padding: 0 4px;
line-height: 18px;
color: #fff;
border-radius: 100px;
background-color: $uni-info;
background-color: transparent;
border: 1px solid #fff;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: $bage-size;
/* #ifdef H5 */
z-index: 999;
cursor: pointer;
/* #endif */
&--info {
color: #fff;
background-color: $uni-info;
}
&--primary {
background-color: $uni-primary;
}
&--success {
background-color: $uni-success;
}
&--warning {
background-color: $uni-warning;
}
&--error {
background-color: $uni-error;
}
&--inverted {
padding: 0 5px 0 0;
color: $uni-info;
}
&--info-inverted {
color: $uni-info;
background-color: transparent;
}
&--primary-inverted {
color: $uni-primary;
background-color: transparent;
}
&--success-inverted {
color: $uni-success;
background-color: transparent;
}
&--warning-inverted {
color: $uni-warning;
background-color: transparent;
}
&--error-inverted {
color: $uni-error;
background-color: transparent;
}
}
</style>

@ -0,0 +1,85 @@
{
"id": "uni-badge",
"displayName": "uni-badge 数字角标",
"version": "1.2.2",
"description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
"keywords": [
"",
"badge",
"uni-ui",
"uniui",
"数字角标",
"徽章"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,10 @@
## Badge 数字角标
> **组件名uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件列表、9宫格等配合使用用于进行数量提示默认为实心灰色背景
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

@ -0,0 +1,6 @@
## 0.1.22022-06-08
- 修复 微信小程序 separator 不显示的Bug
## 0.1.12022-06-02
- 新增 支持 uni.scss 修改颜色
## 0.1.02022-04-21
- 初始化

@ -0,0 +1,121 @@
<template>
<view class="uni-breadcrumb-item">
<view :class="{
'uni-breadcrumb-item--slot': true,
'uni-breadcrumb-item--slot-link': to && currentPage !== to
}" @click="navTo">
<slot />
</view>
<i v-if="separatorClass" class="uni-breadcrumb-item--separator" :class="separatorClass" />
<text v-else class="uni-breadcrumb-item--separator">{{ separator }}</text>
</view>
</template>
<script>
/**
* BreadcrumbItem 面包屑导航子组件
* @property {String/Object} to 路由跳转页面路径/对象
* @property {Boolean} replace 在使用 to 进行路由跳转时启用 replace 将不会向 history 添加新记录( h5 支持
*/
export default {
data() {
return {
currentPage: ""
}
},
options: {
virtualHost: true
},
props: {
to: {
type: String,
default: ''
},
replace:{
type: Boolean,
default: false
}
},
inject: {
uniBreadcrumb: {
from: "uniBreadcrumb",
default: null
}
},
created(){
const pages = getCurrentPages()
const page = pages[pages.length-1]
if(page){
this.currentPage = `/${page.route}`
}
},
computed: {
separator() {
return this.uniBreadcrumb.separator
},
separatorClass() {
return this.uniBreadcrumb.separatorClass
}
},
methods: {
navTo() {
const { to } = this
if (!to || this.currentPage === to){
return
}
if(this.replace){
uni.redirectTo({
url:to
})
}else{
uni.navigateTo({
url:to
})
}
}
}
}
</script>
<style lang="scss">
$uni-primary: #2979ff !default;
$uni-base-color: #6a6a6a !default;
$uni-main-color: #3a3a3a !default;
.uni-breadcrumb-item {
display: flex;
align-items: center;
white-space: nowrap;
font-size: 14px;
&--slot {
color: $uni-base-color;
padding: 0 10px;
&-link {
color: $uni-main-color;
font-weight: bold;
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
&:hover {
color: $uni-primary;
}
}
}
&--separator {
font-size: 12px;
color: $uni-base-color;
}
&:first-child &--slot {
padding-left: 0;
}
&:last-child &--separator {
display: none;
}
}
</style>

@ -0,0 +1,41 @@
<template>
<view class="uni-breadcrumb">
<slot />
</view>
</template>
<script>
/**
* Breadcrumb 面包屑导航父组件
* @description 显示当前页面的路径快速返回之前的任意页面
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} separator 分隔符默认为斜杠'/'
* @property {String} separatorClass 图标分隔符 class
*/
export default {
options: {
virtualHost: true
},
props: {
separator: {
type: String,
default: '/'
},
separatorClass: {
type: String,
default: ''
}
},
provide() {
return {
uniBreadcrumb: this
}
}
}
</script>
<style lang="scss">
.uni-breadcrumb {
display: flex;
}
</style>

@ -0,0 +1,88 @@
{
"id": "uni-breadcrumb",
"displayName": "uni-breadcrumb 面包屑",
"version": "0.1.2",
"description": "Breadcrumb 面包屑",
"keywords": [
"uni-breadcrumb",
"breadcrumb",
"uni-ui",
"面包屑导航",
"面包屑"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save