smart-app alpha 版本

This commit is contained in:
zhuoda 2024-03-10 22:26:32 +08:00
parent d64b769d40
commit 728ddb9a7e
295 changed files with 20261 additions and 1 deletions

View File

@ -8,7 +8,7 @@
### **技术体系**
- 前端Vue3 + Vite5 + Vue-Router + Pinia + Ant Design Vue 4.X
- 移动端uniapp + uview2.x
- 移动端uniapp (vue3版本) + uni-ui + 同时支持APP、小程序、H5
- 后端SpringBoot + Sa Token + Mybatis-plus + 多种数据库
- 在线预览:[https://preview.smartadmin.vip](https://preview.smartadmin.vip)
- 官方文档:[https://smartadmin.vip](https://smartadmin.vip)

View File

@ -0,0 +1,3 @@
NODE_ENV=development
VITE_APP_TITLE='SmartAdmin 开发环境(Dev)'
VITE_APP_API_URL='http://127.0.0.1:1024'

3
smart-app/.env.localhost Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=development
VITE_APP_TITLE='SmartH5 本地环境(Local)'
VITE_APP_API_URL='http://127.0.0.1:1024'

3
smart-app/.env.pre Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
VITE_APP_TITLE='SmartH5 预发布环境(Pre)'
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api'

View File

@ -0,0 +1,3 @@
NODE_ENV=production
VITE_APP_TITLE='SmartH5 V3.X'
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api'

3
smart-app/.env.test Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
VITE_APP_TITLE='SmartH5 测试环境(Test)'
VITE_APP_API_URL='http://127.0.0.1:1024'

18
smart-app/.eslintignore Normal file
View File

@ -0,0 +1,18 @@
*.sh
node_modules
lib
*.md
*.woff
*.ttf
.vscode
.idea
dist
public
/docs
.husky
.local
.localhost
/bin
Dockerfile
src/assets

66
smart-app/.eslintrc.cjs Normal file
View File

@ -0,0 +1,66 @@
/*
* @Description:
* @Author: zhuoda
* @Date: 2021-11-05
* @LastEditTime: 2022-07-05
* @LastEditors: zhuoda
*/
module.exports = {
root: true, //此项是用来告诉eslint找当前配置文件不能往父级查找
env: {
browser: true,
es2021: true,
node: true,
},
parser: 'vue-eslint-parser', //使用vue-eslint-parser 来解析vue文件中的 template和script
parserOptions: {
ecmaVersion: 12, // 默认情况下ESLint使用的是ECMAScript5语法此处我们设置的选项是 es12
sourceType: 'module', // 指定js导入的方式
},
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', 'plugin:vue/base'],
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
plugins: ['vue'],
rules: {
'no-unused-vars': [
'error',
// we are only using this rule to check for unused arguments since TS
// catches unused variables but not args.
{ varsIgnorePattern: '.*', args: 'none' },
],
'space-before-function-paren': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': [
'error',
{
ignores: ['index'], //需要忽略的组件名
},
],
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'never',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
// Enable vue/script-setup-uses-vars rule
'vue/script-setup-uses-vars': 'error',
},
};

21
smart-app/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
*.local
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

30
smart-app/.prettierrc.cjs Normal file
View File

@ -0,0 +1,30 @@
/*
* 代码格式化配置
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-12 14:44:18
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
module.exports = {
printWidth: 150, // 每行代码长度默认80
tabWidth: 2, // 缩进空格数
useTabs: false, //不用tab缩进
semi: true, //// 在语句末尾打印分号
singleQuote: true, // 使用单引号而不是双引号
vueIndentScriptAndStyle: true, //Vue文件脚本和样式标签缩进
quoteProps: 'as-needed', // 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
jsxSingleQuote: true, // 在JSX中使用单引号而不是双引号
trailingComma: 'es5', //多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>"默认none
bracketSpacing: true, // 在对象文字中的括号之间打印空格
jsxBracketSameLine: false, //jsx 标签的反尖括号需要换行
arrowParens: 'always', // 在单独的箭头函数参数周围包括括号 always(x) => x \ avoidx => x
rangeStart: 0, // 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeEnd: Infinity,
requirePragma: false, // 指定要使用的解析器,不需要写文件开头的 @prettier
insertPragma: false, // 不需要自动在文件开头插入 @prettier
proseWrap: 'preserve', // 使用默认的折行标准 always\never\preserve
htmlWhitespaceSensitivity: 'css', // 指定HTML文件的全局空格敏感度 css\strict\ignore
endOfLine: 'auto', // 因为prettier的规范和eslint的换行规则不同所以这个必须配置。要不然每次打开文件都会有一堆的警告;换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr
};

20
smart-app/index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<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>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

81
smart-app/package.json Normal file
View File

@ -0,0 +1,81 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",
"dev:app-ios": "uni -p app-ios",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:app-android": "uni build -p app-android",
"build:app-ios": "uni build -p app-ios",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:mp-xhs": "uni build -p mp-xhs",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-3090920231225001",
"@dcloudio/uni-app-plus": "3.0.0-3090920231225001",
"@dcloudio/uni-components": "3.0.0-3090920231225001",
"@dcloudio/uni-h5": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-alipay": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-baidu": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-jd": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-lark": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-qq": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-toutiao": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-weixin": "3.0.0-3090920231225001",
"@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001",
"@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001",
"@dcloudio/uni-ui": "1.5.0",
"lodash": "^4.17.21",
"pinia": "^2.0.36",
"vue": "3.2.47",
"vue-i18n": "9.1.9",
"sm-crypto": "0.3.13",
"crypto-js": "4.1.1"
},
"devDependencies": {
"@dcloudio/types": "3.3.2",
"@dcloudio/uni-automator": "3.0.0-3090920231225001",
"@dcloudio/uni-cli-shared": "3.0.0-3090920231225001",
"@dcloudio/uni-stacktracey": "3.0.0-3090920231225001",
"@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001",
"@vue/runtime-core": "3.2.45",
"sass": "1.69.7",
"sass-loader": "10.1.1",
"vite": "4.0.3",
"prettier": "3.0.2",
"eslint": "8.16.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-prettier": "5.0.0",
"eslint-plugin-vue": "9.17.0"
}
}

10
smart-app/shims-uni.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {
}
}

19
smart-app/src/App.vue Normal file
View File

@ -0,0 +1,19 @@
<script>
import { useUserStore } from '/@/store/modules/system/user';
export default {
onLaunch: function () {
useUserStore().getLoginInfo();
},
onShow: function () {
console.log('App Show');
},
onHide: function () {
console.log('App Hide');
},
};
</script>
<style lang="scss">
/*每个页面公共css */
@import url('./theme/index.scss');
</style>

View File

@ -0,0 +1,31 @@
/*
* @Description:
* @Author: zhuoda
* @Date: 2021-11-05
* @LastEditTime: 2022-06-23
* @LastEditors: zhuoda
*/
import { postRequest, getRequest } from '/@/lib/smart-request';
export const goodsApi = {
// 添加商品 @author zhuoda
addGoods: (param) => {
return postRequest('/goods/add', param);
},
// 删除 @author zhuoda
deleteGoods: (goodsId) => {
return getRequest(`/goods/delete/${goodsId}`);
},
// 批量 @author zhuoda
batchDelete: (goodsIdList) => {
return postRequest('/goods/batchDelete', goodsIdList);
},
// 分页查询 @author zhuoda
queryGoodsList: (param) => {
return postRequest('/goods/query', param);
},
// 更新商品 @author zhuoda
updateGoods: (param) => {
return postRequest('/goods/update', param);
},
};

View File

@ -0,0 +1,37 @@
/*
* 企业信息
*
* @Author: 开云
* @Date: 2023-09-03 21:47:28
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import { postRequest, getRequest } from '/@/lib/smart-request';
export const enterpriseApi = {
// 新建企业 @author 开云
create: (param) => {
return postRequest('/oa/enterprise/create', param);
},
// 查询企业详情 @author 开云
detail: (enterpriseId) => {
return getRequest(`/oa/enterprise/get/${enterpriseId}`);
},
// 分页查询企业模块 @author 开云
pageQuery: (param) => {
return postRequest('/oa/enterprise/page/query', param);
},
// 编辑企业 @author 开云
update: (param) => {
return postRequest('/oa/enterprise/update', param);
},
// 删除企业 @author 开云
delete: (enterpriseId) => {
return getRequest(`/oa/enterprise/delete/${enterpriseId}`);
},
};

View File

@ -0,0 +1,33 @@
/*
* @Description: 公告信息企业动态
* @version:
* @Author: zhuoda
* @Date: 2022-08-16 20:34:36
*/
import { postRequest, getRequest } from '/@/lib/smart-request';
export const noticeApi = {
// ---------------- 通知公告类型 -----------------------
// 通知公告类型-获取全部 @author zhuoda
getAllNoticeTypeList() {
return getRequest('/oa/noticeType/getAll');
},
// --------------------- 【员工】查看 通知公告 -------------------------
// 通知公告-员工-查看详情 @author zhuoda
view(noticeId) {
return getRequest(`/oa/notice/employee/view/${noticeId}`);
},
// 通知公告-员工-查询 @author zhuoda
queryEmployeeNotice(param) {
return postRequest('/oa/notice/employee/query', param);
},
// 【员工】通知公告-查询 查看记录 @author zhuoda
queryViewRecord(param) {
return postRequest('/oa/notice/employee/queryViewRecord', param);
},
};

View File

@ -0,0 +1,17 @@
/**
* 系统更新日志 api 封装
*
* @Author: 卓大
* @Date: 2022-09-26 14:53:50
* @Copyright 1024创新实验室
*/
import { postRequest, getRequest } from '/@/lib/smart-request';
export const changeLogApi = {
/**
* 分页查询 @author 卓大
*/
queryPage: (param) => {
return postRequest('/support/changeLog/queryPage', param);
},
};

View File

@ -0,0 +1,59 @@
/*
* 字典
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-03 21:55:25
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import { postRequest, getRequest } from '/@/lib/smart-request';
export const dictApi = {
// 分页查询数据字典KEY - @author 卓大
keyQuery: (param) => {
return postRequest('/support/dict/key/query', param);
},
// 查询全部字典key - @author 卓大
queryAllKey: () => {
return getRequest('/support/dict/key/queryAll');
},
/**
* 分页查询数据字典value - @author 卓大
*/
valueQuery: (param) => {
return postRequest('/support/dict/value/query', param);
},
// 数据字典KEY-添加- @author 卓大
keyAdd: (param) => {
return postRequest('/support/dict/key/add', param);
},
// 分页查询数据字典value - @author 卓大
valueAdd: (param) => {
return postRequest('/support/dict/value/add', param);
},
// 数据字典key-更新- @author 卓大
keyEdit: (param) => {
return postRequest('/support/dict/key/edit', param);
},
// 数据字典Value-更新- @author 卓大
valueEdit: (param) => {
return postRequest('/support/dict/value/edit', param);
},
// 数据字典key-删除- @author 卓大
keyDelete: (keyIdList) => {
return postRequest('/support/dict/key/delete', keyIdList);
},
// 数据字典Value-删除- @author 卓大
valueDelete: (valueIdList) => {
return postRequest('/support/dict/value/delete', valueIdList);
},
// 缓存刷新- @author 卓大
cacheRefresh: () => {
return getRequest('/support/dict/cache/refresh');
},
// 数据字典-值列表- @author 卓大
valueList: (keyCode) => {
return getRequest(`/support/dict/value/list/${keyCode}`);
},
};

View File

@ -0,0 +1,40 @@
/*
* 登录
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-03 21:59:58
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import { getRequest, postRequest } from '/@/lib/smart-request';
export const loginApi = {
/**
* 登录 @author 卓大
*/
login: (param) => {
return postRequest('/login', param);
},
/**
* 退出登录 @author 卓大
*/
logout: () => {
return getRequest('/login/logout');
},
/**
* 获取验证码 @author 卓大
*/
getCaptcha: () => {
return getRequest('/login/getCaptcha');
},
/**
* 获取登录信息 @author 卓大
*/
getLoginInfo: () => {
return getRequest('/login/getLoginInfo');
},
};

View File

@ -0,0 +1,55 @@
<!---
* 字段 下拉选择框
*
* @Author: 1024创新实验室罗伊
* @Date: 2022-09-12 22:06:45
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*
-->
<template>
<div>
<uni-data-select :localdata="dictValueList" v-model="selectValue" :placeholder="props.placeholder" :clear="true" @change="onChange" />
</div>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue';
import { dictApi } from '/@/api/support/dict-api';
const props = defineProps({
keyCode: String,
modelValue: [String],
placeholder: {
type: String,
default: '请选择',
},
});
// -------------------------- --------------------------
const dictValueList = ref([]);
async function queryDict() {
let res = await dictApi.valueList(props.keyCode);
dictValueList.value = res.data.map((e) => Object.assign({}, { text: e.valueName, value: e.valueCode }));
}
onMounted(queryDict);
// -------------------------- --------------------------
const selectValue = ref(props.modelValue);
watch(
() => props.modelValue,
(value) => {
selectValue.value = value;
}
);
const emit = defineEmits(['update:modelValue', 'change']);
function onChange(selectValue) {
let find = dictValueList.value.filter((e) => e.value === selectValue)[0];
emit('update:modelValue', find.value);
emit('change', find.value, find.text);
}
</script>

View File

@ -0,0 +1,70 @@
<template>
<view class="card">
<view class="card-header">
<slot name="title">
<view class="card-title">
{{ title }}
</view>
</slot>
<slot v-if="isExtra" name="extra" @click="extra">
<view class="card-extra">
查看更多>
</view>
</slot>
</view>
<view class="card-content">
<slot name="content"></slot>
</view>
</view>
</template>
<script setup>
const props = defineProps({
//
title:{
type:String,
default:''
},
//Extra
isExtra:{
type:Boolean,
default:true
}
})
const emits = defineEmits(['extra'])
const extra = ()=>{
emits('extra')
}
</script>
<style lang="scss">
.card{
width: 700rpx;
margin: 0 auto 20rpx;
border-radius: 12rpx;
overflow: hidden;
.card-header{
height: 76rpx;
background: linear-gradient(180deg,#e8f4ff, #f8fcff);
display: flex;
justify-content: space-between;
padding: 0 30rpx;
align-items: center;
.card-title{
font-size: 32rpx;
font-family: PingFang SC, PingFang SC-Semibold;
font-weight: 600;
text-align: left;
color: #323333;
}
.card-extra{
cursor: pointer;
font-size: 24rpx;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: 400;
text-align: center;
color: #1a9aff;
}
}
}
</style>

View File

@ -0,0 +1,42 @@
<!--
* 枚举 radio
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-08-08 20:32:30
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*
-->
<template>
<radio-group @change="handleChange">
<label v-for="item in $smartEnumPlugin.getValueDescList(props.enumName)" :key="item.value" class="smart-margin-right10">
<radio :value="item.value + ''" :checked="item.value === modelValue">{{ item.desc }}</radio>
</label>
</radio-group>
</template>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
enumName: String,
modelValue: [Number, String],
});
const emit = defineEmits(['update:modelValue', 'change']);
const selectValue = ref(props.modelValue);
watch(
() => props.modelValue,
(newValue) => {
selectValue.value = newValue;
}
);
function handleChange(e) {
emit('update:modelValue', e.detail.value);
emit('change', e.detail.value);
}
</script>

View File

@ -0,0 +1,49 @@
<!---
* 字段 下拉选择框
*
* @Author: 1024创新实验室罗伊
* @Date: 2022-09-12 22:06:45
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*
-->
<template>
<div>
<uni-data-select :localdata="dataList" v-model="selectValue" :clear="true" @change="onChange" />
</div>
</template>
<script setup>
import { inject, onMounted, ref, watch } from 'vue';
const smartEnumPlugin = inject('smartEnumPlugin');
const props = defineProps({
enumName: String,
modelValue: [Number, String],
});
// -------------------------- --------------------------
const dataList = ref([]);
function getEnumData() {
dataList.value = smartEnumPlugin.getValueDescList(props.enumName).map((e) => Object.assign({}, { text: e.desc, value: e.value }));
}
onMounted(getEnumData);
// -------------------------- --------------------------
const selectValue = ref(props.modelValue);
watch(
() => props.modelValue,
(value) => {
selectValue.value = value;
}
);
const emit = defineEmits(['update:modelValue', 'change']);
function onChange(value) {
emit('update:modelValue', value);
emit('change', value, smartEnumPlugin.getDescByValue(props.enumName, value));
}
</script>

View File

@ -0,0 +1,73 @@
<template>
<scroll-view class="scroll-view" scroll-x="true" :show-scrollbar="false">
<view class="item" :class="active === item.value ? 'active' : ''" v-for="item in tabsList" :key="item.value" @click="change(item.value)">
{{ item.label }}
</view>
</scroll-view>
</template>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
modelValue: {
type: Number,
default: 0,
},
position: {
type: String,
default: 'fixed',
},
tabsList: {
type: Array,
default: [],
},
});
const position = ref(props.position);
const active = ref(props.modelValue);
watch(
() => props.modelValue,
(newValue) => {
active.value = newValue;
}
);
const emit = defineEmits(['update:modelValue', 'change']);
const change = (value) => {
active.value = value;
emit('update:modelValue', value);
emit('change', value);
};
</script>
<style lang="scss" scoped>
.scroll-view {
position: v-bind(position);
background-color: #f4f4f4;
z-index: 998;
:deep(::-webkit-scrollbar) {
height: 0 !important;
width: 0 !important;
background: transparent;
}
.item {
padding: 0 24rpx;
height: 72rpx;
font-size: 30rpx;
color: #777;
background: #fff;
display: inline-block;
border-radius: 8rpx;
line-height: 72rpx;
margin: 24rpx 0 24rpx 24rpx;
}
.active {
color: #ffffff;
background: #1a9aff;
}
}
</style>

View File

@ -0,0 +1,26 @@
/*
* 商品
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-03 22:08:10
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const GOODS_STATUS_ENUM = {
APPOINTMENT: {
value: 1,
desc: '预约中',
},
SELL: {
value: 2,
desc: '售卖中',
},
SELL_OUT: {
value: 3,
desc: '售罄',
},
};
export default {
GOODS_STATUS_ENUM,
};

View File

@ -0,0 +1,24 @@
/*
* 企业
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2023-09-03 22:07:27
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const ENTERPRISE_TYPE_ENUM = {
NORMAL: {
value: 1,
desc: '有限企业',
},
FOREIGN: {
value: 2,
desc: '外资企业',
},
};
export default {
ENTERPRISE_TYPE_ENUM,
};

View File

@ -0,0 +1,70 @@
/*
* 通用常量
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 19:57:29
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const PAGE_SIZE = 10;
export const PAGE_SIZE_OPTIONS = ['5', '10', '15', '20', '30', '40', '50', '75', '100', '150', '200', '300', '500'];
//登录页面名字
export const PAGE_PATH_LOGIN = '/login';
//404页面名字
export const PAGE_PATH_404 = '/404';
export const showTableTotal = function (total) {
return `${total}`;
};
export const FLAG_NUMBER_ENUM = {
TRUE: {
value: 1,
desc: '是',
},
FALSE: {
value: 0,
desc: '否',
},
};
export const GENDER_ENUM = {
UNKNOWN: {
value: 0,
desc: '未知',
},
MAN: {
value: 1,
desc: '男',
},
WOMAN: {
value: 2,
desc: '女',
},
};
export const USER_TYPE_ENUM = {
ADMIN_EMPLOYEE: {
value: 1,
desc: '员工',
},
};
export const DATA_TYPE_ENUM = {
NORMAL: {
value: 1,
desc: '普通',
},
ENCRYPT: {
value: 10,
desc: '加密',
},
};

View File

@ -0,0 +1,24 @@
/*
* 所有常量入口
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 19:58:28
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import { FLAG_NUMBER_ENUM, GENDER_ENUM, USER_TYPE_ENUM } from './common-const';
import loginDevice from './system/login-device-const';
import enterpriseConst from './business/oa/enterprise-const';
import goodsConst from './business/erp/goods-const';
import changeLogConst from './support/change-log-const';
export default {
FLAG_NUMBER_ENUM,
GENDER_ENUM,
USER_TYPE_ENUM,
...loginDevice,
...enterpriseConst,
...goodsConst,
...changeLogConst,
};

View File

@ -0,0 +1,19 @@
/*
* key 常量
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 19:58:50
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
/**
* key前缀
*/
const KEY_PREFIX = 'smart_h5_';
/**
* localStorageKey集合
*/
// token
export const USER_TOKEN = `${KEY_PREFIX}token`;

View File

@ -0,0 +1,28 @@
/*
* 正则常量
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 19:59:05
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const regular = {
phone: /^(13|14|15|16|17|18|19)\d{9}$/,
qq: /^[1-9]\d{3,}$/,
linkUrl:
/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/,
// eslint-disable-next-line no-useless-escape
isNumber: /(^[\-1-9][1-9]*(.[1-9]+)?)$/, // 判断是否为数字除了0 外
isLandlineOrPhone: /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/, // 验证 座机 或者手机
account: /^[a-z0-9]{3,16}$/, // 请输入3-16位(小写字母|数字)的账号
mobileAccount: /^[a-z0-9]{6,16}$/, // 请输入6-16位(小写字母|数字)的账号(和移动端保持一致)
accountDesc: '请输入3-16位(小写字母|数字)的账号',
pwd: /^[A-Za-z0-9._]{6,16}$/, // 请输入6-16位(大小写字母|数字|小数点|下划线)的密码
pwdDesc: '请输入6-16位(大小写字母|数字|小数点|下划线)的密码',
delBlankSpace: /\s+/g, // 删除空格
isPdfReg: new RegExp(/\.(pdf|PDF)/),
isElseFileReg: new RegExp(/\.(doc|docx|xls|xlsx|txt|ppt|pptx|pps|ppxs)/),
isIdentityCard: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/, // 验证身份证号
isChinese: /^[\u4e00-\u9fa5]+$/gi, // 验证是否汉字
};

View File

@ -0,0 +1,32 @@
/**
* 系统更新日志 枚举
*
* @Author: 卓大
* @Date: 2022-09-26 14:53:50
* @Copyright 1024创新实验室
*/
/**
* 更新类型:[1:特大版本功能更新;2:功能更新;3:bug修复]
*/
export const CHANGE_LOG_TYPE_ENUM = {
MAJOR_UPDATE: {
value: 1,
desc: '重大更新',
type: 'error',
},
FUNCTION_UPDATE: {
value: 2,
desc: '功能更新',
type: 'primary',
},
BUG_FIX: {
value: 3,
desc: 'Bug修复',
type: 'warning',
},
};
export default {
CHANGE_LOG_TYPE_ENUM,
};

View File

@ -0,0 +1,31 @@
/*
* 登录设备
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 19:56:56
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const LOGIN_DEVICE_ENUM = {
PC: {
value: 1,
desc: '电脑端',
},
ANDROID: {
value: 2,
desc: '安卓',
},
APPLE: {
value: 3,
desc: '苹果',
},
H5: {
value: 3,
desc: 'H5',
},
};
export default {
LOGIN_DEVICE_ENUM,
};

View File

@ -0,0 +1,87 @@
import CryptoJS from 'crypto-js';
import CryptoSM from 'sm-crypto';
function object2string(data) {
if (typeof data === 'Object') {
return JSON.stringify(data);
}
let str = JSON.stringify(data);
if (str.startsWith("'") || str.startsWith('"')) {
str = str.substring(1);
}
if (str.endsWith("'") || str.endsWith('"')) {
str = str.substring(0, str.length - 1);
}
return str;
}
// ----------------------- AES 加密、解密 -----------------------
const AES_KEY = '1024abcd1024abcd1024abcd1024abcd';
const AES = {
encryptData: function (data) {
// AES 加密 并转为 base64
let utf8Data = CryptoJS.enc.Utf8.parse(object2string(data));
const key = CryptoJS.enc.Utf8.parse(AES_KEY);
const encrypted = CryptoJS.AES.encrypt(utf8Data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
},
decryptData: function (data) {
// 第一步Base64 解码
let words = CryptoJS.enc.Base64.parse(data);
// 第二步AES 解密
const key = CryptoJS.enc.Utf8.parse(AES_KEY);
return CryptoJS.AES.decrypt({ ciphertext: words }, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString(CryptoJS.enc.Utf8);
},
};
// ----------------------- 国密SM4算法 加密、解密 -----------------------
const SM4_KEY = '1024abcd1024abcd1024abcd1024abcd';
const SM4 = {
encryptData: function (data) {
// 第一步SM4 加密
let encryptData = CryptoSM.sm4.encrypt(object2string(data), SM4_KEY);
// 第二步: Base64 编码
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(encryptData));
},
decryptData: function (data) {
// 第一步Base64 解码
let words = CryptoJS.enc.Base64.parse(data);
let decode64Str = CryptoJS.enc.Utf8.stringify(words);
// 第二步SM4 解密
return CryptoSM.sm4.decrypt(decode64Str, SM4_KEY);
},
};
// ----------------------- 对外暴露: 加密、解密 -----------------------
// 默认使用SM4算法
const EncryptObject = SM4;
// const EncryptObject = AES;
/**
* 加密
*/
export const encryptData = function (data) {
return !data ? null : EncryptObject.encryptData(data);
};
/**
* 解密
*/
export const decryptData = function (data) {
return !data ? null : EncryptObject.decryptData(data);
};

View File

@ -0,0 +1,96 @@
/*
* ajax请求
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 20:46:03
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import { USER_TOKEN } from '/@/constants/local-storage-key-const';
import { DATA_TYPE_ENUM } from '/@/constants/common-const';
import { decryptData, encryptData } from './encrypt';
import { useUserStore } from '/@/store/modules/system/user';
const baseUrl = import.meta.env.VITE_APP_API_URL;
function getUserToken() {
let token = uni.getStorageSync(USER_TOKEN);
if (token) {
return token;
}
return '';
}
/**
* 通用请求封装
*/
export const request = function (url, method, data) {
return new Promise((resolve, reject) => {
uni.request({
url: baseUrl + url, //拼接请求路径
data: data,
method: method,
header: {
'x-access-token': getUserToken(),
},
success: (response) => {
// 如果是加密数据
if (response.data.dataType === DATA_TYPE_ENUM.ENCRYPT.value) {
response.data.encryptData = response.data.data;
let decryptStr = decryptData(response.data.data);
if (decryptStr) {
response.data.data = JSON.parse(decryptStr);
}
}
const res = response.data;
if (res.code && res.code !== 1) {
// `token` 过期或者账号已在别处登录
if (res.code === 30007 || res.code === 30008 || res.code === 30012) {
uni.showToast({
title: res.msg,
icon: 'none',
});
useUserStore().clearUserLoginInfo();
uni.navigateTo({ url: '/pages/login/login' });
}
uni.showToast({
title: res.msg,
icon: 'none',
});
reject(response);
} else {
resolve(res);
}
},
fail: (error) => {
reject(error);
},
});
});
};
/**
* get请求
*/
export const getRequest = (url) => {
return request(url, 'GET');
};
/**
* post请求
*/
export const postRequest = (url, data) => {
return request(url, 'POST', data);
};
// ================================= 加密 =================================
/**
* 加密请求参数的post请求
*/
export const postEncryptRequest = (url, data) => {
return request(url, 'POST', { encryptData: encryptData(data) });
};

View File

@ -0,0 +1,22 @@
/*
* 错误上报sentry
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2024-01-02 20:49:28
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
export const smartSentry = {
/**
* sentry 主动上报
*/
captureError: (error) => {
if (error.config && error.data && error && error.headers && error.request && error.status) {
return;
}
// Sentry.captureException(error);
console.error(error);
},
};

View File

@ -0,0 +1,30 @@
export const SmartLoading = {
show: function (msg) {
uni.showLoading({ title: msg ? msg : '加载中' });
},
hide: function () {
uni.hideLoading();
},
};
export const SmartToast = {
success: (message) => {
uni.showToast({
title: message,
icon: 'success',
});
},
error: (message) => {
uni.showToast({
title: message,
icon: 'error',
});
},
toast: (message) => {
uni.showToast({
title: message,
icon: 'none',
});
},
};

18
smart-app/src/main.js Normal file
View File

@ -0,0 +1,18 @@
import { createSSRApp } from 'vue';
import App from './App.vue';
import { store } from './store/index';
// 枚举管理
import smartEnumPlugin from '/@/plugins/smart-enums-plugin';
import constantsInfo from '/@/constants/index';
import lodash from 'lodash';
export function createApp() {
const app = createSSRApp(App);
app.use(store);
app.use(smartEnumPlugin, constantsInfo);
app.config.globalProperties.$lodash = lodash;
return {
app,
store,
};
}

View File

@ -0,0 +1,72 @@
{
"name" : "",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"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 */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics": {
"enable": false
},
"vueVersion" : "3"
}

186
smart-app/src/pages.json Normal file
View File

@ -0,0 +1,186 @@
{
"easycom": {
"autoscan": true,
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
{
"path": "pages/home/index",
"style": {
"navigationStyle":"custom"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationBarTextStyle": "white",
"navigationStyle": "custom"
}
},
{
"path" : "pages/mine/mine",
"style" :
{
"navigationBarTitleText" : "我的",
"enablePullDownRefresh" : false,
"navigationStyle": "custom"
}
},
{
"path" : "pages/enterprise/enterprise-list",
"style" :
{
"navigationBarTitleText" : "客户线索",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/enterprise/enterprise-form",
"style" :
{
"navigationBarTitleText" : "添加客户",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/enterprise/enterprise-detail",
"style" :
{
"navigationBarTitleText" : "客户详情",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/notice/notice-index",
"style" :
{
"navigationBarTitleText" : "通知公告",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/notice/notice-detail",
"style" :
{
"navigationBarTitleText" : "通知公告",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/goods/goods-index",
"style" :
{
"navigationBarTitleText" : "商品",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/support/change-log/change-log-list",
"style" :
{
"navigationBarTitleText" : "版本更新",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/list/list",
"style" :
{
"navigationBarTitleText" : "常见列表",
"enablePullDownRefresh" : true,
"navigationStyle": "custom"
}
},
{
"path" : "pages/message/message",
"style" :
{
"navigationBarTitleText" : "消息",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/form/form",
"style" :
{
"navigationBarTitleText" : "提交表单",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/select-people/select-people",
"style" :
{
"navigationBarTitleText" : "选择人员",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/pure-list/pure-list",
"style" :
{
"navigationBarTitleText" : "列表",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
},
{
"path" : "pages/order-detail/order-detail",
"style" :
{
"navigationBarTitleText" : "运单详情",
"enablePullDownRefresh" : false,
"navigationBarBackgroundColor": "#fff"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#858585",
"selectedColor": "#1A9AFF",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/home/index",
"iconPath": "static/images/tabbar/home-icon.png",
"selectedIconPath": "static/images/tabbar/home-icon-h.png",
"text": "首页"
},
{
"pagePath": "pages/list/list",
"iconPath": "static/images/tabbar/list-icon.png",
"selectedIconPath": "static/images/tabbar/list-icon-h.png",
"text": "常见列表"
},
{
"pagePath": "pages/message/message",
"iconPath": "static/images/tabbar/message-icon.png",
"selectedIconPath": "static/images/tabbar/message-icon-h.png",
"text": "消息"
},
{
"pagePath": "pages/mine/mine",
"iconPath": "static/images/tabbar/mine-icon.png",
"selectedIconPath": "static/images/tabbar/mine-icon-h.png",
"text": "我的"
}]
}
}

View File

@ -0,0 +1,293 @@
<template>
<view class="container">
<view>
<smart-tabs :tabsList="tabs" v-model="smartTabIndex" @change="onTabChange" :fixed="true" />
</view>
<view class="smart-detail smart-margin-top60 content" id="detail1">
<view class="smart-detail-card">
<view class="smart-detail-card-title"> 企业基础信息</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 企业名称 </view>
<view class="smart-detail-card-value">
{{ data.enterpriseName }}
</view>
</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 统一社会信用代码 </view>
<view class="smart-detail-card-value">
{{ data.unifiedSocialCreditCode }}
</view>
</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 类型 </view>
<view class="smart-detail-card-value">
{{ $smartEnumPlugin.getDescByValue('ENTERPRISE_TYPE_ENUM', data.type) }}
</view>
</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 企业ID </view>
<view class="smart-detail-card-value">
{{ data.enterpriseId }}
</view>
</view>
</view>
<view class="smart-detail-card" id="detail2">
<view class="smart-detail-card-title"> 图片信息</view>
<view class="smart-detail-card-cell" v-if="data.enterpriseLogo && data.enterpriseLogo.length > 0">
<view class="smart-detail-card-label"> 企业logo </view>
<view class="smart-detail-card-value" @click="preview([data.enterpriseLogo[0].fileUrl])">
<image :src="data.enterpriseLogo[0].fileUrl"></image>
</view>
</view>
<view class="smart-detail-card-cell" v-if="data.businessLicense && data.businessLicense.length > 0">
<view class="smart-detail-card-label"> 营业执照 </view>
<view class="smart-detail-card-value" @click="preview([data.businessLicense[0].fileUrl])">
<image :src="data.businessLicense[0].fileUrl"></image>
</view>
</view>
</view>
<view class="smart-detail-card" id="detail3">
<view class="smart-detail-card-title"> 联系方式</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 联系人 </view>
<view class="smart-detail-card-value">
{{ data.contact }}
</view>
</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 联系人电话 </view>
<view class="smart-detail-card-value">
{{ data.contactPhone }}
</view>
</view>
<view class="smart-detail-card-cell">
<view class="smart-detail-card-label"> 邮箱 </view>
<view class="smart-detail-card-value">
{{ data.email }}
</view>
</view>
</view>
</view>
<view class="btn-group">
<button class="btn" type="warn" @click="onDelete">删除</button>
<button class="btn" type="primary" @click="onChange">修改</button>
</view>
</view>
</template>
<script setup>
import SmartTabs from '/@/components/smart-tabs/index.vue';
import { ref, reactive } from 'vue';
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
import { onShow, onLoad } from '@dcloudio/uni-app';
import { smartSentry } from '/@/lib/smart-sentry';
import { SmartLoading, SmartToast } from '/@/lib/smart-support';
// ----------------------- tab -----------------------
const tabs = ref([
{
label: '基础信息',
value: 1,
},
{
label: '图片信息',
value: 2,
},
{
label: '联系人',
value: 3,
},
]);
const smartTabIndex = ref(1);
function onTabChange(tabIndex) {
console.log(12, tabIndex);
uni.pageScrollTo({
selector: '#detail' + tabIndex,
duration: 300,
success: console.log,
fail: console.log,
});
}
// ----------------------- -----------------------
const data = reactive({
//ID
enterpriseId: '',
//
enterpriseName: '',
//
unifiedSocialCreditCode: '',
//
type: '',
//
contact: '',
//
contactPhone: '',
//
email: '',
//
address: '',
//logo
enterpriseLogo: undefined,
//
businessLicense: undefined,
});
async function getDetail(id) {
try {
SmartLoading.show();
let res = await enterpriseApi.detail(id);
data.enterpriseId = res.data.enterpriseId;
data.enterpriseName = res.data.enterpriseName;
data.unifiedSocialCreditCode = res.data.unifiedSocialCreditCode;
data.type = res.data.type;
data.contact = res.data.contact;
data.contactPhone = res.data.contactPhone;
data.email = res.data.email;
data.address = res.data.address;
data.enterpriseLogo = res.data.enterpriseLogo;
data.businessLicense = res.data.businessLicense;
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
function preview(urls) {
uni.previewImage({
urls: urls,
});
}
onLoad((options) => {
if (options.enterpriseId) {
data.enterpriseId = options.enterpriseId;
getDetail(options.enterpriseId);
}
});
onShow(() => {
getDetail(data.enterpriseId);
});
function onChange() {
uni.navigateTo({ url: '/pages/enterprise/enterprise-form?enterpriseId=' + data.enterpriseId });
}
function onDelete() {
uni.showModal({
title: '提示',
content: '确定要删除吗?',
confirmText: '确定删除',
success: function (res) {
if (res.confirm) {
doDelete();
}
},
});
}
async function doDelete() {
try {
SmartLoading.show();
await enterpriseApi.delete(data.enterpriseId);
SmartToast.success('删除成功');
setTimeout(() => {
uni.redirectTo({ url: '/pages/enterprise/enterprise-list' });
}, 500);
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f4f4f4;
height: 100vh;
overflow-y: scroll;
}
.smart-detail {
.smart-detail-card {
background-color: white;
margin: 0 auto 14px auto;
width: 94%;
border-radius: 16rpx;
box-sizing: border-box;
padding: 16rpx 30rpx;
.smart-detail-card-title {
height: 70rpx;
display: flex;
align-items: center;
font-size: $uni-font-size-lg;
color: #323333;
font-weight: bold;
margin-bottom: 16rpx;
&::before {
content: '';
height: 32rpx;
width: 3px;
border-radius: 4rpx;
margin-right: 10rpx;
background-color: $uni-color-primary;
}
}
.smart-detail-card-cell {
display: flex;
min-height: 80rpx;
padding: 10rpx 0;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
border-top: 1rpx solid #ededed;
.smart-detail-card-label {
color: #666666;
font-size: $uni-font-size-lg;
}
.smart-detail-card-value {
color: black;
font-size: $uni-font-size-lg;
padding: 20rpx 0;
}
}
}
}
.content {
margin-bottom: 120px;
}
.btn-group {
border-top: #eee 1px solid;
height: 80px;
display: flex;
flex-direction: row;
align-items: center;
position: fixed;
bottom: 0;
background-color: white;
width: 100%;
.btn {
margin: 10px;
flex: 1;
}
}
</style>

View File

@ -0,0 +1,184 @@
<template>
<view class="container">
<view class="smart-form">
<uni-forms ref="formRef" :label-width="100" :modelValue="form" label-position="left" :rules="rules">
<view class="smart-form-group">
<view class="smart-form-group-title"> 基本信息 </view>
<view class="smart-form-group-content">
<uni-forms-item class="smart-form-item" label="企业名称:" name="enterpriseName" required>
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.enterpriseName" placeholder="请输入 企业名称" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="统一社会信用代码:" name="unifiedSocialCreditCode" required>
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.unifiedSocialCreditCode" placeholder="请输入 统一社会信用代码" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="企业类型:" name="type" required>
<smart-enum-radio v-model="form.type" enumName="ENTERPRISE_TYPE_ENUM" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="公司地址:" name="address">
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.address" placeholder="请输入 公司地址" />
</uni-forms-item>
</view>
</view>
<view class="smart-form-group">
<view class="smart-form-group-title"> 联系方式 </view>
<view class="smart-form-group-content">
<uni-forms-item class="smart-form-item" label="联系人" name="contact" required>
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.contact" placeholder="请输入 联系人" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="联系人电话" name="contactPhone" required>
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.contactPhone" placeholder="请输入 联系人电话" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="邮箱" name="email">
<uni-easyinput class="uni-mt-5" trim="all" v-model="form.email" placeholder="请输入 邮箱" />
</uni-forms-item>
</view>
</view>
</uni-forms>
<view class="smart-form-submit smart-margin-top20 bottom-button">
<button class="smart-form-submit-btn smart-margin-right20" type="default" @click="cancel">取消</button>
<button class="smart-form-submit-btn" type="warn" @click="reset">重置</button>
<button class="smart-form-submit-btn" type="primary" @click="ok">保存</button>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
import { regular } from '/@/constants/regular-const';
import SmartEnumRadio from '/@/components/smart-enum-radio/index.vue';
import { smartSentry } from '/@/lib/smart-sentry';
import { SmartLoading, SmartToast } from '/@/lib/smart-support';
import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
// --------------------- ---------------------
const defaultFormData = {
enterpriseId: undefined,
enterpriseName: undefined,
unifiedSocialCreditCode: undefined,
type: undefined,
contact: undefined,
contactPhone: undefined,
email: undefined,
address: undefined,
disabledFlag: false,
};
let form = reactive({ ...defaultFormData });
const rules = {
enterpriseName: {
rules: [{ required: true, errorMessage: '请输入企业名称' }],
},
unifiedSocialCreditCode: {
rules: [{ required: true, errorMessage: '请输入 统一社会信用代码' }],
},
contact: {
rules: [{ required: true, errorMessage: '请输入 联系人' }],
},
contactPhone: {
rules: [
{ required: true, errorMessage: '请输入联系人电话' },
{ pattern: regular.phone, errorMessage: '电话格式错误' },
],
},
type: {
rules: [{ required: true, errorMessage: '请选择 类型' }],
},
};
// --------------------- ---------------------
onLoad((options) => {
if (options.enterpriseId) {
form.enterpriseId = options.enterpriseId;
getDetail(options.enterpriseId);
}
});
onReady(() => {
if (form.enterpriseId) {
uni.setNavigationBarTitle({
title: '修改客户',
});
}
});
async function getDetail(id) {
try {
SmartLoading.show();
let res = await enterpriseApi.detail(id);
form.enterpriseId = res.data.enterpriseId;
form.enterpriseName = res.data.enterpriseName;
form.unifiedSocialCreditCode = res.data.unifiedSocialCreditCode;
form.type = res.data.type;
form.contact = res.data.contact;
form.contactPhone = res.data.contactPhone;
form.email = res.data.email;
form.address = res.data.address;
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
// ----------------------- ------------------------
const formRef = ref();
//
function cancel() {
close();
uni.navigateBack();
}
//
function reset() {
Object.assign(form, defaultFormData);
formRef.value.clearValidate();
}
//
function ok() {
formRef.value
.validate()
.then(async () => {
SmartLoading.show();
try {
if (form.enterpriseId) {
await enterpriseApi.update(form);
} else {
await enterpriseApi.create(form);
}
SmartToast.success(`${form.enterpriseId ? '修改' : '添加'}成功`);
uni.navigateBack();
} catch (error) {
smartSentry.captureError(error);
} finally {
SmartLoading.hide();
}
})
.catch((error) => {
console.log('error', error);
SmartToast.toast('参数验证错误,请仔细填写表单数据!');
});
}
</script>
<style lang="scss" scoped>
.query-form-pop {
height: 800rpx;
overflow-y: scroll;
}
.bottom-button {
position: fixed;
bottom: 0;
}
</style>

View File

@ -0,0 +1,217 @@
<template>
<view class="container">
<mescroll-body @init="mescrollInit" :down="{ auto: false }" @down="onDown" @up="onUp" :up="{ toTop: { src: '' } }">
<!--搜索框-->
<uni-nav-bar :border="false" fixed :leftWidth="0" rightWidth="70px">
<view class="input">
<uni-easyinput
prefixIcon="search"
:clearable="true"
trim="all"
v-model="queryForm.keywords"
placeholder="搜索:企业名称、联系人、联系电话等"
@confirm="search"
@clear="search"
/>
</view>
<template #right>
<view class="nav-right" @click="search">
<uni-icons type="search" size="30"></uni-icons>
<view class="nav-right-name"> 搜索 </view>
</view>
</template>
</uni-nav-bar>
<!-- 列表 -->
<view class="list-container">
<view class="list-item" @click="gotoDetail(item.enterpriseId)" v-for="item in listData" :key="item.enterpriseId">
<view class="list-item-row">
<view class="list-item-label">公司</view>
<view class="list-item-content bolder">{{ item.enterpriseName }}</view>
<view class="list-item-phone" @click="callPhone(item.contactPhone)">
<uni-icons type="phone" size="18" color="#007aff"></uni-icons>
联系
</view>
</view>
<view class="list-item-row">
<view class="list-item-label">营业执照</view>
<view class="list-item-content">{{ item.unifiedSocialCreditCode }}</view>
</view>
<view class="list-item-row">
<view class="list-item-label">联系人</view>
<view class="list-item-content">{{ item.contact }}</view>
</view>
<view class="list-item-row">
<view class="list-item-label">电话</view>
<view class="list-item-content">{{ item.contactPhone }}</view>
</view>
</view>
</view>
</mescroll-body>
<uni-fab ref="fab" :pattern="fabPattern" horizontal="right" @fabClick="gotoAdd" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app';
import useMescroll from '@/uni_modules/uni-mescroll/hooks/useMescroll';
import { smartSentry } from '/@/lib/smart-sentry';
import _ from 'lodash';
// --------------------------- ---------------------------------
const defaultForm = {
keywords: '', //
pageNum: 1,
pageSize: 10,
};
//
const queryForm = reactive({ ...defaultForm });
//
const listData = ref([]);
function buildQueryParam(pageNum) {
queryForm.pageNum = pageNum;
return Object.assign({}, queryForm, { pageNum });
}
async function query(mescroll, isDownFlag, param) {
try {
let res = await enterpriseApi.pageQuery(param);
if (!isDownFlag) {
listData.value = listData.value.concat(res.data.list);
} else {
listData.value = res.data.list;
}
mescroll.endSuccess(res.data.list.length, res.data.pages > res.data.pageNum);
} catch (e) {
smartSentry.captureError(e);
//,
mescroll.endErr();
}
}
const { mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
/**
* 搜索
*/
function search() {
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
/**
* 下拉刷新
*/
function onDown(mescroll) {
queryForm.pageNum = 1;
query(mescroll, true, buildQueryParam(1));
}
/**
* 上拉加载更多
*/
function onUp(mescroll) {
query(mescroll, false, buildQueryParam(mescroll.num));
}
onShow(() => {
search();
});
// --------------------------- ---------------------------------
const fabPattern = reactive({
color: 'blue',
backgroundColor: 'blue',
});
function gotoAdd() {
uni.navigateTo({ url: '/pages/enterprise/enterprise-form' });
}
// --------------------------- ---------------------------------
function callPhone(phone) {
uni.makePhoneCall({
phoneNumber: phone, //
});
}
function gotoDetail(id) {
uni.navigateTo({ url: '/pages/enterprise/enterprise-detail?enterpriseId=' + id });
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f4f4f4;
}
.input {
width: 100%;
height: 60rpx;
background: #f7f8f9;
border-radius: 4px;
margin: 8rpx 0;
display: flex;
align-items: center;
}
.nav-right {
width: 140rpx;
display: flex;
height: 88rpx;
flex-direction: row;
line-height: 88rpx;
.nav-right-name {
margin-left: 5px;
line-height: 88rpx;
font-size: 30rpx;
}
}
.list-container {
padding: 10rpx 20rpx;
margin-top: 10rpx;
.list-item {
background: #ffffff;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
margin-bottom: 20rpx;
padding: 30rpx 40rpx;
.list-item-row {
display: flex;
flex-direction: row;
margin-bottom: 16rpx;
justify-content: flex-start;
.list-item-label {
font-size: 28rpx;
font-weight: 400;
text-align: left;
color: #999999;
}
.bolder {
font-weight: 600 !important;
}
.list-item-content {
font-size: 30rpx;
font-weight: 500;
text-align: left;
color: #323333;
}
.list-item-phone {
color: $uni-color-primary;
margin-left: auto;
}
}
}
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<view class="font-item-box">
<text :class="modelValue==0?'active':''" @click="modelValue=0">标准</text>
<view></view>
<text :class="modelValue==1?'active':''" @click="modelValue=1">大号</text>
<view></view>
<text :class="modelValue==2?'active':''" @click="modelValue=2">小号</text>
</view>
</template>
<script setup>
import { watch } from 'vue';
const emits = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue:{
type:Number,
default:0
}
})
watch(()=>props.modelValue,(newValue,oldValue)=>{
emits('update:modelValue',newValue)
})
</script>
<style lang="scss" scoped>
.font-item-box {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
text {
font-size: 30rpx;
color: #cccccc;
&.active {
color: #1A9AFF;
}
}
view {
width: 4rpx;
height: 16rpx;
background-color: #e6e6e6;
margin: 0 42rpx;
}
}
</style>

View File

@ -0,0 +1,59 @@
<template>
<view class="card-content">
<view @click="modelValue = index" :class="modelValue == index?'active':''"
v-for="(item,index) in list" :key="index">
{{item}}
</view>
</view>
</template>
<script setup>
import { watch } from 'vue';
const emits = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue:{
type:Number,
default:0
},
list:{
type:Array,
default:[]
}
})
watch(()=>props.modelValue,(newValue,oldValue)=>{
emits('update:modelValue',newValue)
})
</script>
<style lang="scss" scoped>
.card-content {
padding: 0 30rpx 24rpx;
display: flex;
flex-wrap: wrap;
view {
box-sizing: border-box;
width: 197rpx;
height: 72rpx;
background: #f7f8f9;
border-radius: 8rpx;
text-align: center;
line-height: 72rpx;
margin-right: 24rpx;
margin-top: 24rpx;
font-size: 30rpx;
color: #323333;
border: 2rpx solid #f7f8f9;
&:nth-child(3n) {
margin-right: 0;
}
}
.active {
background: #eff8ff;
border: 2rpx solid #2291f9;
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<view class="sex-box">
<view class="sex-item" :class="modelValue?'active':''" @click="modelValue=true">
<uni-icons type="circle" v-if="!modelValue" color="#ccc" size="30"></uni-icons>
<uni-icons v-else type="checkbox-filled" color="#1A9AFF" size="30"></uni-icons>
<view>
</view>
</view>
<view class="sex-item" :class="!modelValue?'active':''" @click="modelValue=false">
<uni-icons type="circle" v-if="modelValue" color="#ccc" size="30"></uni-icons>
<uni-icons v-else type="checkbox-filled" color="#1A9AFF" size="30"></uni-icons>
<view>
</view>
</view>
</view>
</template>
<script setup>
import { watch } from 'vue';
const emits = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue:{
type:Boolean,
default:true
}
})
watch(()=>props.modelValue,(newValue,oldValue)=>{
emits('update:modelValue',newValue)
})
</script>
<style lang="scss" scoped>
.sex-box {
width: 100%;
display: flex;
justify-content: flex-end;
.sex-item {
display: flex;
width: 112rpx;
height: 64rpx;
background-color: #f3f3f3;
border: 1rpx solid #ededed;
align-items: center;
margin-left: 40rpx;
justify-content: center;
border-radius: 8rpx;
font-size: 32rpx;
}
.active {
background: #f1f9ff;
border: 1rpx solid #1a9aff;
color: #1A9AFF;
}
}
</style>

View File

@ -0,0 +1,199 @@
<template>
<view class="">
<view class="form-card">
<view class="title"> 常用功能 </view>
<view class="content">
<uni-forms :label-width="100" :modelValue="formData" label-position="left">
<uni-forms-item class="uni-forms-item" label="姓名" name="name">
<input class="input" type="text" v-model="formData.name" placeholder="请输入姓名" />
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="手机号码" name="name">
<input class="input" type="text" v-model="formData.name" placeholder="请输入手机号码" />
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="邮箱地址" name="name">
<input class="input" type="text" v-model="formData.name" placeholder="请输入邮箱地址" />
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="性别" name="name">
<RadioSex v-model="formData.sex"></RadioSex>
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="出生日期" name="name">
<view class="item-box">
<picker ref="datePickerRef" mode="date" @change="bindDateChange">
<input ref="dateInputRef" class="input" type="text" v-model="date" placeholder="点击选择时间" />
</picker>
</view>
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="所在地" name="name">
<input class="input" disabled type="text" v-model="formData.name" placeholder="点击选择所在地" />
</uni-forms-item>
</uni-forms>
</view>
</view>
<view class="form-card">
<view class="title"> 推送用户 </view>
<view class="content">
<uni-forms :label-width="100" :modelValue="formData" label-position="left">
<uni-forms-item class="uni-forms-item" label="选择用户" name="name">
<view class="item-box" @click="openSelectPeople">
<image class="user-select-image" src="/src/static/images/form/add.png" mode=""></image>
</view>
</uni-forms-item>
</uni-forms>
</view>
</view>
<view class="form-card">
<view class="title"> 兴趣爱好 </view>
<Interest v-model="formData.interest" :list="interestList"></Interest>
</view>
<view class="form-card">
<view class="title"> 推送用户 </view>
<view class="content">
<uni-forms :label-width="100" :modelValue="formData" label-position="left">
<uni-forms-item class="uni-forms-item" label="亮度调整" name="name">
<view class="item-box">
<slider style="width: 100%" value="50" activeColor="#2291F9" backgroundColor="#f5f6f8" block-color="#2291F9" block-size="20" />
</view>
</uni-forms-item>
<uni-forms-item class="uni-forms-item" label="字体大小" name="name">
<FontSizeSelece v-model="formData.fontType"></FontSizeSelece>
</uni-forms-item>
</uni-forms>
</view>
</view>
<view class="form-card">
<view class="title"> 自我介绍 </view>
<view class="content">
<uni-forms :modelValue="formData" label-position="left">
<view class="textarea">
<textarea auto-height style="font-size: 30rpx" placeholder="请输入自我介绍" placeholder-class="textarea-placeholder" />
</view>
<view class="example-body">
<uni-file-picker limit="9" title="上传图片">
<image style="width: 100%; height: 100%" src="/static/images/form/add-image.png" mode=""></image>
</uni-file-picker>
</view>
</uni-forms>
</view>
</view>
</view>
</template>
<script setup>
import RadioSex from './components/radio-sex.vue';
import Interest from './components/interest.vue';
import FontSizeSelece from './components/font-size-select.vue';
import { reactive, ref } from 'vue';
const interestList = ['唱歌', '跳舞', 'RAP', '篮球', '音乐', '唱歌', '跳舞', 'RAP', '篮球'];
const formData = reactive({
interest: 4,
fontType: 0,
});
const hobby = ref('');
const date = ref();
const bindDateChange = (e) => {
date.value = e.detail.value;
};
const openSelectPeople = () => {
uni.navigateTo({
url: '/pages/select-people/select-people',
});
};
</script>
<style lang="scss" scoped>
page {
background: #f5f6f8;
}
::v-deep .uni-forms-item__content {
display: flex;
align-items: center;
}
::v-deep .uni-forms-item__label {
font-size: 32rpx;
color: #000000;
padding-top: 28rpx;
}
::v-deep .uni-forms-item {
margin-bottom: 0 !important;
}
::v-deep .uni-slider-thumb {
background: #fff !important;
border: 10rpx solid #1a9aff;
box-sizing: border-box;
}
.uni-forms-item {
height: 100rpx;
border-bottom: 1rpx solid #ededed;
&:last-child {
border: none;
}
}
.form-card {
box-sizing: border-box;
width: 700rpx;
margin: 20rpx auto 0;
background: #fff;
border-radius: 16rpx;
.title {
width: 100%;
height: 84rpx;
background-image: url('/static/images/list/form-list.png');
background-size: 100% 84rpx;
line-height: 84rpx;
text-indent: 30rpx;
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
.content {
padding: 0 30rpx;
}
.input {
font-size: 30rpx;
text-align: right;
width: 100%;
}
}
.item-box {
width: 100%;
display: flex;
justify-content: flex-end;
}
.user-select-image {
width: 40rpx;
height: 40rpx;
}
.textarea {
background: #fcfcfc;
border: 0.5px solid #ededed;
border-radius: 4px;
width: 100%;
height: 320rpx;
margin-top: 24rpx;
padding: 24rpx 30rpx;
box-sizing: border-box;
.textarea-placeholder {
color: #cccccc;
font-size: 30rpx;
}
}
.example-body {
padding-bottom: 24rpx;
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<view class="list-container">
<view class="list-item" @click="gotoDetail(item.goodsId)" v-for="item in list" :key="item.noticeId">
<view class="title"> {{ item.goodsName }} </view>
<view class="author" v-if="item.remark"> 备注{{ item.remark }} </view>
<view class="author" v-if="item.categoryName"> 分类{{ item.categoryName }} </view>
<view class="author"> 创建时间{{ item.createTime }} </view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
marginTop: {
type: String,
default: '0',
},
list: {
type: Array,
default: [],
},
});
function gotoDetail(goodsId) {
uni.navigateTo({ url: '/pages/goods/goods-detail?noticeId=' + goodsId });
}
</script>
<style lang="scss" scoped>
.list-container {
margin-top: v-bind(marginTop);
padding: 20rpx 10rpx;
}
.list-item {
box-sizing: border-box;
margin: 0 30rpx;
padding: 30rpx 0;
border-bottom: #cdcdcd 1px solid;
.title {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
font-size: 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.author {
margin-bottom: 14rpx;
color: #999999;
font-size: 12px;
text-overflow: ellipsis;
}
.publish-time {
font-size: 12px;
color: #999999;
display: flex;
flex-direction: row;
justify-content: space-between;
.un-read {
color: $uni-color-primary;
}
}
}
</style>

View File

@ -0,0 +1,100 @@
<template>
<uni-popup ref="popupRef" background-color="#fff" type="bottom" :is-mask-click="false">
<view class="query-form-pop">
<view class="smart-form">
<uni-forms :label-width="100" :modelValue="form" label-position="left">
<view class="smart-form-group">
<view class="smart-form-group-title"> 产地 </view>
<view class="smart-form-group-content">
<DictSelect keyCode="GODOS_PLACE" v-model="form.place" @change="onPlaceChange" />
</view>
</view>
<view class="smart-form-group">
<view class="smart-form-group-title"> 状态 </view>
<view class="smart-form-group-content">
<SmartEnumSelect enumName="GOODS_STATUS_ENUM" @change="onGoodsStatusChange" v-model="form.goodsStatus" />
</view>
</view>
</uni-forms>
<view class="smart-form-submit smart-margin-top20">
<button class="smart-form-submit-btn smart-margin-right20" type="default" @click="cancel">取消</button>
<button class="smart-form-submit-btn" type="warn" @click="reset">重置</button>
<button class="smart-form-submit-btn" type="primary" @click="ok">确定</button>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { reactive, ref, toRaw } from 'vue';
import DictSelect from '/@/components/dict-select/index.vue';
import SmartEnumSelect from '/@/components/smart-enum-select/index.vue';
const emits = defineEmits(['close']);
defineExpose({ show });
// --------------------- ---------------------
const popupRef = ref();
function show() {
popupRef.value.open();
}
function close() {
popupRef.value.close();
}
// --------------------- ---------------------
function onPlaceChange(value, text) {
form.placeName = text;
}
function onGoodsStatusChange(value, text) {
form.goodsStatusName = text;
}
// --------------------- ---------------------
const defaultFormData = {
//
goodsStatus: undefined,
goodsStatusName: undefined,
//
place: undefined,
placeName: undefined,
};
const form = reactive({ ...defaultFormData });
// ----------------------- ------------------------
//
function cancel() {
close();
emits('close', null);
}
//
function reset() {
Object.assign(form, defaultFormData);
close();
emits('close', toRaw(form));
}
//
function ok() {
close();
emits('close', toRaw(form));
}
</script>
<style lang="scss" scoped>
.query-form-pop {
height: 800rpx;
overflow-y: scroll;
}
</style>

View File

@ -0,0 +1,222 @@
<template>
<view>
<mescroll-body @init="mescrollInit" :down="{ auto: false }" @down="onDown" @up="onUp">
<!--搜索框-->
<uni-nav-bar :border="false" fixed :leftWidth="0" rightWidth="70px">
<view class="input">
<uni-easyinput
prefixIcon="search"
:clearable="true"
trim="all"
v-model="queryForm.searchWord"
placeholder="搜索:商品名称"
@confirm="search"
@clear="search"
/>
</view>
<template #right>
<view class="nav-right" @click="showQueryFormPopUp">
<uni-icons type="settings" size="30"></uni-icons>
<view class="nav-right-name"> 筛选 </view>
</view>
</template>
</uni-nav-bar>
<!--筛选条件提示-->
<uni-notice-bar
@close="onCloseQueryFormTips"
v-if="showQueryFormTipsFlag"
class="query-bar"
background-color="#007aff"
color="white"
show-close
single
:text="queryFormTips"
/>
<!-- 筛选条件表单弹窗 -->
<QueryFormPopUp ref="queryFormPopUpRef" @close="onCloseQueryFormPopUp" />
<!-- 列表 -->
<NoticeList :list="listData" :margin-top="queryFormTipsMarginTop" />
</mescroll-body>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import QueryFormPopUp from './components/goods-query-form-popup.vue';
import { goodsApi } from '/@/api/business/goods/goods-api';
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import useMescroll from '@/uni_modules/uni-mescroll/hooks/useMescroll';
import { smartSentry } from '/@/lib/smart-sentry';
import NoticeList from './components/goods-list.vue';
import _ from 'lodash';
// --------------------------- ---------------------------------
const queryFormPopUpRef = ref();
/**
* 显示 筛选弹窗
*/
function showQueryFormPopUp() {
queryFormPopUpRef.value.show();
}
/**
* 监听 筛选弹窗 关闭
*/
function onCloseQueryFormPopUp(param) {
if (param === null) {
return;
}
Object.assign(queryForm, param);
showOrHideQueryFormTips();
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
// --------------------------- tips ---------------------------------
const queryFormTips = ref(null);
const showQueryFormTipsFlag = ref(false);
const queryFormTipsMarginTop = ref('0px');
/**
* 查询提示
*/
function buildQueryFormTips() {
let tips = null;
if (queryForm.searchWord) {
tips = '搜索:' + queryForm.searchWord;
}
if (queryForm.goodsStatusName) {
tips = tips ? tips + '' : '';
tips = tips + '商品状态:' + queryForm.goodsStatusName;
}
if (queryForm.placeName) {
tips = tips ? tips + '' : '';
tips = tips + '产地:' + queryForm.placeName;
}
return tips;
}
/**
* 显示或者隐藏tips
*/
function showOrHideQueryFormTips() {
let tips = buildQueryFormTips();
queryFormTipsMarginTop.value = _.isEmpty(tips) ? '0px' : '50rpx';
showQueryFormTipsFlag.value = !_.isEmpty(tips);
queryFormTips.value = tips;
}
/**
* 关闭筛选条件 tips清空搜索条件
*/
function onCloseQueryFormTips() {
Object.assign(queryForm, defaultForm);
queryFormTipsMarginTop.value = '0px';
showQueryFormTipsFlag.value = false;
queryFormTips.value = '';
search();
}
// --------------------------- ---------------------------------
const defaultForm = {
searchWord: '',
//
goodsStatus: undefined,
goodsStatusName: undefined,
//
place: undefined,
placeName: undefined,
pageNum: 1,
pageSize: 10,
};
//
const queryForm = reactive({ ...defaultForm });
//
const listData = ref([]);
function buildQueryParam(pageNum) {
queryForm.pageNum = pageNum;
return Object.assign({}, queryForm, { pageNum });
}
async function query(mescroll, isDownFlag, param) {
try {
let res = await goodsApi.queryGoodsList(param);
if (!isDownFlag) {
listData.value = listData.value.concat(res.data.list);
} else {
listData.value = res.data.list;
}
mescroll.endSuccess(res.data.list.length, res.data.pages > res.data.pageNum);
} catch (e) {
smartSentry.captureError(e);
//,
mescroll.endErr();
}
}
const { mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
/**
* 搜索
*/
function search() {
showOrHideQueryFormTips();
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
/**
* 下拉刷新
*/
function onDown(mescroll) {
queryForm.pageNum = 1;
query(mescroll, true, buildQueryParam(1));
}
/**
* 上拉加载更多
*/
function onUp(mescroll) {
query(mescroll, false, buildQueryParam(mescroll.num));
}
</script>
<style lang="scss" scoped>
.input {
width: 100%;
height: 72rpx;
background: #f7f8f9;
border-radius: 4px;
margin: 8rpx 0;
display: flex;
align-items: center;
}
.nav-right {
width: 140px;
display: flex;
height: 88rpx;
flex-direction: row;
line-height: 88rpx;
.nav-right-name {
margin-left: 5px;
line-height: 88rpx;
font-size: 30rpx;
}
}
.query-bar {
position: fixed;
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<view class="banner" v-if="!$lodash.isEmpty(bannerList)">
<swiper class="swiper" circular :indicator-dots="true" :autoplay="true" indicator-active-color="#fff">
<swiper-item v-for="(item, index) in bannerList" :key="index">
<image class="swiper-item" :src="item.image" mode=""></image>
</swiper-item>
</swiper>
</view>
</template>
<script setup>
import { ref } from 'vue';
const bannerList = ref([
{
image: '/static/images/index/banner.png',
},
{
image: '/static/images/index/banner.png',
},
{
image: '/static/images/index/banner.png',
},
{
image: '/static/images/index/banner.png',
},
]);
</script>
<style lang="scss" scoped>
.banner {
border-radius: 16rpx;
overflow: hidden;
width: 700rpx;
height: 300rpx;
margin: 10rpx auto 20rpx;
.swiper {
width: 100%;
.swiper-item {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,135 @@
<template>
<view class="container">
<uni-card title="品质商品" :isFull="true" padding="0px" spacing="0px">
<view class="course">
<scroll-view class="scroll-view" scroll-x="true">
<view class="scroll-view-item" v-for="item in goodsList" :key="item.goodsId">
<div style="display: flex">
<image class="scroll-item-left" src="/static/logo.png" mode=""></image>
<view class="scroll-item-right">
<view class="item-title"> {{ item.categoryName }}-{{ item.goodsName }} </view>
<view class="item-right-bottom">
<view class="item-time"> 产地{{ item.place[0].valueName }}</view>
</view>
<view class="item-right-bottom">
<view class="item-time"> {{ item.remark }}</view>
<view class="item-reserved"> 预约 </view>
</view>
</view>
</div>
</view>
</scroll-view>
</view>
</uni-card>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { smartSentry } from '/@/lib/smart-sentry';
import { onShow } from '@dcloudio/uni-app';
import { goodsApi } from '/@/api/business/goods/goods-api';
const queryForm = {
pageNum: 1,
pageSize: 5,
searchCount: false,
};
const goodsList = ref([]);
async function queryGoodsList() {
try {
const result = await goodsApi.queryGoodsList(queryForm);
goodsList.value = result.data.list;
} catch (err) {
smartSentry.captureError(err);
}
}
onShow(() => {
queryGoodsList();
});
//
function onMore() {
router.push({
path: '/oa/notice/notice-employee-list',
});
}
function toDetail(noticeId) {
router.push({
path: '/oa/notice/notice-employee-detail',
query: { noticeId },
});
}
</script>
<style lang="scss" scoped>
.container {
width: 700rpx;
margin: 0 auto 20rpx;
border-radius: 12rpx;
overflow: hidden;
:deep(.uni-card__header-box) {
font-weight: bold;
}
:deep(.uni-card__content) {
padding: 0 !important;
}
:deep(.uni-card__header) {
background: linear-gradient(180deg, #e8f4ff, #f8fcff);
}
}
.course {
padding: 30rpx 0 30rpx 30rpx;
background-color: #fff;
}
.scroll-view-item {
display: inline-block;
width: 570rpx;
height: 128rpx;
overflow: hidden;
font-size: 36rpx;
border-right: 1rpx solid #ededed;
margin-right: 30rpx;
.scroll-item-left {
width: 128rpx;
height: 128rpx;
margin-right: 20rpx;
}
.scroll-item-right {
.item-title {
white-space: pre-wrap;
font-size: 30rpx;
width: 390rpx;
}
.item-right-bottom {
display: flex;
justify-content: space-between;
.item-time {
font-size: 12px;
font-weight: 400;
color: #777777;
letter-spacing: -0.02px;
}
.item-reserved {
width: 100rpx;
height: 40rpx;
background: #1a9aff;
border-radius: 4px;
box-shadow: 0 5rpx 8rpx 0 rgba(58, 121, 255, 0.2);
color: #fff;
text-align: center;
font-size: 26rpx;
line-height: 40rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,119 @@
<template>
<view class="menu-container">
<uni-grid :column="5" :highlight="true" :showBorder="false">
<!--------------------------------- 第一排--------------------------------->
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="changeHome">
<image class="item-image" src="/@/static/images/index/ic_home_menu1.png"></image>
<view class="item-text"> 首页切换 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/notice/notice-index')">
<image class="item-image" src="/@/static/images/index/ic_home_menu2.png"></image>
<view class="item-text"> 通知公告 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/enterprise/enterprise-list')">
<image class="item-image" src="/@/static/images/index/ic_home_menu3.png"></image>
<view class="item-text"> 客户线索 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/goods/goods-index')">
<image class="item-image" src="/@/static/images/index/ic_home_menu4.png"></image>
<view class="item-text"> 品质商品 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/support/change-log/change-log-list')">
<image class="item-image" src="/@/static/images/index/ic_home_menu5.png"></image>
<view class="item-text"> 版本更新 </view>
</view>
</uni-grid-item>
<!--------------------------------- 第二排--------------------------------->
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/form/form')">
<image class="item-image" src="/@/static/images/index/ic_home_menu6.png"></image>
<view class="item-text"> 表单 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/order-detail/order-detail')">
<image class="item-image" src="/@/static/images/index/ic_home_menu7.png"></image>
<view class="item-text"> 物流快递 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/pure-list/pure-list')">
<image class="item-image" src="/@/static/images/index/ic_home_menu8.png"></image>
<view class="item-text"> 优惠券 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/list/list')">
<image class="item-image" src="/@/static/images/index/ic_home_menu9.png"></image>
<view class="item-text"> 精品课程 </view>
</view>
</uni-grid-item>
<uni-grid-item class="menu-grid">
<view class="menu-item" @click="navigateTo('/pages/change-log/change-log-list')">
<image class="item-image" src="/@/static/images/index/ic_home_menu10.png"></image>
<view class="item-text"> 加密安全 </view>
</view>
</uni-grid-item>
</uni-grid>
</view>
</template>
<script setup>
const emit = defineEmits(['changeHome']);
function changeHome() {
emit('changeHome');
}
function navigateTo(url) {
uni.navigateTo({
url,
});
}
</script>
<style lang="scss" scoped>
.menu-container {
.menu-grid {
&:nth-child(n + 6) {
margin-top: 20rpx;
}
}
//height: 340rpx;
box-sizing: border-box;
border-radius: 16rpx;
width: 700rpx;
margin: 0 auto 20rpx;
display: flex;
justify-content: space-between;
padding: 30rpx 10rpx;
flex-wrap: wrap;
background-color: #fff;
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
.item-image {
width: 80rpx;
height: 80rpx;
margin-bottom: 10rpx;
}
.item-text {
font-size: 26rpx;
color: #353535;
}
}
}
</style>

View File

@ -0,0 +1,90 @@
<template>
<view class="container">
<uni-card title="通知公告" :isFull="true" type="line" padding="0px" spacing="0px">
<template #extra> <view @click="onMore">查看更多</view> </template>
<uni-list>
<uni-list-item :ellipsis="1" v-for="item in data" :rightText="item.publishDate" clickable @click="goto(item.noticeId)" :title="item.title" />
</uni-list>
</uni-card>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { noticeApi } from '/@/api/business/oa/notice-api';
import { smartSentry } from '/@/lib/smart-sentry';
import { onShow } from '@dcloudio/uni-app';
const queryForm = {
pageNum: 1,
pageSize: 5,
searchCount: false,
};
let data = ref([]);
const loading = ref(false);
//
async function queryNoticeList() {
try {
loading.value = true;
const result = await noticeApi.queryEmployeeNotice(queryForm);
data.value = result.data.list;
} catch (err) {
smartSentry.captureError(err);
} finally {
loading.value = false;
}
}
//
function goto(noticeId) {
uni.navigateTo({ url: '/pages/notice/notice-detail?noticeId=' + noticeId });
}
onShow(() => {
queryNoticeList();
});
//
function onMore() {
uni.navigateTo({
url: '/pages/notice/notice-index',
});
}
</script>
<style lang="scss" scoped>
.container {
width: 700rpx;
margin: 0 auto 20rpx;
border-radius: 12rpx;
padding: 0;
overflow: hidden;
:deep(.uni-card__header-box) {
font-weight: bold;
}
:deep(.uni-list--border-bottom) {
background-color: transparent;
}
:deep(.uni-card__content) {
padding: 0 !important;
}
:deep(.uni-card__header) {
border: none;
}
:deep(.uni-list-item__container) {
padding: 16rpx 20rpx;
}
:deep(.uni-card__header) {
background: linear-gradient(180deg, #e8f4ff, #f8fcff);
}
:deep(.uni-card__header-extra) {
font-size: 24rpx;
font-weight: 400;
text-align: center;
color: #1a9aff;
}
}
</style>

View File

@ -0,0 +1,87 @@
<template>
<view class="statistics-view">
<view class="view-top">
<view class="view-top-item-left">
<view class="item-left-top"> 本月销售额 </view>
<view class="item-left-bottom"> ¥32,226.00 </view>
</view>
<view class="view-top-item-right">
<view class="item-right-top"> 本月销售目标 </view>
<view class="item-right-bottom"> ¥50,000.00 </view>
</view>
</view>
<view class="view-bottom">
<view class="view-bottom-item">
<view class="item-bottom-top"> 本月完成率 </view>
<view class="item-bottom-bottom"> 85% </view>
</view>
<view class="view-item">
<view class="item-bottom-top"> 本月新增客户 </view>
<view class="item-bottom-bottom">+1024 </view>
</view>
<view class="view-item">
<view class="item-bottom-top"> 本月累计通话 </view>
<view class="item-bottom-bottom"> 16:00小时 </view>
</view>
</view>
</view>
</template>
<script></script>
<style lang="scss" scoped>
.statistics-view {
width: 700rpx;
height: 300rpx;
margin: 10rpx auto 20rpx;
background: linear-gradient(133deg, #045ff0 0%, #2291f9 55%, #2168ec 100%);
border-radius: 6px;
.view-top {
display: flex;
padding: 36rpx 44rpx;
.view-top-item-left {
margin-right: 100rpx;
.item-left-top {
opacity: 0.6;
font-size: 26rpx;
color: #ffffff;
margin-bottom: 5rpx;
}
.item-left-bottom {
font-size: 52rpx;
font-weight: 700;
color: #ffffff;
}
}
.view-top-item-right {
.item-right-top {
opacity: 0.6;
font-size: 26rpx;
color: #ffffff;
margin-bottom: 20rpx;
}
.item-right-bottom {
font-size: 30rpx;
font-weight: 700;
color: #ffffff;
}
}
}
.view-bottom {
padding: 26rpx 44rpx;
display: flex;
justify-content: space-between;
.item-bottom-top {
opacity: 0.6;
font-size: 24rpx;
font-weight: 400;
color: #ffffff;
}
.item-bottom-bottom {
font-size: 30rpx;
font-weight: 500;
color: #ffffff;
}
}
}
</style>

View File

@ -0,0 +1,72 @@
<template>
<view class="page">
<uni-nav-bar title="首页" :border="false" fixed>
<template #right>
<view class="right">
<view class="">
<image src="/@/static/images/index/ic_scan.png" mode=""></image>
</view>
<view class="">
<image src="/@/static/images/index/ic_search.png" mode=""></image>
</view>
</view>
</template>
</uni-nav-bar>
<!-- 数据表 -->
<Statistics v-if="!showBannerFlag" />
<!-- Banner -->
<Banner v-if="showBannerFlag" />
<!-- 功能菜单 -->
<Menu @changeHome="changeHome" />
<!-- 通知公告 -->
<Notice />
<!-- 商品 -->
<Goods />
</view>
</template>
<script setup>
import Banner from './components/banner.vue';
import Menu from './components/menu.vue';
import Statistics from './components/statistics.vue';
import Notice from './components/notice.vue';
import Goods from './components/goods.vue';
import { ref } from 'vue';
const showBannerFlag = ref(false);
function changeHome() {
showBannerFlag.value = !showBannerFlag.value;
}
</script>
<style lang="scss" scoped>
page {
background-color: #f5f5f5;
}
:deep(.uni-navbar__header-btns) {
width: 150rpx !important;
}
.right {
position: relative;
display: flex;
z-index: 999;
view {
width: 56rpx;
height: 56rpx;
margin-left: 36rpx;
image {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,187 @@
<template>
<view class="list-view">
<view class="item">
<view class="item-top">
<view class="item-top-item">
<view class="item-top-label"> 创建时间 </view>
<view class="item-title"> 2023-08-27 21:33 </view>
<view class="item-state">
<view class="tag" type="warring"> 未付款 </view>
</view>
</view>
<view class="item-top-item">
<view class="item-top-label"> 客户名称 </view>
<view class="item-title"> 六边形工程师 </view>
</view>
<view class="item-top-item">
<view class="item-top-label"> 供应商名称 </view>
<view class="item-title"> 1024数字科技有限公司 </view>
</view>
<view class="item-top-item">
<view class="item-top-label"> 客户经理 </view>
<view class="item-title"> 林jj </view>
</view>
<view class="item-top-item">
<view class="item-top-label"> 生产厂商 </view>
<view class="item-title"> 闫jj </view>
</view>
</view>
<!-- <view class="decollator">
<view class="decollator-left">
</view>
<view class="decollator-center">
</view>
<view class="decollator-right">
</view>
</view> -->
<view class="item-footer">
<view class="item-footer-left"> 订单总价 </view>
<!-- <image src="" mode=""></image> -->
<view class="item-footer-right"> 300000.00 </view>
</view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.decollator {
height: 30rpx;
position: relative;
display: flex;
align-items: center;
.decollator-left {
top: 2rpx;
position: absolute;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: #f5f5f5;
z-index: 10;
left: -30rpx;
}
.decollator-right {
top: 2rpx;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: #f5f5f5;
position: absolute;
z-index: 10;
right: -30rpx;
}
.decollator-center {
width: 100%;
position: absolute;
bottom: 0;
z-index: 1;
border-top: 1rpx dashed #ededed;
}
}
.list-view {
margin: 20rpx 24rpx;
}
.item {
box-sizing: border-box;
width: 700rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding-top: 24rpx;
overflow: hidden;
.item-top {
padding: 0 30rpx;
.item-top-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
margin-bottom: 20rpx;
.item-top-label {
width: 168rpx;
margin-right: 10rpx;
font-size: 28rpx;
color: #777777;
}
.item-title {
font-size: 28rpx;
color: #323333;
font-weight: bold;
}
.item-state {
flex: 1;
display: flex;
justify-content: flex-end;
.tag {
width: 112rpx;
height: 40rpx;
border-radius: 4rpx;
text-align: center;
line-height: 40rpx;
font-size: 24rpx;
&[type='warring'] {
color: #ff6c00;
background: #fff0ed;
}
}
}
}
.item-sub-title {
font-size: 28rpx;
color: #777777;
margin-bottom: 10rpx;
&:last-child {
padding-bottom: 20rpx;
margin-bottom: 0;
}
}
.order-end-time {
height: 40rpx;
background: #ff6c00;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
color: #fff;
text-align: center;
font-size: 24rpx;
line-height: 40rpx;
}
}
.line-border-bottom {
border-bottom: 1rpx solid #ededed;
}
.item-footer {
height: 120rpx;
display: flex;
border-top: 1rpx dashed #ccc;
//background-color: #F7FAFD;
align-items: center;
justify-content: space-between;
margin: 0 30rpx;
.item-footer-left {
font-size: 28rpx;
color: #777;
}
.item-footer-right {
font-size: 34rpx;
color: #444;
font-weight: bold;
}
}
</style>

View File

@ -0,0 +1,86 @@
<template>
<view class="list-view">
<view class="item">
<view class="item-top">
<view class="item-top-info">
<view class="name"> 彭嘉轩 </view>
<view class="mobile"> 13011112338 </view>
</view>
<view class="item-top-phone"> <image src="/static/images/list/phone.png" mode=""></image> 联系Ta </view>
</view>
<view class="item-title"> 最后跟进内容上午跟客户谈了下 </view>
<view class="item-bottom"> 2022-08-20 19:15 最后活跃 </view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.list-view {
margin: 20rpx 24rpx;
}
.item {
box-sizing: border-box;
width: 700rpx;
height: 240rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding: 24rpx 30rpx;
.item-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.item-top-info {
display: flex;
align-items: center;
.name {
font-size: 34rpx;
font-weight: 500;
color: #444444;
margin-right: 10rpx;
}
.mobile {
font-size: 32rpx;
font-weight: bold;
text-align: left;
color: #444444;
}
}
.item-top-phone {
color: #1a9aff;
font-size: 28rpx;
display: flex;
align-items: center;
image {
width: 40rpx;
height: 40rpx;
margin-left: 4rpx;
}
}
}
.item-title {
font-size: 28rpx;
color: #777777;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #ededed;
margin-bottom: 24rpx;
}
.item-bottom {
font-size: 28rpx;
color: #777777;
}
}
</style>

View File

@ -0,0 +1,242 @@
<template>
<view class="list-view">
<view class="item">
<view class="item-header">
<view class="item-top">
<view class="item-top-left"> 2023-08-20 19:15 </view>
<view class="item-top-right">
<view class="tag" type="warring"> 未付款 </view>
</view>
</view>
<view class="line-border-bottom"> </view>
<view class="item-center">
<view class="item-center-left">
<view class="item-top-z"> </view>
<view class="item-center"> </view>
<view class="item-bottom-x"> </view>
</view>
<view class="item-center-address">
<view class="m-b-16">
<view class="item-title"> 装货地址 </view>
<view class="item-address"> 河南省洛阳市洛龙区110号 </view>
</view>
<view class="m-b-16">
<view class="item-title"> 卸货地址 </view>
<view class="item-address"> 河南省洛阳市西工区120号 </view>
</view>
</view>
</view>
<view class="line-border-bottom"> </view>
<view class="item-footer">
<view class="item-footer-left">
<text>586.00</text>
</view>
<view class="item-footer-right">
<view class="camera">
<image src="/static/images/list/camera.png" mode=""></image>
拍照
</view>
<view class="ok">
<image src="/static/images/list/success.png" mode=""></image>
完成
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.list-view {
margin: 20rpx 24rpx;
}
.item {
.item-header {
padding: 0 30rpx;
}
box-sizing: border-box;
width: 700rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding-top: 24rpx;
overflow: hidden;
.item-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.item-top-left {
font-size: 28rpx;
font-weight: 400;
color: #777777;
}
.item-top-right {
.tag {
width: 112rpx;
height: 40rpx;
border-radius: 4rpx;
text-align: center;
line-height: 40rpx;
font-size: 24rpx;
&[type='warring'] {
color: #ff6c00;
background: #fff0ed;
}
&[type='success'] {
color: #1a9aff;
background: #f2f9ff;
}
}
}
}
.item-center {
margin-top: 20rpx;
display: flex;
.item-center-left {
margin-top: 5rpx;
margin-right: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
.item-top-z {
position: relative;
z-index: 10;
width: 34rpx;
height: 34rpx;
background: #1a9aff;
border-radius: 12rpx;
text-align: center;
font-size: 24rpx;
color: #fff;
}
.item-center {
height: 75rpx;
border-left: 1rpx dashed #777777;
margin-top: -5rpx;
border-spacing: 6rpx;
border-width: 2rpx;
}
.item-bottom-x {
width: 34rpx;
height: 34rpx;
background: #ff6c00;
border-radius: 12rpx;
text-align: center;
font-size: 24rpx;
color: #fff;
}
}
.item-center-address {
.m-b-16 {
margin-bottom: 16rpx;
}
.item-title {
font-size: 34rpx;
color: #444444;
font-weight: bold;
margin-bottom: 4rpx;
}
.item-address {
font-size: 28rpx;
color: #777777;
}
}
}
.item-sub-title {
font-size: 28rpx;
color: #777777;
margin-bottom: 10rpx;
&:last-child {
padding-bottom: 20rpx;
margin-bottom: 0;
}
}
.order-end-time {
height: 40rpx;
background: #ff6c00;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
color: #fff;
text-align: center;
font-size: 24rpx;
line-height: 40rpx;
}
}
.item-footer {
padding: 20rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
.item-footer-left {
font-size: 34rpx;
color: #777777;
text {
color: #ff3924;
font-weight: bold;
}
}
.item-footer-right {
display: flex;
align-items: center;
view {
width: 160rpx;
height: 64rpx;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
image {
width: 40rpx;
height: 40rpx;
}
&.ok {
background: #1a9aff;
margin-left: 24rpx;
}
&.camera {
background: linear-gradient(107deg, #57d697 9%, #40c87e 86%);
}
}
}
}
.line-border-bottom {
border-bottom: 1rpx solid #ededed;
}
</style>

View File

@ -0,0 +1,109 @@
<template>
<view class="list-view">
<view class="item">
<view class="item-header">
<view class="item-top">
<view class="item-top-left"> 2023-08-20 19:15 </view>
<view class="item-top-right">
<view class="tag" type="warring"> 未付款 </view>
</view>
</view>
<view class="line-border-bottom"> </view>
<view class="item-title"> 订单标题 </view>
<view class="item-sub-title"> 订单金额¥5852.00 </view>
<view class="item-sub-title"> 客户1024创新实验室 </view>
</view>
<view class="order-end-time"> 剩余 29:35:07 关闭订单 </view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.list-view {
margin: 20rpx 24rpx;
}
.item {
.item-header {
padding: 0 30rpx;
}
box-sizing: border-box;
width: 700rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding-top: 24rpx;
overflow: hidden;
.item-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.item-top-left {
font-size: 28rpx;
font-weight: 400;
color: #777777;
}
.item-top-right {
.tag {
width: 112rpx;
height: 40rpx;
border-radius: 4rpx;
text-align: center;
line-height: 40rpx;
font-size: 24rpx;
&[type='warring'] {
color: #ff6c00;
background: #fff0ed;
}
&[type='success'] {
color: #323333;
background: #f7f8f9;
}
}
}
}
.item-title {
margin-top: 20rpx;
margin-bottom: 12rpx;
font-size: 34rpx;
font-weight: 700;
color: #444444;
}
.item-sub-title {
font-size: 28rpx;
color: #777777;
margin-bottom: 10rpx;
&:last-child {
padding-bottom: 20rpx;
margin-bottom: 0;
}
}
.order-end-time {
height: 40rpx;
background: #ff6c00;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
color: #fff;
text-align: center;
font-size: 24rpx;
line-height: 40rpx;
}
}
.line-border-bottom {
border-bottom: 1rpx solid #ededed;
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<view class="tabs">
<view class="item" @click="value = item.value" v-for="(item,index) in list" :key="index">
{{item.title}}
<view class="tabs-slide" v-if="value === item.value">
</view>
</view>
</view>
</template>
<script setup>
import { ref, watch } from 'vue';
const emits = defineEmits(['update:value'])
const props = defineProps({
value:{
type:Number,
default:0
},
list:{
type:Array,
default:[]
}
})
watch(()=>props.value,(newValue,oldValue)=>{
emits('update:value',newValue)
})
</script>
<style lang="scss" scoped>
.tabs{
box-sizing: border-box;
height: 100rpx;
display: flex;
justify-content: space-between;
width: 100%;
padding: 0 30rpx;
align-items: center;
position: relative;
background-color: #fff;
.item{
position: relative;
height: 100%;
line-height: 100rpx;
}
.tabs-slide{
position: absolute;
transition: 0.3s;
width: 50%;
background: #1a9aff;
border-radius: 4rpx;
height: 8rpx;
bottom: 0;
left: 50%;
transform: translate(-50%);
}
}
</style>

View File

@ -0,0 +1,70 @@
<template>
<view>
<uni-nav-bar :border="false" fixed>
<view class="input">
<icon type="search" size="16"/>
<input placeholder="请输入搜索关键字" placeholder-class="placeolder-input"/>
</view>
<template #right>
<uni-icons type="list" size="30"></uni-icons>
</template>
</uni-nav-bar>
<Tabs v-model:value="active" :list="tabsList"/>
<ListModelOne v-if="active==0"></ListModelOne>
<ListModelTwo v-if="active==1"/>
<ListModelThree v-if="active==2"/>
<ListModelFour v-if="active==3"/>
</view>
</template>
<script setup>
import { ref } from 'vue'
import Tabs from './components/tabs.vue'
import ListModelOne from './components/list-model-one.vue'
import ListModelTwo from './components/list-model-two.vue'
import ListModelThree from './components/list-model-three.vue'
import ListModelFour from './components/list-model-four.vue'
const active = ref(0);
const tabsList = [{
title:'线索列表',
value:0
},{
title:'我的订单',
value:1
},{
title:'我的运单',
value:2
},{
title:'付款单',
value:3
}]
</script>
<style lang="scss" scoped>
page{
background: #f5f6f8;
}
.input{
width: 526rpx;
height: 72rpx;
background: #f7f8f9;
border-radius: 4px;
margin: 8rpx 0;
display: flex;
align-items: center;
icon{
margin-left: 20rpx;
}
input{
margin-left: 8rpx;
font-size: 28rpx;
}
.placeolder-input{
color: #ccc;
}
}
</style>

View File

@ -0,0 +1,57 @@
<template>
<view class="check-box">
<view class="check-item">
<image @click="agree" :src="!agreeFlag ? checkOutImg : checkInImg" />
<span>
我已阅读并同意
<span class="link" @click="openProtocol('user_agreement')">用户协议</span>
<span class="link" @click="openProtocol('privacy_terms')">隐私政策</span>
</span>
</view>
</view>
</template>
<script setup>
import checkOutImg from '/@/static/images/login/check-out.png';
import checkInImg from '/@/static/images/login/check-in.png';
import { ref } from 'vue';
const agreeFlag = ref(false);
function agree() {
agreeFlag.value = !agreeFlag.value;
}
function openProtocol(protocolKey) {
uni.navigateTo({
url: `/pages/protocol/index?key=${protocolKey}`,
});
}
defineExpose({
agreeFlag,
});
</script>
<style lang="scss" scoped>
.check-box {
.check-item {
display: flex;
align-items: center;
font-size: $small-size;
font-weight: 400;
color: #999999;
margin-bottom: 7px;
image {
width: 17px;
height: 17px;
margin-right: 2px;
}
.link {
color: $main-color;
}
}
}
</style>

View File

@ -0,0 +1,139 @@
<template>
<view class="other-way-box">
<view class="title">
<span style="margin: 0 10px"> 第三方账号登录 </span>
</view>
<view class="other-way">
<!-- 手机号登录 -->
<view v-if="phoneLoginFlag" @click="navigateTo('/pages/login/phone-login')" class="item">
<image src="/@/static/images/login/phone-login-icon.png" />
</view>
<!-- 微信登录 -->
<view v-if="wxLoginFlag" @click="toWeChatLogin" class="item">
<image src="/@/static/images/login/wx-login-icon.png" />
</view>
<!-- 苹果账号登录 -->
<view v-if="iosFlag" @click="toAppleLogin" class="item apple">
<image src="/@/static/images/login/ios-login-icon.png" />
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
const emit = defineEmits(['wechatLogin', 'appleLogin']);
const phoneLoginFlag = computed(() => {
let currentPages = getCurrentPages();
let currentPage = currentPages[currentPages.length - 1];
return currentPage.route === 'pages/login/phone-login';
});
const wxLoginFlag = computed(() => {
let currentPages = getCurrentPages();
let currentPage = currentPages[currentPages.length - 1];
return currentPage.route === 'pages/login/login';
});
const iosFlag = computed(() => {
// #ifdef APP-PLUS
let systemInfoSync = uni.getSystemInfoSync();
let platform = systemInfoSync.platform;
return platform === 'ios';
// #endif
return true;
});
function navigateTo(url) {
uni.navigateTo({ url });
}
//
function toWeChatLogin() {
emit('wechatLogin');
}
//
function toAppleLogin() {
//
var appleOauth = null;
plus.oauth.getServices(
(services) => {
for (var i in services) {
var service = services[i];
// id 'apple' iOS13 service
if (service.id == 'apple') {
appleOauth = service;
break;
}
}
appleOauth.logout(
(success) => {
// console.log("退", JSON.stringify(success))
appleOauth.login(
(oauth) => {
// oauth.target.appleInfo
let info = oauth.target.appleInfo || {};
// console.log("", JSON.stringify(info))
emit('appleLogin', info);
},
(err) => {
// error
},
{
// scope: 'email'
scope: 'email',
}
);
},
(err) => {
console.log('退出登录失败');
}
);
},
(err) => {
// services
}
);
}
</script>
<style lang="scss" scoped>
.other-way-box {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.title {
font-size: $small-size;
font-weight: 400;
color: #cccccc;
}
.other-way {
margin-top: 42rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
.item {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: $main-size;
font-weight: 400;
color: #666666;
&.apple {
margin-left: 40px;
}
image {
width: 70rpx;
height: 70rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,300 @@
<template>
<view class="container">
<view class="top-view">
<view class="login"> 登录 </view>
<view class="logo">
<image src="/@/static/images/login/login-logo.png" />
</view>
</view>
<view class="bottom-view">
<view class="input-view smart-margin-top10">
<image src="/@/static/images/login/login-username.png"></image>
<uni-easyinput
class="input"
placeholder="请输入用户名"
:clearable="true"
placeholderStyle="color:#CCCCCC"
border="none"
v-model="loginForm.username"
/>
</view>
<view class="input-view smart-margin-top10">
<image src="/@/static/images/login/login-password.png"></image>
<uni-easyinput
class="input"
placeholder="请输入密码"
:clearable="true"
:password="true"
placeholderStyle="color:#CCCCCC"
border="none"
v-model="loginForm.password"
/>
</view>
<view class="input-view smart-margin-top10">
<image src="/@/static/images/login/login-password.png"></image>
<uni-easyinput
class="input"
placeholder="请输入验证码"
:clearable="true"
:password="false"
placeholderStyle="color:#CCCCCC"
border="none"
v-model="loginForm.captchaCode"
style="width: 50%"
/>
<img class="captcha-img" :src="captchaBase64Image" @click="getCaptcha" />
</view>
<view class="code-login-view smart-margin-top10">
<text class="code-text">验证码登录</text>
<text class="forget-text">忘记密码</text>
</view>
<view @click="login" class="button login-btn smart-margin-top20"> 登录 </view>
<view @click="login" class="button register-btn smart-margin-top20"> 创建账号 </view>
<OtherWayBox class="other-way-box" />
<LoginCheckBox class="login-check-box" ref="loginCheckBoxRef" />
</view>
</view>
</template>
<script setup>
import { nextTick, reactive, ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import OtherWayBox from './components/other-way-box.vue';
import LoginCheckBox from './components/login-check-box.vue';
import { loginApi } from '/@/api/system/login-api';
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
import { encryptData } from '/@/lib/encrypt';
import { useUserStore } from '/@/store/modules/system/user';
import { smartSentry } from '/@/lib/smart-sentry';
const loginForm = reactive({
loginName: 'admin',
password: '',
captchaCode: '',
captchaUuid: '',
loginDevice: LOGIN_DEVICE_ENUM.PC.value,
});
const loginCheckBoxRef = ref();
async function login() {
if (!loginCheckBoxRef.value.agreeFlag) {
uni.showToast({
icon: 'none',
title: '请阅读并同意《用户协议》、《隐私政策》',
});
return;
}
if (!loginForm.username) {
uni.showToast({
icon: 'none',
title: '请输入用户名',
});
return;
}
if (!loginForm.password) {
uni.showToast({
icon: 'none',
title: '请输入密码',
});
return;
}
try {
uni.showLoading('登录中');
//
let encryptPasswordForm = Object.assign({}, loginForm, {
password: encryptData(loginForm.password),
});
const res = await loginApi.login(encryptPasswordForm);
stopRefreshCaptchaInterval();
uni.showToast({ title: '登录成功' });
// pinia
useUserStore().setUserLoginInfo(res.data);
uni.switchTab({ url: '/pages/home/index' });
} catch (e) {
if (e.data && e.data.code !== 0) {
loginForm.captchaCode = '';
getCaptcha();
}
smartSentry.captureError(e);
uni.hideLoading();
}
}
//--------------------- ---------------------------------
const captchaBase64Image = ref('');
async function getCaptcha() {
try {
let captchaResult = await loginApi.getCaptcha();
captchaBase64Image.value = captchaResult.data.captchaBase64Image;
console.log(captchaResult.data.captchaBase64Image, 2);
loginForm.captchaUuid = captchaResult.data.captchaUuid;
beginRefreshCaptchaInterval(captchaResult.data.expireSeconds);
} catch (e) {
console.log(e);
}
}
let refreshCaptchaInterval = null;
function beginRefreshCaptchaInterval(expireSeconds) {
if (refreshCaptchaInterval === null) {
refreshCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
}
}
function stopRefreshCaptchaInterval() {
if (refreshCaptchaInterval != null) {
clearInterval(refreshCaptchaInterval);
refreshCaptchaInterval = null;
}
}
onShow(getCaptcha);
</script>
<style lang="scss" scoped>
.bottom-view {
box-sizing: border-box;
margin-top: -280rpx;
border-radius: 20rpx 20rpx 0 0;
width: 100%;
background-color: white;
padding: 0 60rpx;
.input-view {
display: flex;
flex-direction: row;
align-items: center;
background-color: $page-bg-color;
border-radius: 4px;
height: 100rpx;
.captcha-img {
margin-left: 5px;
height: 100rpx;
}
image {
margin-left: 30rpx;
width: 44rpx;
height: 44rpx;
}
.input {
margin: 0 16rpx;
background-color: $page-bg-color;
}
}
.code-login-view {
margin: 50rpx 0 0;
height: 40rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.code-text {
height: 40rpx;
font-size: $main-size;
font-weight: 400;
text-align: left;
color: $main-font-color;
}
.forget-text {
height: 40rpx;
font-size: $main-size;
font-weight: 400;
text-align: right;
color: $second-font-color;
}
}
}
.button {
flex-shrink: 0;
width: 100%;
height: 90rpx;
border-radius: 4px;
box-shadow: 0px 5px 8px 0px rgba(58, 121, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
font-size: $main-size;
&.disabled {
opacity: 0.4;
}
&.login-btn {
background: $main-color;
color: #ffffff;
}
&.register-btn {
background: white;
color: $main-color;
border: 0.5px solid $main-color;
border-color: rgba(26, 154, 255, 0.3);
}
}
.logo {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
height: 220rpx;
image {
width: 208rpx;
height: 220rpx;
}
}
::v-deep .uni-easyinput__content {
background-color: transparent !important;
}
::v-deep .is-input-border {
border: none;
}
.container {
display: flex;
align-items: center;
flex-direction: column;
min-height: 100vh;
width: 100vw;
.back-icon {
width: 18px;
height: 18px;
}
.top-view {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 720rpx;
background-image: url(/@/static/images/login/login-top-back.png);
.login {
font-weight: bold;
margin-top: 70rpx;
}
.logo {
width: 260rpx;
height: 260rpx;
}
}
}
.other-way-box {
flex-shrink: 0;
margin-top: 82rpx;
}
.login-check-box {
flex-shrink: 0;
margin-top: 69px;
margin-bottom: 63px;
margin-left: 22px;
align-self: flex-start;
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<view>
<view class="message" v-for="(item, index) in 10">
<view class="message-header">
<view class="header-left">
<image src="/src/static/images/message/message.png" mode=""></image>
<view> 系统通知 </view>
</view>
<view class="header-time"> 2023-08-20 20:48 </view>
</view>
<view class="header-content">
<view class="content-title"> 报销-付款已完成 </view>
<view class="content"> 您的费用保修单已完成付款金额300.00请注意查收 </view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.message {
width: 700rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
margin: 24rpx auto 0;
box-sizing: border-box;
padding: 30rpx 30rpx 24rpx;
.message-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.header-left {
align-items: center;
display: flex;
image {
width: 48rpx;
height: 48rpx;
margin-right: 14rpx;
}
font-size: 34rpx;
color: #000000;
}
.header-time {
font-size: 28rpx;
font-weight: 400;
color: #cccccc;
}
}
.header-content {
box-sizing: border-box;
padding: 24rpx;
background-color: #f7f8f9;
width: 100%;
border-radius: 8rpx;
.content-title {
color: #323333;
font-size: 34rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.content {
font-size: 28rpx;
color: #777777;
}
}
}
page {
background-color: #f5f5f5;
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<view class="menu-list">
<uni-list>
<uni-list-item title="消息通知" link showBadge badgeText="6" badgeType="error">
<template #header>
<image class="icon" src="/static/images/mine/mine-message.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="关于我们" link showBadge>
<template #header>
<image class="icon" src="/static/images/mine/mine-about-us.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="版本信息" link rightText="V1.0" showBadge>
<template #header>
<image class="icon" src="/static/images/mine/mine-version-info.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="意见反馈" link rightText="欢迎吐槽" showBadge>
<template #header>
<image class="icon" src="/static/images/mine/mine-feedback.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="隐私条款" link showBadge>
<template #header>
<image class="icon" src="/static/images/mine/user-agreement-icon.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="用户协议" link showBadge>
<template #header>
<image class="icon" src="/static/images/mine/mine-protocol.png" mode=""></image>
</template>
</uni-list-item>
<uni-list-item title="联系客服" showBadge>
<template #header>
<image class="icon" src="/static/images/mine/mine-service.png" mode=""></image>
</template>
<template #footer>
<view style="font-size: 30rpx; color: #1a9aff; line-height: 45rpx"> 400-888-666 </view>
</template>
</uni-list-item>
<uni-list-item title="账号管理" showBadge link>
<template #header>
<image class="icon" src="/static/images/mine/mine-account.png" mode=""></image>
</template>
</uni-list-item>
</uni-list>
</view>
</template>
<script setup></script>
<style scoped lang="scss">
.menu-list {
box-sizing: border-box;
background-color: #fff;
width: 700rpx;
margin: 20rpx auto 0;
border-radius: 6px;
overflow: hidden;
box-shadow: 0 3px 4px 0 rgba(24, 144, 255, 0.06);
padding: 0 30rpx;
.icon {
width: 42rpx;
height: 42rpx;
margin-right: 20rpx;
}
}
</style>

View File

@ -0,0 +1,112 @@
<template>
<!-- 顶部背景 -->
<view class="nav-container">
<view class="title"> 我的 </view>
</view>
<!-- 用户信息 -->
<view class="user-info-box">
<view class="user-icon">
<image
:src="'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4d40b566-1f0a-4f8d-bc97-c513df8775b3%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708226948&t=a9a155669b60f13d6a32c00de2477f22'"
class="user-image"
>
</image>
</view>
<view class="user-info">
<view class="user-name">{{ actualName }}</view>
<view class="user-phone">{{ phone }}</view>
</view>
<view class="vip-flag">
<image src="/@/static/images/mine/no-vip-flag.png" mode=""></image>
</view>
</view>
</template>
<script setup>
import { useUserStore } from '/@/store/modules/system/user';
import { computed } from 'vue';
const actualName = computed(() => {
return useUserStore().actualName;
});
const phone = computed(() => {
return useUserStore().phone;
});
</script>
<style scoped lang="scss">
.nav-container {
flex-shrink: 0;
width: 100%;
height: 312rpx;
background: url('@/static/images/mine/top-background.png') center/100% no-repeat;
position: relative;
.title {
text-align: center;
margin-top: 100rpx;
font-size: 34rpx;
color: #fff;
font-weight: bold;
}
}
.user-info-box {
z-index: 10;
margin: -53px 12px 0;
background: #ffffff;
border-radius: 6px;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
backdrop-filter: blur(5.98px);
padding: 20px 15px;
display: flex;
flex-direction: row;
align-items: center;
.user-icon {
width: 58px;
height: 58px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-radius: 29px;
background-color: white;
.user-image {
width: 54px;
height: 54px;
border-radius: 27px;
}
}
.user-info {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
margin: 5px auto 0 12px;
align-self: flex-start;
.user-name {
height: 25px;
font-size: 18px;
font-weight: 600;
text-align: center;
color: #323333;
}
.user-phone {
margin-top: 4px;
height: 20px;
font-size: 14px;
font-weight: 400;
text-align: left;
color: #777777;
line-height: 20px;
}
}
.vip-flag {
align-self: flex-start;
width: 83px;
height: 29px;
margin: 3px 0 0 auto;
image {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,178 @@
<template>
<view class="user-info-box">
<view class="user-icon">
<image
class="user-image"
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4d40b566-1f0a-4f8d-bc97-c513df8775b3%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1708226948&t=a9a155669b60f13d6a32c00de2477f22"
>
</image>
</view>
<view class="user-info">
<view class="user-name">{{ actualName }}</view>
<view class="user-phone">{{ phone }}</view>
</view>
</view>
<view class="vip-card">
<view class="card-left">
<image class="vip-icon" src="/static/images/mine/vip-icon.png" mode=""></image>
<view class=""> SmartAdmin </view>
</view>
<image class="open-vip" src="/static/images/mine/open-vip.png" mode=""></image>
</view>
<view class="grid-menu">
<uni-grid :column="4" :showBorder="false">
<uni-grid-item v-for="(item, index) in menuList" :index="index" :key="index">
<view class="grid-item-box" style="background-color: #fff">
<image class="image" :src="item.image" mode=""></image>
<text class="text">{{ item.title }}</text>
</view>
</uni-grid-item>
</uni-grid>
</view>
</template>
<script setup>
import { useUserStore } from '/@/store/modules/system/user';
import { computed } from 'vue';
const actualName = computed(() => {
return useUserStore().actualName;
});
const phone = computed(() => {
return useUserStore().phone;
});
const menuList = [
{
title: '地址',
image: '/static/images/mine/mine-menu-address.png',
},
{
title: '优惠券',
image: '/static/images/mine/mine-menu-coupon.png',
},
{
title: '收藏',
image: '/static/images/mine/mine-menu-collect.png',
},
{
title: '余额',
image: '/static/images/mine/mine-menu-balance.png',
},
];
</script>
<style scoped lang="scss">
.user-info-box {
z-index: 10;
padding: 32px 12px 15px;
display: flex;
flex-direction: row;
align-items: center;
.user-icon {
width: 58px;
height: 58px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-radius: 29px;
background-color: white;
.user-image {
width: 54px;
height: 54px;
border-radius: 27px;
}
}
.user-info {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
margin: 5px auto 0 12px;
align-self: flex-start;
.user-name {
height: 25px;
font-size: 18px;
font-weight: 600;
text-align: center;
color: #323333;
}
.user-phone {
margin-top: 4px;
height: 20px;
font-size: 14px;
font-weight: 400;
text-align: left;
color: #777777;
line-height: 20px;
}
}
}
.vip-card {
background-image: url('/@/static/images/mine/vip-bg.png');
height: 80rpx;
background-repeat: no-repeat;
width: 700rpx;
margin: 0 auto;
background-size: 700rpx 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
.card-left {
display: flex;
align-items: center;
.vip-icon {
width: 50rpx;
height: 46rpx;
margin-left: 32rpx;
margin-right: 8rpx;
}
view {
color: #f5cc8f;
font-size: 30rpx;
font-weight: 600;
}
}
.open-vip {
width: 136rpx;
height: 46rpx;
display: flex;
margin-right: 32rpx;
}
}
.grid-menu {
width: 700rpx;
margin: 20rpx auto;
}
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.item-image {
width: 80rpx;
height: 80rpx;
}
}
.image {
width: 84rpx;
height: 84rpx;
}
.text {
font-size: 14px;
margin-top: 5px;
}
.grid-item-box {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 15px 0;
}
</style>

View File

@ -0,0 +1,43 @@
<template>
<view class="container">
<!-- 用户 -->
<!-- <MineUserBlue />-->
<MineUserWhite />
<!---功能菜单--->
<MineMenu />
<!---退出--->
<view class="logout-btn" @click="logout">
<view class="label">退出登录</view>
</view>
</view>
</template>
<script setup>
import MineMenu from './components/mine-menu.vue';
import MineUserBlue from './components/mine-user-blue.vue';
import MineUserWhite from './components/mine-user-white.vue';
const logout = () => {};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
background: #f4f4f4;
display: flex;
flex-direction: column;
}
.logout-btn {
margin: 24px 27px 50px;
height: 44px;
opacity: 0.5;
background: #ffffff;
border-radius: 22px;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
font-size: 15px;
line-height: 44px;
font-weight: 700;
text-align: center;
color: #353535;
}
</style>

View File

@ -0,0 +1,72 @@
<template>
<view class="list-container">
<view class="list-item" @click="gotoDetail(item.noticeId)" v-for="item in list" :key="item.noticeId">
<view class="title"> {{ item.noticeTypeName }} {{ item.title }} </view>
<view class="author" v-if="item.author"> 作者{{ item.author }} </view>
<view class="author" v-if="item.source"> 来源{{ item.source }} </view>
<view class="publish-time">
<view class="time">发布时间{{ item.publishTime }}</view>
<view class="un-read" v-if="!item.viewFlag">未读</view>
<view class="read" v-if="item.viewFlag">已读</view>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
marginTop: {
type: String,
default: '0',
},
list: {
type: Array,
default: [],
},
});
function gotoDetail(noticeId) {
uni.navigateTo({ url: '/pages/notice/notice-detail?noticeId=' + noticeId });
}
</script>
<style lang="scss" scoped>
.list-container {
margin-top: v-bind(marginTop);
padding: 20rpx 10rpx;
}
.list-item {
box-sizing: border-box;
margin: 0 30rpx;
padding: 30rpx 0;
border-bottom: #cdcdcd 1px solid;
.title {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
font-size: 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.author {
margin-bottom: 14rpx;
color: #999999;
font-size: 12px;
text-overflow: ellipsis;
}
.publish-time {
font-size: 12px;
color: #999999;
display: flex;
flex-direction: row;
justify-content: space-between;
.un-read {
color: $uni-color-primary;
}
}
}
</style>

View File

@ -0,0 +1,115 @@
<template>
<uni-popup ref="popupRef" background-color="#fff" type="bottom" :is-mask-click="false">
<view class="query-form-pop">
<view class="smart-form">
<uni-forms :label-width="100" :modelValue="form" label-position="left">
<view class="smart-form-group">
<view class="smart-form-group-title"> 分类 </view>
<view class="smart-form-group-content">
<uni-forms-item class="smart-form-item" label="类型:">
<uni-data-select v-model="form.noticeTypeId" :localdata="noticeTypeList" @change="changeNoticeType" :clear="true" />
</uni-forms-item>
</view>
</view>
<view class="smart-form-group">
<view class="smart-form-group-title"> 发布日期 </view>
<view class="smart-form-group-content">
<uni-forms-item class="smart-form-item" label="开始日期">
<uni-datetime-picker type="date" clear-icon v-model="form.publishTimeBegin" />
</uni-forms-item>
<uni-forms-item class="smart-form-item" label="截止日期">
<uni-datetime-picker type="date" clear-icon v-model="form.publishTimeEnd" />
</uni-forms-item>
</view>
</view>
</uni-forms>
<view class="smart-form-submit smart-margin-top20">
<button class="smart-form-submit-btn smart-margin-right20" type="default" @click="cancel">取消</button>
<button class="smart-form-submit-btn" type="warn" @click="reset">重置</button>
<button class="smart-form-submit-btn" type="primary" @click="ok">确定</button>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { onMounted, reactive, ref, toRaw } from 'vue';
import { noticeApi } from '/@/api/business/oa/notice-api';
import _ from 'lodash';
const emits = defineEmits(['close']);
defineExpose({ show });
// --------------------- ---------------------
const popupRef = ref();
function show() {
popupRef.value.open();
}
function close() {
popupRef.value.close();
}
// --------------------- ---------------------
const defaultFormData = {
//
noticeTypeId: undefined,
noticeTypeName: undefined,
//
publishTimeBegin: undefined,
//
publishTimeEnd: undefined,
};
const form = reactive({ ...defaultFormData });
// --------------------- ---------------------
const noticeTypeList = ref([]);
async function queryNoticeTypeList() {
let res = await noticeApi.getAllNoticeTypeList();
noticeTypeList.value = res.data.map((e) => Object.assign({}, { text: e.noticeTypeName, value: e.noticeTypeId }));
}
onMounted(() => {
queryNoticeTypeList();
});
function changeNoticeType(e) {
form.noticeTypeId = e;
form.noticeTypeName = _.find(noticeTypeList.value, { value: form.noticeTypeId }).text;
}
// ----------------------- ------------------------
//
function cancel() {
close();
emits('close', null);
}
//
function reset() {
Object.assign(form, defaultFormData);
close();
emits('close', toRaw(form));
}
//
function ok() {
close();
emits('close', toRaw(form));
}
</script>
<style lang="scss" scoped>
.query-form-pop {
height: 800rpx;
overflow-y: scroll;
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<view class="container">
<view class="title">
<uni-title type="h1" align="center" :title="noticeDetail.title"></uni-title>
<uni-title
type="h4"
align="center"
color="#999999"
v-if="noticeDetail.documentNumber"
:title="'(' + noticeDetail.documentNumber + ')'"
></uni-title>
<uni-title type="h4" align="center" color="#999999" :title="noticeDetail.subTitle"></uni-title>
</view>
<view class="content">
<rich-text :nodes="noticeDetail.content" />
</view>
</view>
</template>
<script setup>
import { reactive } from 'vue';
import { noticeApi } from '/@/api/business/oa/notice-api';
import { onLoad } from '@dcloudio/uni-app';
import { smartSentry } from '/@/lib/smart-sentry';
const noticeDetail = reactive({
title: '',
subTitle: '',
documentNumber: '',
content: '',
});
async function getNoticeDetail(noticeId) {
try {
uni.showLoading({ title: '加载中' });
let res = await noticeApi.view(noticeId);
noticeDetail.title = res.data.title;
noticeDetail.content = res.data.contentHtml;
noticeDetail.documentNumber = res.data.documentNumber;
let subTitleArray = [];
if (res.data.author) {
subTitleArray.push(res.data.author);
}
if (res.data.publishTime) {
subTitleArray.push(res.data.publishTime);
}
noticeDetail.subTitle = subTitleArray.join(' | ');
} catch (e) {
smartSentry.captureError(e);
} finally {
uni.hideLoading();
}
}
onLoad((option) => {
uni.pageScrollTo({
scrollTop: 0,
});
getNoticeDetail(option.noticeId);
});
</script>
<style lang="scss" scoped>
.container {
height: 100vh;
padding: 20rpx;
.content {
border-top: #cccccc 1px solid;
margin-top: 50rpx;
padding: 50rpx 16rpx 50rpx 16rpx;
line-height: 30px;
color: #333333;
}
}
</style>

View File

@ -0,0 +1,224 @@
<template>
<view>
<mescroll-body @init="mescrollInit" :down="{ auto: false }" @down="onDown" @up="onUp">
<!--搜索框-->
<uni-nav-bar :border="false" fixed :leftWidth="0" rightWidth="70px">
<view class="input">
<uni-easyinput
prefixIcon="search"
:clearable="true"
trim="all"
v-model="queryForm.keywords"
placeholder="搜索:标题、作者、来源等"
@confirm="search"
@clear="search"
/>
</view>
<template #right>
<view class="nav-right" @click="showQueryFormPopUp">
<uni-icons type="settings" size="30"></uni-icons>
<view class="nav-right-name"> 筛选 </view>
</view>
</template>
</uni-nav-bar>
<!--筛选条件提示-->
<uni-notice-bar
@close="onCloseQueryFormTips"
v-if="showQueryFormTipsFlag"
class="query-bar"
background-color="#007aff"
color="white"
show-close
single
:text="queryFormTips"
/>
<!-- 筛选条件表单弹窗 -->
<NoticeQueryFormPopUp ref="noticeQueryFormPopUpRef" @close="onCloseQueryFormPopUp" />
<!-- 列表 -->
<NoticeList :list="noticeListData" :margin-top="queryFormTipsMarginTop" />
</mescroll-body>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import NoticeQueryFormPopUp from './components/notice-query-form-popup.vue';
import { noticeApi } from '/@/api/business/oa/notice-api';
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import useMescroll from '@/uni_modules/uni-mescroll/hooks/useMescroll';
import { smartSentry } from '/@/lib/smart-sentry';
import NoticeList from './components/notice-list.vue';
import _ from 'lodash';
// --------------------------- ---------------------------------
const noticeQueryFormPopUpRef = ref();
/**
* 显示 筛选弹窗
*/
function showQueryFormPopUp() {
noticeQueryFormPopUpRef.value.show();
}
/**
* 监听 筛选弹窗 关闭
*/
function onCloseQueryFormPopUp(param) {
if (param === null) {
return;
}
Object.assign(queryForm, param);
showOrHideQueryFormTips();
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
// --------------------------- tips ---------------------------------
const queryFormTips = ref(null);
const showQueryFormTipsFlag = ref(false);
const queryFormTipsMarginTop = ref('0px');
/**
* 查询提示
*/
function buildQueryFormTips() {
let tips = null;
if (queryForm.keywords) {
tips = '搜索:' + queryForm.keywords;
}
if (queryForm.noticeTypeName) {
tips = tips ? tips + '' : '';
tips = tips + '类型:' + queryForm.noticeTypeName;
}
if (queryForm.publishTimeBegin) {
tips = tips ? tips + '' : '';
tips = tips + '发布开始时间:' + queryForm.publishTimeBegin;
}
if (queryForm.publishTimeEnd) {
tips = tips ? tips + '' : '';
tips = tips + '发布截止时间:' + queryForm.publishTimeEnd;
}
return tips;
}
/**
* 显示或者隐藏tips
*/
function showOrHideQueryFormTips() {
let tips = buildQueryFormTips();
queryFormTipsMarginTop.value = _.isEmpty(tips) ? '0px' : '50rpx';
showQueryFormTipsFlag.value = !_.isEmpty(tips);
queryFormTips.value = tips;
}
/**
* 关闭筛选条件 tips清空搜索条件
*/
function onCloseQueryFormTips() {
Object.assign(queryForm, defaultForm);
queryFormTipsMarginTop.value = '0px';
showQueryFormTipsFlag.value = false;
queryFormTips.value = '';
search();
}
// --------------------------- ---------------------------------
const defaultForm = {
noticeTypeId: undefined, //
noticeTypeName: undefined, //
keywords: '', //
publishTimeBegin: null, //-
publishTimeEnd: null, //-
pageNum: 1,
pageSize: 10,
};
//
const queryForm = reactive({ ...defaultForm });
//
const noticeListData = ref([]);
function buildQueryParam(pageNum) {
queryForm.pageNum = pageNum;
return Object.assign({}, queryForm, { pageNum });
}
async function query(mescroll, isDownFlag, param) {
try {
let res = await noticeApi.queryEmployeeNotice(param);
if (!isDownFlag) {
noticeListData.value = noticeListData.value.concat(res.data.list);
} else {
noticeListData.value = res.data.list;
}
mescroll.endSuccess(res.data.list.length, res.data.pages > res.data.pageNum);
} catch (e) {
smartSentry.captureError(e);
//,
mescroll.endErr();
}
}
const { mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
/**
* 搜索
*/
function search() {
showOrHideQueryFormTips();
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
/**
* 下拉刷新
*/
function onDown(mescroll) {
queryForm.pageNum = 1;
query(mescroll, true, buildQueryParam(1));
}
/**
* 上拉加载更多
*/
function onUp(mescroll) {
query(mescroll, false, buildQueryParam(mescroll.num));
}
</script>
<style lang="scss" scoped>
.input {
width: 100%;
height: 72rpx;
background: #f7f8f9;
border-radius: 4px;
margin: 8rpx 0;
display: flex;
align-items: center;
}
.nav-right {
width: 140px;
display: flex;
height: 88rpx;
flex-direction: row;
line-height: 88rpx;
.nav-right-name {
margin-left: 5px;
line-height: 88rpx;
font-size: 30rpx;
}
}
.query-bar {
position: fixed;
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<view class="view">
<view class="line"> </view>
<view class="view-item">
<view class="itme-top">
<view class="itme-top-icon-text" type="default"> </view>
<view class="item-top-text"> 湖北省武汉市东西湖区东湖区东湖区 </view>
</view>
<view class="item-bottom"> 河南省洛阳市洛龙区119号 </view>
</view>
<view class="view-item">
<view class="itme-top">
<view class="itme-top-icon-text" type="warning"> </view>
<view class="item-top-text"> 广东省东莞 </view>
</view>
<view class="item-bottom"> 河南省洛阳市西工区110</view>
</view>
<view class="view-item">
<view class="itme-top">
<view class="itme-top-icon-text" type="error"> </view>
<view class="item-top-text"> 湖北省武汉市东西湖区东湖区东湖区 </view>
</view>
<view class="item-bottom"> 河南省洛阳市洛龙区110号 </view>
</view>
<view class="view-item">
<view class="itme-top">
<view class="itme-top-icon-text" type="success"> </view>
<view class="item-top-text"> 湖北省武汉市东西湖区东湖区东湖区 </view>
</view>
<view class="item-bottom"> 河南省洛阳市洛龙区119号 </view>
</view>
</view>
</template>
<script setup></script>
<style lang="scss" scoped>
.view {
box-sizing: border-box;
width: 94%;
border-radius: 16rpx;
background-color: #fff;
padding: 30rpx;
margin: 0 auto 20rpx;
position: relative;
.line {
position: absolute;
height: 300rpx;
border-left: 1rpx dashed #444;
z-index: 0;
top: 40rpx;
left: 50rpx;
}
.view-item {
&:last-child {
margin-bottom: 0;
}
position: relative;
z-index: 1;
margin-bottom: 16rpx;
.item-bottom {
font-size: 28rpx;
color: #777777;
margin-left: 58rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.itme-top {
display: flex;
align-items: center;
}
.itme-top-icon-text {
width: 40rpx;
height: 40rpx;
border-radius: 12rpx;
text-align: center;
line-height: 40rpx;
color: #fff;
font-size: 26rpx;
margin-right: 18rpx;
&[type='default'] {
background: #1a9aff;
}
&[type='warning'] {
background: #f3c35b;
}
&[type='error'] {
background: #ff6c00;
}
&[type='success'] {
background: #6ec98a;
}
}
.item-top-text {
font-size: 32rpx;
color: #444;
font-weight: bold;
padding-bottom: 5rpx;
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
</style>

View File

@ -0,0 +1,172 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg">
</view>
<view class="title-text">
运单信息
</view>
</view>
<view class="view-item">
<view class="item-left">
运单号
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
订单号
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
客户订单号
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
箱号
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
铅封号
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
柜型
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
最迟提箱时间
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
货主
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
业务时间
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
结算方式
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
结算类型
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
司机
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
车辆
</view>
<view class="item-right">
TDD202304950
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
List:{
type:Array,
default:[]
}
})
</script>
<style lang="scss" scoped>
.view{
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
}
.view-title{
height: 84rpx;
display: flex;
align-items: center;
.title-left-bg{
height: 28rpx;
width: 6rpx;
background: #1A9AFF;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text{
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
}
.view-item{
display: flex;
height: 100rpx;
justify-content: space-between;
align-items: center;
color: 323333;
border-bottom: 1rpx solid #ededed;
&:last-child{
border: none;
}
.item-left{
font-size: 32rpx;
}
.item-right{
font-size: 30rpx;
}
}
</style>

View File

@ -0,0 +1,165 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg">
</view>
<view class="title-text">
费用明细
</view>
<view class="sub-title">
已收金额/已收金额/费用
</view>
</view>
<view class="view-item">
<view class="item-left">
运费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
过磅费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
压夜费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
超重费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
提箱费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
报关费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
其他费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
保税绕园费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
放空费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
修箱费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
服务费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
List:{
type:Array,
default:[]
}
})
</script>
<style lang="scss" scoped>
.view{
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
}
.view-title{
height: 84rpx;
display: flex;
align-items: center;
.title-left-bg{
height: 28rpx;
width: 6rpx;
background: #1A9AFF;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text{
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
.sub-title{
font-size: 28rpx;
color: #ccc;
flex: 1;
text-align: right;
}
}
.view-item{
display: flex;
height: 100rpx;
justify-content: space-between;
align-items: center;
color: 323333;
border-bottom: 1rpx solid #ededed;
&:last-child{
border: none;
}
.item-left{
font-size: 32rpx;
}
.item-right{
font-size: 30rpx;
}
}
</style>

View File

@ -0,0 +1,12 @@
<template>
<InfoCardModelTwo/>
<InfoCardModelTwo/>
</template>
<script setup>
import InfoCardModelTwo from './info-card-model-two.vue'
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,13 @@
<template>
<AddressCard/>
<InfoCardModelOne/>
</template>
<script setup>
import AddressCard from './address-card.vue'
import InfoCardModelOne from './info-card-model-one.vue'
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,165 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg">
</view>
<view class="title-text">
费用明细
</view>
<view class="sub-title">
已付费用/预付费用/费用
</view>
</view>
<view class="view-item">
<view class="item-left">
运费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
过磅费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
压夜费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
超重费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
提箱费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
报关费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
其他费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
保税绕园费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
放空费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
修箱费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
<view class="view-item">
<view class="item-left">
服务费
</view>
<view class="item-right">
TDD202304950
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
List:{
type:Array,
default:[]
}
})
</script>
<style lang="scss" scoped>
.view{
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
}
.view-title{
height: 84rpx;
display: flex;
align-items: center;
.title-left-bg{
height: 28rpx;
width: 6rpx;
background: #1A9AFF;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text{
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
.sub-title{
font-size: 28rpx;
color: #ccc;
flex: 1;
text-align: right;
}
}
.view-item{
display: flex;
height: 100rpx;
justify-content: space-between;
align-items: center;
color: 323333;
border-bottom: 1rpx solid #ededed;
&:last-child{
border: none;
}
.item-left{
font-size: 32rpx;
}
.item-right{
font-size: 30rpx;
}
}
</style>

View File

@ -0,0 +1,12 @@
<template>
<InfoCardModelThree/>
<InfoCardModelThree/>
</template>
<script setup>
import InfoCardModelThree from './info-card-model-three.vue'
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,131 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg">
</view>
<view class="title-text">
货物信息1
</view>
<view class="sub-title">
</view>
</view>
<view class="view-item">
<view class="item-left">
货物类型
</view>
<view class="item-right">
其他
</view>
</view>
<view class="view-item">
<view class="item-left">
货物名称
</view>
<view class="item-right">
其他
</view>
</view>
<view class="view-item">
<view class="item-left">
货物单位
</view>
<view class="item-right">
</view>
</view>
<view class="view-item">
<view class="item-left">
货物毛重/
</view>
<view class="item-right">
64
</view>
</view>
<view class="view-item">
<view class="item-left">
货物数量
</view>
<view class="item-right">
2
</view>
</view>
<view class="view-item">
<view class="item-left">
备注
</view>
<view class="item-right">
这是备注信息
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
List:{
type:Array,
default:[]
}
})
</script>
<style lang="scss" scoped>
.view{
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
padding-bottom: 24rpx;
}
.view-title{
height: 84rpx;
display: flex;
align-items: center;
margin-bottom: 16rpx;
.title-left-bg{
height: 28rpx;
width: 6rpx;
background: #1A9AFF;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text{
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
.sub-title{
font-size: 28rpx;
color: #ccc;
flex: 1;
text-align: right;
}
}
.view-item{
display: flex;
height: 40rpx;
align-items: center;
margin-bottom: 16rpx;
&:last-child{
margin-bottom: 0;
}
.item-left{
width: 180rpx;
margin-right: 20rpx;
font-size: 28rpx;
color: #777777;
}
.item-right{
font-size: 30rpx;
color: #323333;
font-weight: bold;
font-size: 28rpx;
}
}
</style>

View File

@ -0,0 +1,117 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg">
</view>
<view class="title-text">
凭证/磅单装货
</view>
</view>
<view class="view-item">
<view class="item-left">
时间
</view>
<view class="item-right">
2023-08-08 12:24:05
</view>
</view>
<view class="view-item">
<view class="item-left">
位置
</view>
<view class="item-right">
河南省许昌市襄城县书岗线
</view>
</view>
<view class="view-item">
<view class="item-left">
经度
</view>
<view class="item-right">
33.45767
</view>
</view>
<view class="view-item">
<view class="item-left">
纬度
</view>
<view class="item-right">
113.45585
</view>
</view>
<view class="image-box">
<image src="/static/logo.png" mode=""></image>
<image src="/static/logo.png" mode=""></image>
</view>
</view>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.view{
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
padding-bottom: 24rpx;
margin-bottom: 24rpx;
}
.view-title{
height: 84rpx;
display: flex;
align-items: center;
margin-bottom: 16rpx;
.title-left-bg{
height: 28rpx;
width: 6rpx;
background: #FED453;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text{
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
}
.view-item{
display: flex;
height: 40rpx;
align-items: center;
margin-bottom: 16rpx;
&:last-child{
margin-bottom: 0;
}
.item-left{
width: 90rpx;
margin-right: 20rpx;
font-size: 28rpx;
color: #777777;
}
.item-right{
font-size: 30rpx;
color: #323333;
font-weight: bold;
font-size: 28rpx;
}
}
.image-box{
display: flex;
justify-content: space-between;
image{
width: 308rpx;
height: 172rpx;
border-radius: 8rpx;
}
padding-top: 20rpx;
border-top: 1rpx solid #ededed;
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<view class="view">
<view class="view-title">
<view class="title-left-bg"> </view>
<view class="title-text"> 付款单号1 </view>
<view class="sub-title">
<view class="success"> 已审核 </view>
<view class="warning"> 待支付 </view>
</view>
</view>
<view class="view-item">
<view class="item-left"> 运单号 </view>
<view class="item-right"> TYD2023080979 </view>
</view>
<view class="view-item">
<view class="item-left"> 应付金额 </view>
<view class="item-right"> 500 </view>
</view>
<view class="view-item">
<view class="item-left"> 已付金额 </view>
<view class="item-right"> 200 </view>
</view>
<view class="view-item">
<view class="item-left"> 收款账户 </view>
<view class="item-right"> 王强/623457910384 </view>
</view>
</view>
</template>
<script setup></script>
<style lang="scss" scoped>
.view {
width: 94%;
margin: 0 auto;
background: #fff;
border-radius: 16rpx;
box-sizing: border-box;
padding: 0 30rpx;
padding-bottom: 24rpx;
margin-bottom: 24rpx;
}
.view-title {
height: 84rpx;
display: flex;
align-items: center;
margin-bottom: 16rpx;
.title-left-bg {
height: 28rpx;
width: 6rpx;
background: #1a9aff;
border-radius: 4rpx;
margin-right: 14rpx;
}
.title-text {
font-size: 32rpx;
color: #323333;
font-weight: bold;
}
.sub-title {
flex: 1;
display: flex;
justify-content: flex-end;
view {
height: 42rpx;
width: 112rpx;
text-align: center;
line-height: 42rpx;
font-size: 24rpx;
margin-left: 24rpx;
}
.success {
background: #e5f8e9;
color: #1ce36d;
}
.warning {
background: #fff0ed;
color: #ff6c00;
}
}
}
.view-item {
display: flex;
height: 40rpx;
align-items: center;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.item-left {
width: 180rpx;
margin-right: 20rpx;
font-size: 28rpx;
color: #777777;
}
.item-right {
font-size: 30rpx;
color: #323333;
font-weight: bold;
font-size: 28rpx;
}
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<scroll-view class="scroll-view" scroll-x="true" :show-scrollbar="false">
<view class="item" :class="active == item.value ? 'active' : ''" v-for="item in tabsList" :key="item.value" @click="change(item.value)">
{{ item.lable }}
</view>
</scroll-view>
</template>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
modelValue: {
type: Number,
default: 0,
},
tabsList: {
type: Array,
default: [],
},
});
const active = ref(0);
watch(
() => props.modelValue,
(newValue) => {
active.value = newValue;
}
);
const emit = defineEmits(['update:modelValue']);
const change = (value) => {
active.value = value;
emit('update:modelValue', value);
};
</script>
<style lang="scss" scoped>
.item {
padding: 0 24rpx;
height: 72rpx;
font-size: 30rpx;
color: #777;
background: #fff;
display: inline-block;
border-radius: 8rpx;
line-height: 72rpx;
margin-left: 24rpx;
margin: 24rpx 0 24rpx 24rpx;
}
.active {
color: #ffffff;
background: #1a9aff;
}
.scroll-view ::v-deep ::-webkit-scrollbar {
height: 0 !important;
width: 0 !important;
background: transparent;
}
.smart-form-submit {
border-top: #eee 1px solid;
height: 80px;
display: flex;
flex-direction: row;
align-items: center;
position: absolute;
bottom: 0;
background-color: white;
width: 100%;
.smart-form-submit-btn {
margin: 10px;
height: 2.5;
flex: 1;
}
}
</style>

View File

@ -0,0 +1,52 @@
<template>
<view>
<ScrollTabs v-model="active" :tabsList="tabsList"></ScrollTabs>
<DetailModelBaseInfo v-if="active==0"/>
<DetailModelPath v-if="active==1"/>
<DetailModelDuePay v-if="active==2"/>
<DetailModelReceivable v-if="active==3"/>
<DetailModelFinal v-if="active==4"/>
<DetailModelVoucher v-if="active==5"/>
</view>
</template>
<script setup>
import { ref } from 'vue';
import ScrollTabs from './components/scroll-tabs.vue'
import DetailModelBaseInfo from './components/detail-model-base-info.vue'
import DetailModelPath from './components/detail-model-path.vue'
import DetailModelDuePay from './components/detail-model-due-pay.vue'
import DetailModelReceivable from './components/detail-model-receivable.vue'
import DetailModelFinal from './components/detail-model-final.vue'
import DetailModelVoucher from './components/detail-model-voucher.vue'
const tabsList = [{
lable:'基本路线',
value:0
},{
lable:'路线/货物',
value:1
},{
lable:'应付费用信息',
value:2
},{
lable:'应收费用信息',
value:3
},{
lable:'结算信息',
value:4
},{
lable:'凭证/磅单',
value:5
}]
const active = ref(0)
</script>
<style lang="scss" scoped>
page{
background: #f4f4f4;
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<view class="item" v-for="(item,index) in 4" :key="index" :class="type[index]">
<view class="header">
Plc控制柜
</view>
<view class="footer">
<view class="footer-left">
A区气路总阀
</view>
<view class="footer-state" :class="type[index]">
关闭
</view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: []
}
})
const type = ['info','primary','warning','']
</script>
<style lang="scss" scoped>
.item {
width: 700rpx;
margin: 20rpx auto 0;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding: 26rpx 40rpx 20rpx;
box-sizing: border-box;
border-left: 8rpx solid #4F4D4D;
&.primary{
border-color: #007FF2;
}
&.warning{
border-color: #FF6C00;
}
&.info{
border-color: #CCCCCC;
}
.header {
display: flex;
justify-content: space-between;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #ededed;
margin-bottom: 19rpx;
font-size: 34rpx;
color: #444;
}
.footer {
display: flex;
justify-content: space-between;
font-size: 28rpx;
.footer-left{
color: #777777;
}
.footer-state{
&.primary{
color: #007FF2;
}
&.warning{
color: #FF6C00;
}
&.info{
color: #CCCCCC;
}
color: #4F4D4D;
}
}
}
</style>

View File

@ -0,0 +1,96 @@
<template>
<view class="item" v-for="(item, index) in 2" :key="index">
<view class="header">
<view class="header-left">
<image class="header-left-image" src="/static/images/pure-list/maintain.png" mode=""></image>
<view class="header-left-title"> 报修信息 </view>
</view>
<view class="header-right-id"> 保修单还12876 </view>
</view>
<view class="footer">
<view class="footer-item">
<view class="label"> 设备 </view>
<view class="info"> 灭火控制柜plc </view>
</view>
<view class="footer-item">
<view class="label"> 描述 </view>
<view class="info"> 总设备压力过大导致气压不稳 </view>
</view>
<view class="footer-item">
<view class="label"> 报修人 </view>
<view class="info"> 闫jj </view>
</view>
<view class="footer-item">
<view class="label"> 受理人 </view>
<view class="info"> 王jj </view>
</view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.item {
position: relative;
width: 700rpx;
margin: 20rpx auto 0;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding: 26rpx 40rpx 20rpx;
box-sizing: border-box;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #ededed;
margin-bottom: 16rpx;
.header-left {
display: flex;
align-items: center;
.header-left-image {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.header-left-title {
font-size: 34rpx;
font-weight: bold;
color: #444444;
}
}
.header-right-id {
font-size: 28rpx;
color: #777777;
}
}
.footer {
.footer-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
.label {
width: 112rpx;
font-size: 28rpx;
color: #777777;
}
.info {
font-size: 28rpx;
color: #323333;
font-weight: bold;
}
}
}
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<view class="item">
<view class="item-header">
<view class="header-title">
商业环境快速变化带来的挑战
</view>
<view class="header-right">
共15讲>
</view>
</view>
<view class="item-tags">
<view class="primary">
商务
</view>
<view class="success">
专题
</view>
<view class="warning">
付费
</view>
</view>
<view class="content">
<view class="content-box">
<view class="c-top">
授课老师
</view>
<view class="c-bottom">
王老师
</view>
</view>
<view class="content-box">
<view class="c-top">
开课时间
</view>
<view class="c-bottom">
2023.08.20 20:00
</view>
</view>
</view>
</view>
</template>
<script setup>
defineProps({
list:{
type:Array,
default:[]
}
})
</script>
<style lang="scss" scoped>
.item{
width: 700rpx;
margin: 20rpx auto 0;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24,144,255,0.06);
padding: 26rpx 30rpx 20rpx;
box-sizing: border-box;
.item-header{
display: flex;
justify-content: space-between;
align-items: flex-start;
.header-title{
width: 480rpx;
font-size: 34rpx;
color: #444;
font-weight: 600;
}
.header-right{
margin-top: 4rpx;
font-size: 28rpx;
color: #777777;
}
}
.item-tags{
display: flex;
margin: 10rpx 0;
view{
width: 112rpx;
height: 42rpx;
border-radius: 4rpx;
text-align: center;
line-height: 42rpx;
font-size: 24rpx;
margin-right: 24rpx;
&.primary{
background: #eef7fd;
color: #1A9AFF;
}
&.success{
color: #1CE36D;
background: #e5f8e9;
}
&.warning{
background: #fff0ed;
color: #FF6C00;
}
}
}
.content{
width: 100%;
height: 140rpx;
background: #f7f8f9;
border-radius: 4px;
display: flex;
justify-content: space-around;
align-items: center;
.content-box{
display: flex;
flex-direction: column;
align-items: center;
}
.c-top{
font-size: 24rpx;
color: #777777;
margin-bottom: 4rpx;
}
.c-bottom{
font-size: 30rpx;
color: #444444;
}
}
}
</style>

View File

@ -0,0 +1,109 @@
<template>
<view class="item" v-for="(item, index) in 2" :key="index">
<view v-if="index == 1" class="forbidden">
<image src="/static/images/pure-list/employ.png" mode=""></image>
</view>
<view class="header">
<view class="header-left">
<view class="header-left-title"> 双十一课程优惠券 </view>
<view class="header-left-time"> 有效期至2023.08.28 </view>
</view>
<view class="header-right-price" :class="index == 1 ? 'grayscale' : ''"> <text>10</text> </view>
</view>
<view class="footer">
<view class="footer-left"> 适用于直播课 </view>
<view v-if="index != 1" class="footer-right"> 去使用 </view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.forbidden {
position: absolute;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.5);
left: 0;
top: 0;
image {
position: absolute;
right: 0;
bottom: 0;
width: 184rpx;
height: 160rpx;
}
}
.item {
position: relative;
width: 700rpx;
margin: 20rpx auto 0;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding: 26rpx 40rpx 20rpx;
box-sizing: border-box;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
border-bottom: 1rpx dashed #ededed;
margin-bottom: 16rpx;
.header-left {
.header-left-title {
font-size: 34rpx;
font-weight: 500;
text-align: left;
color: #444444;
margin-bottom: 8rpx;
}
.header-left-time {
font-size: 28rpx;
color: #777;
}
}
.header-right-price {
color: #ff3924;
font-size: 42rpx;
font-weight: bold;
text {
font-size: 72rpx;
}
}
.grayscale {
color: #ccc;
}
}
.footer {
height: 64rpx;
display: flex;
justify-content: space-between;
align-items: center;
.footer-left {
font-size: 28rpx;
color: #777777;
}
.footer-right {
width: 144rpx;
height: 64rpx;
background: linear-gradient(112deg, #f7681d 9%, #f64226 84%);
border-radius: 8rpx;
box-shadow: 0px 5px 8px 0px rgba(236, 79, 40, 0.2);
color: #fff;
font-size: 28rpx;
text-align: center;
line-height: 64rpx;
}
}
}
</style>

View File

@ -0,0 +1,159 @@
<template>
<view class="item" v-for="(item, index) in 2">
<view class="item-header">
<view class="header-title"> 订单号HUMU2268394 </view>
<view class="header-right" :class="index == 1 ? 'pay' : 'nopay'">
{{ index == 1 ? '已支付' : '未支付' }}
</view>
</view>
<view class="address">
<view class="start-address">
<view class="atom start">
<view> </view>
</view>
<view class="start-address-right">
<view class="start-address-text"> 出发地洛阳西工百货楼 </view>
<view class="start-time"> 出发时间2023.08.23 </view>
</view>
</view>
<view class="end-address">
<view class="atom end">
<view> </view>
</view>
<view class="start-address-text"> 目的地洛阳宜阳县 </view>
</view>
</view>
<view class="footer">
<view class="footer-order-time"> 下单时间2023.08.23 </view>
<view class="footer-order-price"> 订单金额<text class="pay" :class="index == 1 ? 'pay' : 'nopay'">¥450.00</text> </view>
</view>
</view>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: [],
},
});
</script>
<style lang="scss" scoped>
.item {
width: 700rpx;
margin: 20rpx auto 0;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
padding: 26rpx 30rpx 20rpx;
box-sizing: border-box;
.item-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
position: relative;
margin-bottom: 26rpx;
.header-title {
width: 480rpx;
font-size: 34rpx;
color: #444;
font-weight: 600;
}
.header-right {
position: absolute;
right: -40rpx;
background-size: 138rpx 60rpx;
width: 138rpx;
height: 60rpx;
font-size: 28rpx;
color: #fff;
line-height: 50rpx;
text-indent: 24rpx;
&.pay {
background-image: url('/static/images/pure-list/blue.png');
}
&.nopay {
background-image: url('/static/images/pure-list/orange.png');
}
}
}
.address {
width: 100%;
background: #f7f8f9;
border-radius: 4px;
padding: 20rpx 24rpx;
box-sizing: border-box;
margin-bottom: 30rpx;
.atom {
width: 30rpx;
height: 30rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10rpx;
margin-top: 6rpx;
view {
width: 14rpx;
height: 14rpx;
border-radius: 50%;
}
&.start {
background: rgba(26, 154, 255, 0.2);
view {
background: rgb(26, 154, 255);
}
}
&.end {
background: rgba(255, 108, 0, 0.2);
view {
background: rgb(255, 108, 0);
}
}
}
.end-address {
display: flex;
align-items: flex-start;
}
.start-address-text {
font-size: 30x;
font-weight: bold;
color: #444444;
margin-bottom: 4rpx;
}
.start-address {
display: flex;
align-items: flex-start;
.start-time {
font-size: 28rpx;
color: #777777;
}
margin-bottom: 20rpx;
}
}
.footer {
display: flex;
justify-content: space-between;
.footer-order-time {
font-size: 28rpx;
color: #777;
}
.footer-order-price {
color: #777;
font-size: 28rpx;
text {
font-weight: bold;
margin-left: 4rpx;
&.pay {
color: #323333;
}
&.nopay {
color: #ff3924;
}
}
}
}
}
</style>

View File

@ -0,0 +1,21 @@
<template>
<ListModelOne></ListModelOne>
<ListModelTwo/>
<ListModelThree/>
<ListModelFour/>
<ListModelFive/>
</template>
<script setup>
import ListModelOne from './components/list-model-one.vue'
import ListModelTwo from './components/list-model-two.vue'
import ListModelThree from './components/list-model-three.vue'
import ListModelFour from './components/list-model-four.vue'
import ListModelFive from './components/list-model-five.vue'
</script>
<style lang="scss" scoped>
page{
background: #f5f6f8;
}
</style>

View File

@ -0,0 +1,143 @@
<template>
<view>
<view class="select-all">
<view class="circle" v-if="false"> </view>
<image v-else src="/src/static/images/select-people/select.png" mode=""></image>
<view class=""> 全选 </view>
</view>
<view class="item" v-for="(item, index) in 5">
<view class="item-btn">
<view class="circle" v-if="false"> </view>
<image v-else src="/src/static/images/select-people/select.png" mode=""></image>
</view>
<view class="item-content">
<view class="item-name"> 卓大 </view>
<view class="item-desc"> 架构师 </view>
</view>
</view>
<view class="h-168"> </view>
<view class="footer">
<view class="footer-content">
<view class="select"> 已选择(2) </view>
<view class="select-item-card">
<view class="card-item" v-for="(item, index) in 3" :key="index"> 卓大{{ index == 2 ? '...' : '' }} </view>
</view>
<view class="submit">
<view class="btn"> 确认 (5/12) </view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
page {
background: #f5f6f8;
}
.select-all {
height: 104rpx;
width: 100%;
background: #fff;
display: flex;
align-items: center;
padding-left: 55rpx;
font-size: 32rpx;
color: #000000;
}
.circle {
width: 44rpx;
height: 44rpx;
border-radius: 50%;
border: 1rpx solid #ccc;
margin-right: 20rpx;
}
image {
width: 44rpx;
height: 44rpx;
margin-right: 20rpx;
}
.item {
box-sizing: border-box;
width: 700rpx;
height: 140rpx;
margin: 16rpx auto 0;
padding: 30rpx 24rpx;
display: flex;
background-color: #fff;
border-radius: 12rpx;
.item-name {
font-size: 32rpx;
font-weight: 600;
color: #444444;
margin-bottom: 8rpx;
}
.item-desc {
font-size: 28rpx;
color: #777777;
}
}
.h-168 {
height: 168rpx;
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
height: 168rpx;
background-color: #fff;
padding: 16rpx 24rpx;
box-sizing: border-box;
.footer-content {
height: 80rpx;
width: 100%;
display: flex;
align-items: center;
.select {
font-size: 28rpx;
color: #444444;
margin-right: 32rpx;
}
.select-item-card {
display: flex;
view {
height: 44rpx;
padding: 0 12rpx;
line-height: 44rpx;
font-size: 22rpx;
color: #1a9aff;
border: 1px solid #2291f9;
border-radius: 8rpx;
margin-left: -12rpx;
position: relative;
background-color: #fff;
}
}
.submit {
flex: 1;
display: flex;
justify-content: flex-end;
view {
height: 80rpx;
width: 232rpx;
background: #1a9aff;
border-radius: 8rpx;
font-size: 30rpx;
line-height: 80rpx;
text-align: center;
color: #fff;
}
}
}
}
</style>

View File

@ -0,0 +1,199 @@
<template>
<view class="container">
<mescroll-body @init="mescrollInit" :down="{ auto: false }" @down="onDown" @up="onUp" :up="{ toTop: { src: '' } }">
<!--搜索框-->
<uni-nav-bar :border="false" fixed :leftWidth="0" rightWidth="70px">
<view class="input">
<uni-easyinput
:clearable="true"
trim="all"
v-model="queryForm.keyword"
placeholder="搜索: 更新内容 等"
@confirm="search"
@clear="search"
/>
</view>
<template #right>
<view class="nav-right" @click="search">
<uni-icons type="search" size="30"></uni-icons>
<view class="nav-right-name"> 搜索 </view>
</view>
</template>
</uni-nav-bar>
<!-- 列表 -->
<view class="list-container">
<view class="list-item" @click="gotoDetail(item.changeLogId)" v-for="item in listData" :key="item.changeLogId">
<view class="list-item-row">
<view class="list-item-content bolder">{{ item.version }}</view>
<uni-tag
:text="$smartEnumPlugin.getDescByValue('CHANGE_LOG_TYPE_ENUM', item.type)"
:type="$smartEnumPlugin.getObjectByValue('CHANGE_LOG_TYPE_ENUM', item.type).type"
/>
</view>
<view class="list-item-row">
<view class="list-item-label">发布日期{{ item.publicDate }} - {{ item.publishAuthor }}</view>
</view>
<view class="list-item-row">
<view class="list-item-label">{{ item.content }}</view>
</view>
</view>
</view>
</mescroll-body>
<uni-fab ref="fab" :pattern="fabPattern" horizontal="right" @fabClick="gotoAdd" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { changeLogApi } from '/@/api/support/change-log-api';
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app';
import useMescroll from '@/uni_modules/uni-mescroll/hooks/useMescroll';
import { smartSentry } from '/@/lib/smart-sentry';
import _ from 'lodash';
// --------------------------- ---------------------------------
const defaultForm = {
keyword: '', //
pageNum: 1,
pageSize: 10,
};
//
const queryForm = reactive({ ...defaultForm });
//
const listData = ref([]);
function buildQueryParam(pageNum) {
queryForm.pageNum = pageNum;
return Object.assign({}, queryForm, { pageNum });
}
async function query(mescroll, isDownFlag, param) {
try {
let res = await changeLogApi.queryPage(param);
if (!isDownFlag) {
listData.value = listData.value.concat(res.data.list);
} else {
listData.value = res.data.list;
}
mescroll.endSuccess(res.data.list.length, res.data.pages > res.data.pageNum);
} catch (e) {
smartSentry.captureError(e);
//,
mescroll.endErr();
}
}
const { mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
/**
* 搜索
*/
function search() {
query(getMescroll(), true, buildQueryParam(1));
uni.pageScrollTo({
scrollTop: 0,
});
}
/**
* 下拉刷新
*/
function onDown(mescroll) {
queryForm.pageNum = 1;
query(mescroll, true, buildQueryParam(1));
}
/**
* 上拉加载更多
*/
function onUp(mescroll) {
query(mescroll, false, buildQueryParam(mescroll.num));
}
onShow(() => {
search();
});
// --------------------------- ---------------------------------
function gotoDetail(id) {
uni.navigateTo({ url: '/pages/enterprise/enterprise-detail?enterpriseId=' + id });
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f4f4f4;
}
.input {
width: 100%;
height: 60rpx;
background: #f7f8f9;
border-radius: 4px;
margin: 8rpx 0;
display: flex;
align-items: center;
}
.nav-right {
width: 140rpx;
display: flex;
height: 88rpx;
flex-direction: row;
line-height: 88rpx;
.nav-right-name {
margin-left: 5px;
line-height: 88rpx;
font-size: 30rpx;
}
}
.list-container {
padding: 10rpx 20rpx;
margin-top: 10rpx;
.list-item {
background: #ffffff;
box-shadow: 0px 3px 4px 0px rgba(24, 144, 255, 0.06);
margin-bottom: 20rpx;
padding: 30rpx 40rpx;
.list-item-row {
display: flex;
flex-direction: row;
margin-bottom: 16rpx;
justify-content: space-between;
.list-item-label {
font-size: 30rpx;
font-weight: 400;
text-align: left;
}
.bolder {
font-weight: 600 !important;
font-size: 34rpx !important;
}
.list-item-content {
font-size: 30rpx;
font-weight: 500;
text-align: left;
}
.list-item-content-container {
font-size: 30rpx;
font-weight: 500;
text-align: left;
color: #323333;
height: 40px;
}
.list-item-phone {
color: $uni-color-primary;
margin-left: auto;
}
}
}
}
</style>

View File

@ -0,0 +1,97 @@
/*
* 枚举插件
* 此插件为 1024创新实验室 自创的插件
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2022-09-06 20:51:03
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import _ from 'lodash';
import { FLAG_NUMBER_ENUM } from '/@/constants/common-const';
export default {
install: (app, smartEnumWrapper) => {
const smartEnumPlugin = {};
/**
* 根据枚举值获取描述
* @param {*} constantName 枚举名
* @param {*} value 枚举值
* @returns
*/
smartEnumPlugin.getDescByValue = function (constantName, value) {
if (!smartEnumWrapper || !Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) {
return '';
}
// boolean类型需要做特殊处理
if (constantName === 'FLAG_NUMBER_ENUM' && !_.isUndefined(value) && typeof value === 'boolean') {
value = value ? FLAG_NUMBER_ENUM.TRUE.value : FLAG_NUMBER_ENUM.FALSE.value;
}
let smartEnum = smartEnumWrapper[constantName];
for (let item in smartEnum) {
if (smartEnum[item].value === value) {
return smartEnum[item].desc;
}
}
return '';
};
/**
* 根据枚举值获取对象
* @param {*} constantName 枚举名
* @param {*} value 枚举值
* @returns
*/
smartEnumPlugin.getObjectByValue = function (constantName, value) {
if (!smartEnumWrapper || !Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) {
return '';
}
let smartEnum = smartEnumWrapper[constantName];
for (let item in smartEnum) {
if (smartEnum[item].value === value) {
return smartEnum[item];
}
}
return null;
};
/**
* 根据枚举名获取对应的描述键值对[{value:desc}]
* @param {*} constantName 枚举名
* @returns
*/
smartEnumPlugin.getValueDescList = function (constantName) {
if (!Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) {
return [];
}
const result = [];
let targetSmartEnum = smartEnumWrapper[constantName];
for (let item in targetSmartEnum) {
result.push(targetSmartEnum[item]);
}
return result;
};
/**
* 根据枚举名获取对应的value描述键值对{value:desc}
* @param {*} constantName 枚举名
* @returns
*/
smartEnumPlugin.getValueDesc = function (constantName) {
if (!Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) {
return {};
}
let smartEnum = smartEnumWrapper[constantName];
let result = {};
for (let item in smartEnum) {
let key = smartEnum[item].value + '';
result[key] = smartEnum[item].desc;
}
return result;
};
app.config.globalProperties.$smartEnumPlugin = smartEnumPlugin;
app.provide('smartEnumPlugin', smartEnumPlugin);
},
};

6
smart-app/src/shime-uni.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export {};
declare module "vue" {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 B

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