新版本

This commit is contained in:
liangzai 2025-03-14 03:40:55 +08:00
parent 22fe77f26a
commit d88388d04b
149 changed files with 6268 additions and 20894 deletions

37
.cursorrules Normal file
View File

@ -0,0 +1,37 @@
// Uniapp Vue 3 best practices
const vue3CompositionApiBestPractices = [
"Use setup() function for component logic",
"Utilize ref and reactive for reactive state",
"Implement computed properties with computed()",
"Use watch and watchEffect for side effects",
"Implement lifecycle hooks with onMounted, onUpdated, etc.",
"Utilize provide/inject for dependency injection",
];
// Folder structure
const folderStructure = `
src/
components/
composables/
views/
static/
ui/
App.vue
main.ts
`;
// Additional instructions
const additionalInstructions = `
1. Follow the uniapp vue3 version
2. Pay attention to the compatibility of mobile APP
3. Implement proper props and emits definitions
4. Utilize Vue 3's Teleport component when needed
5. Use Suspense for async components
6. Implement proper error handling
7. Follow Vue 3 style guide and naming conventions
8. Use Vite for fast development and building
`;

5
.env Normal file
View File

@ -0,0 +1,5 @@
# 基础环境变量配置
VITE_APP_BASE_URL=https://www.quannengcha.com
VITE_APP_SHARE_URL=https://www.tianyuandata.com
# 默认环境配置
VITE_APP_DEBUG=false

5
.env.development Normal file
View File

@ -0,0 +1,5 @@
# 开发环境配置
VITE_APP_BASE_URL=https://www.quannengcha.com
# 是否启用调试模式
VITE_APP_DEBUG=true

5
.env.production Normal file
View File

@ -0,0 +1,5 @@
# 生产环境配置
VITE_APP_BASE_URL=https://www.quannengcha.com
# 关闭调试模式
VITE_APP_DEBUG=false

View File

@ -2,7 +2,7 @@
"version" : "1.0",
"configurations" : [
{
"playground" : "custom",
"playground" : "standard",
"type" : "uni-app:app-ios"
},
{

View File

@ -5,7 +5,6 @@
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},

View File

@ -1,251 +0,0 @@
{
"code": "00",
"data": {
"als_m12_id_max_monnum": "2",
"als_m1_cell_nbank_allnum": "1",
"als_d15_cell_nbank_week_allnum": "0",
"als_d15_id_nbank_allnum": "1",
"als_m12_id_min_monnum": "0",
"als_m3_id_max_monnum": "1",
"als_m12_cell_min_inteday": "14",
"als_m6_cell_nbank_max_inteday": "46",
"als_d15_cell_nbank_selfnum": "0",
"als_d15_cell_nbank_sloan_allnum": "1",
"als_m3_id_nbank_orgnum": "2",
"als_m12_cell_nbank_ca_allnum": "2",
"als_m1_id_nbank_week_orgnum": "0",
"als_m6_id_nbank_orgnum": "2",
"als_m3_cell_min_monnum": "1",
"als_m6_id_avg_monnum": "1.00",
"als_m6_cell_nbank_orgnum": "2",
"DataStrategy": {
"strategy_version": "1.0",
"product_type": "100099",
"strategy_id": "DTA_BR0007512",
"product_name": "预置_借贷意向验证",
"scene": "lend"
},
"als_d15_id_rel_orgnum": "1",
"als_m3_cell_nbank_cf_orgnum": "1",
"als_m12_cell_nbank_sloan_orgnum": "2",
"als_fst_id_nbank_inteday": "264",
"als_m1_id_nbank_allnum": "1",
"als_m6_cell_nbank_max_monnum": "1",
"als_m12_cell_caon_allnum": "2",
"als_m1_cell_nbank_cf_allnum": "1",
"als_m6_cell_nbank_night_allnum": "1",
"als_m12_id_nbank_night_allnum": "1",
"als_m3_cell_caon_orgnum": "1",
"als_m12_id_nbank_avg_monnum": "1.20",
"als_d15_cell_nbank_orgnum": "1",
"als_m12_id_nbank_cf_allnum": "4",
"als_m3_cell_nbank_orgnum": "2",
"als_m12_id_nbank_sloan_allnum": "6",
"als_m3_cell_min_inteday": "31",
"als_m6_cell_nbank_sloan_allnum": "4",
"als_m3_id_nbank_cf_allnum": "2",
"als_m6_cell_nbank_avg_monnum": "1.00",
"als_m12_id_nbank_max_monnum": "2",
"als_m1_cell_nbank_sloan_allnum": "1",
"als_m6_cell_nbank_ca_allnum": "2",
"als_m3_id_min_inteday": "31",
"als_m3_cell_caon_allnum": "1",
"als_m6_id_nbank_cf_orgnum": "1",
"als_m1_cell_nbank_night_orgnum": "0",
"als_m1_id_nbank_cf_orgnum": "1",
"als_m3_id_nbank_cf_orgnum": "1",
"als_d15_cell_nbank_night_orgnum": "0",
"als_m6_cell_nbank_night_orgnum": "1",
"als_m12_id_nbank_night_orgnum": "1",
"als_m3_id_nbank_avg_monnum": "1.00",
"als_m3_id_min_monnum": "1",
"als_lst_cell_nbank_csinteday": "1",
"als_m12_cell_nbank_max_inteday": "128",
"als_m6_cell_max_monnum": "1",
"als_d15_cell_nbank_night_allnum": "0",
"als_m12_cell_min_monnum": "0",
"als_m3_id_nbank_max_monnum": "1",
"als_m3_cell_max_monnum": "1",
"als_m1_id_rel_orgnum": "1",
"als_m1_cell_nbank_cf_orgnum": "1",
"als_m12_id_nbank_orgnum": "2",
"als_m1_cell_nbank_night_allnum": "0",
"als_m3_cell_nbank_allnum": "3",
"als_m3_id_nbank_night_allnum": "1",
"als_d15_cell_rel_orgnum": "1",
"als_d15_cell_nbank_cf_allnum": "1",
"als_m6_cell_nbank_selfnum": "0",
"als_m6_cell_caon_orgnum": "1",
"als_m12_cell_nbank_sloan_allnum": "6",
"als_m3_id_caon_allnum": "1",
"als_m12_cell_nbank_night_orgnum": "1",
"als_m12_id_min_inteday": "14",
"als_m12_id_nbank_sloan_orgnum": "2",
"als_m6_id_nbank_ca_allnum": "2",
"als_d15_id_nbank_orgnum": "1",
"als_m6_cell_nbank_cf_orgnum": "1",
"swift_number": "3034309_20241022220649_604904CBA19",
"als_m6_cell_nbank_tot_mons": "4",
"als_m12_id_tot_mons": "5",
"als_m12_id_avg_monnum": "1.20",
"als_m3_id_nbank_sloan_orgnum": "2",
"als_m3_cell_nbank_max_inteday": "38",
"als_m1_id_nbank_orgnum": "1",
"als_m12_id_nbank_cf_orgnum": "1",
"als_m1_cell_nbank_orgnum": "1",
"als_d15_cell_nbank_allnum": "1",
"als_m6_id_max_monnum": "1",
"als_m12_id_max_inteday": "128",
"als_m3_cell_nbank_selfnum": "0",
"als_m1_cell_nbank_selfnum": "0",
"als_m12_id_nbank_ca_allnum": "2",
"als_m6_id_nbank_night_allnum": "1",
"als_m3_id_nbank_max_inteday": "38",
"als_d15_id_nbank_selfnum": "0",
"als_m6_id_nbank_avg_monnum": "1.00",
"als_m12_cell_nbank_max_monnum": "2",
"als_m6_cell_min_monnum": "0",
"als_d15_cell_rel_allnum": "1",
"als_m6_cell_nbank_cf_allnum": "2",
"als_m12_id_nbank_selfnum": "0",
"als_m6_id_nbank_sloan_orgnum": "2",
"als_m1_cell_rel_allnum": "1",
"als_m12_id_nbank_max_inteday": "128",
"als_m6_cell_max_inteday": "46",
"als_m6_id_caon_allnum": "2",
"als_m6_id_nbank_night_orgnum": "1",
"als_lst_id_nbank_consnum": "1",
"als_m3_cell_nbank_max_monnum": "1",
"als_m6_id_rel_allnum": "2",
"als_m6_id_rel_orgnum": "1",
"als_m6_id_nbank_sloan_allnum": "4",
"als_m1_cell_rel_orgnum": "1",
"als_m6_cell_tot_mons": "4",
"als_m12_cell_nbank_min_inteday": "14",
"als_m12_id_nbank_ca_orgnum": "1",
"als_m6_id_caon_orgnum": "1",
"als_m3_id_max_inteday": "38",
"als_m6_cell_min_inteday": "31",
"als_m3_cell_nbank_sloan_orgnum": "2",
"als_m12_id_caon_orgnum": "1",
"als_m1_id_nbank_night_orgnum": "0",
"als_m6_cell_nbank_week_orgnum": "2",
"als_m3_cell_rel_orgnum": "1",
"als_m6_cell_rel_orgnum": "1",
"als_m3_id_nbank_sloan_allnum": "3",
"als_m12_cell_avg_monnum": "1.20",
"flag_datastrategy": "1",
"als_d15_id_nbank_cf_allnum": "1",
"als_m3_cell_max_inteday": "38",
"als_m12_cell_nbank_cf_allnum": "4",
"flag_applyloanstr": "1",
"als_m6_id_nbank_ca_orgnum": "1",
"als_m3_id_rel_orgnum": "1",
"als_m12_id_nbank_week_orgnum": "2",
"als_m3_cell_nbank_tot_mons": "3",
"als_m6_id_nbank_min_inteday": "31",
"als_m3_id_nbank_ca_orgnum": "1",
"als_m3_id_caon_orgnum": "1",
"als_m12_cell_nbank_week_allnum": "2",
"als_m1_cell_nbank_week_allnum": "0",
"als_m12_id_nbank_week_allnum": "2",
"als_m1_id_nbank_sloan_allnum": "1",
"als_m3_cell_nbank_min_inteday": "31",
"als_m12_id_nbank_allnum": "6",
"als_m1_id_nbank_cf_allnum": "1",
"als_m3_cell_avg_monnum": "1.00",
"als_m6_id_nbank_tot_mons": "4",
"als_lst_cell_nbank_inteday": "7",
"als_m3_id_nbank_ca_allnum": "1",
"als_m6_cell_caon_allnum": "2",
"als_m6_id_max_inteday": "46",
"als_m12_cell_rel_orgnum": "1",
"als_m12_id_nbank_tot_mons": "5",
"als_m12_cell_nbank_min_monnum": "0",
"als_m6_id_tot_mons": "4",
"als_m3_cell_tot_mons": "3",
"als_m3_id_nbank_night_orgnum": "1",
"als_m12_id_nbank_min_inteday": "14",
"als_m12_id_rel_allnum": "4",
"als_m6_cell_nbank_week_allnum": "2",
"als_m3_id_rel_allnum": "2",
"als_m12_cell_nbank_selfnum": "0",
"als_m12_id_caon_allnum": "2",
"als_m3_id_nbank_min_inteday": "31",
"als_m12_cell_tot_mons": "5",
"als_m12_id_rel_orgnum": "1",
"als_m6_cell_nbank_ca_orgnum": "1",
"als_d15_id_nbank_cf_orgnum": "1",
"als_m6_id_nbank_min_monnum": "0",
"als_m6_cell_avg_monnum": "1.00",
"als_m12_cell_nbank_night_allnum": "1",
"als_d15_cell_nbank_cf_orgnum": "1",
"als_m6_id_nbank_week_allnum": "2",
"als_m3_id_nbank_tot_mons": "3",
"als_m3_cell_nbank_night_orgnum": "1",
"als_m6_cell_nbank_sloan_orgnum": "2",
"als_m3_cell_nbank_ca_allnum": "1",
"als_m1_id_nbank_selfnum": "0",
"als_m6_id_nbank_cf_allnum": "2",
"als_m1_id_nbank_sloan_orgnum": "1",
"als_m6_id_nbank_week_orgnum": "2",
"als_m1_id_rel_allnum": "1",
"als_m3_cell_nbank_min_monnum": "1",
"als_m12_cell_max_monnum": "2",
"als_m12_cell_nbank_allnum": "6",
"als_d15_id_nbank_week_orgnum": "0",
"als_m1_id_nbank_night_allnum": "0",
"als_m6_id_min_inteday": "31",
"als_m12_cell_rel_allnum": "4",
"als_m6_id_nbank_max_inteday": "46",
"als_m12_cell_caon_orgnum": "1",
"als_d15_cell_nbank_week_orgnum": "0",
"als_d15_cell_nbank_sloan_orgnum": "1",
"als_m1_cell_nbank_sloan_orgnum": "1",
"als_m3_id_nbank_selfnum": "0",
"als_m1_cell_nbank_week_orgnum": "0",
"als_d15_id_nbank_sloan_allnum": "1",
"als_m3_cell_rel_allnum": "2",
"als_d15_id_nbank_sloan_orgnum": "1",
"als_m6_id_nbank_max_monnum": "1",
"als_m6_cell_nbank_allnum": "4",
"als_m3_cell_nbank_cf_allnum": "2",
"als_m1_id_nbank_week_allnum": "0",
"als_d15_id_rel_allnum": "1",
"als_m12_cell_nbank_tot_mons": "5",
"als_m3_id_tot_mons": "3",
"als_m6_cell_rel_allnum": "2",
"als_m12_cell_nbank_week_orgnum": "2",
"als_lst_id_nbank_inteday": "7",
"als_m6_id_nbank_selfnum": "0",
"als_m6_id_min_monnum": "0",
"code": "00",
"als_m12_cell_nbank_ca_orgnum": "1",
"als_m3_id_nbank_week_orgnum": "1",
"als_d15_id_nbank_week_allnum": "0",
"als_m3_id_nbank_min_monnum": "1",
"als_m3_id_avg_monnum": "1.00",
"als_d15_id_nbank_night_orgnum": "0",
"als_m3_cell_nbank_night_allnum": "1",
"als_fst_cell_nbank_inteday": "264",
"als_m3_id_nbank_week_allnum": "1",
"als_d15_id_nbank_night_allnum": "0",
"als_m12_cell_nbank_orgnum": "2",
"als_m3_cell_nbank_ca_orgnum": "1",
"als_m3_cell_nbank_sloan_allnum": "3",
"als_m12_cell_max_inteday": "128",
"als_m6_cell_nbank_min_inteday": "31",
"als_m12_id_nbank_min_monnum": "0",
"als_lst_id_nbank_csinteday": "1",
"als_lst_cell_nbank_consnum": "1",
"als_m3_cell_nbank_week_orgnum": "1",
"als_m12_cell_nbank_avg_monnum": "1.20",
"als_m3_id_nbank_allnum": "3",
"als_m6_id_nbank_allnum": "4",
"als_m12_cell_nbank_cf_orgnum": "1",
"als_m3_cell_nbank_avg_monnum": "1.00",
"als_m6_cell_nbank_min_monnum": "0",
"als_m3_cell_nbank_week_allnum": "1"
},
"flag_applyloanstr": "1"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
const fs = require('node:fs')
const path = require('node:path')
// 读取文件路径
const filePath = path.join(__dirname, 'jdyx.txt')
// 输出文件路径
const outputFilePath = path.join(__dirname, 'output.json')
// 读取文件内容
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('读取文件失败:', err)
return
}
const records = []
let currentRecord = ''
let capturing = false // 是否正在捕获一条记录
// 按字符处理数据
for (let i = 0; i < data.length; i++) {
const char = data[i]
// 检查是否找到 `als`
if (!capturing && data.slice(i, i + 3) === 'als') {
capturing = true // 开始捕获
currentRecord = 'als' // 初始化记录
i += 2 // 跳过已匹配的 "als"
continue
}
// 捕获状态下,遇到空格时结束记录
if (capturing) {
if (char === ' ') {
records.push(currentRecord) // 保存当前记录
capturing = false // 停止捕获
currentRecord = '' // 重置记录
}
else {
currentRecord += char // 继续捕获字符
}
}
}
// 将结果写入到JSON文件中
fs.writeFile(outputFilePath, JSON.stringify(records, null, 2), (err) => {
if (err) {
console.error('写入文件失败:', err)
}
else {
console.log(`记录已保存到文件: ${outputFilePath}`)
}
})
})

View File

@ -1,41 +0,0 @@
const fs = require('node:fs')
const path = require('node:path')
// 读取文件路径
const inputFilePath = path.join(__dirname, 'output.json')
// 输出文件路径
const outputFilePath = path.join(__dirname, 'word_list.json')
// 读取JSON文件
fs.readFile(inputFilePath, 'utf8', (err, data) => {
if (err) {
console.error('读取文件失败:', err)
return
}
// 解析JSON内容
const records = JSON.parse(data)
// 用于存储所有分割后的单词
const wordSet = new Set()
// 遍历每个元素,将其按下划线分割
records.forEach((record) => {
const words = record.split('_')
words.forEach(word => wordSet.add(word)) // 去重
})
// 将Set转换为数组
const uniqueWords = Array.from(wordSet)
// 将结果写入到新的JSON文件
fs.writeFile(outputFilePath, JSON.stringify(uniqueWords, null, 2), (err) => {
if (err) {
console.error('写入文件失败:', err)
}
else {
console.log(`单词列表已保存到文件: ${outputFilePath}`)
}
})
})

View File

@ -1,822 +0,0 @@
[
"als_d7_id_pdl_allnum",
"als_d7_id_pdl_orgnum",
"als_d7_id_caon_allnum",
"als_d7_id_caon_orgnum",
"als_d7_id_rel_allnum",
"als_d7_id_rel_orgnum",
"als_d7_id_caoff_allnum",
"als_d7_id_caoff_orgnum",
"als_d7_id_cooff_allnum",
"als_d7_id_cooff_orgnum",
"als_d7_id_af_allnum",
"als_d7_id_af_orgnum",
"als_d7_id_coon_allnum",
"als_d7_id_coon_orgnum",
"als_d7_id_oth_allnum",
"als_d7_id_oth_orgnum",
"als_d7_id_bank_selfnum",
"als_d7_id_bank_allnum",
"als_d7_id_bank_tra_allnum",
"als_d7_id_bank_ret_allnum",
"als_d7_id_bank_orgnum",
"als_d7_id_bank_tra_orgnum",
"als_d7_id_bank_ret_orgnum",
"als_d7_id_bank_week_allnum",
"als_d7_id_bank_week_orgnum",
"als_d7_id_bank_night_allnum",
"als_d7_id_bank_night_orgnum",
"als_d7_id_nbank_selfnum",
"als_d7_id_nbank_allnum",
"als_d7_id_nbank_p2p_allnum",
"als_d7_id_nbank_mc_allnum",
"als_d7_id_nbank_ca_allnum",
"als_d7_id_nbank_cf_allnum",
"als_d7_id_nbank_com_allnum",
"als_d7_id_nbank_oth_allnum",
"als_d7_id_nbank_nsloan_allnum",
"als_d7_id_nbank_autofin_allnum",
"als_d7_id_nbank_sloan_allnum",
"als_d7_id_nbank_cons_allnum",
"als_d7_id_nbank_finlea_allnum",
"als_d7_id_nbank_else_allnum",
"als_d7_id_nbank_orgnum",
"als_d7_id_nbank_p2p_orgnum",
"als_d7_id_nbank_mc_orgnum",
"als_d7_id_nbank_ca_orgnum",
"als_d7_id_nbank_cf_orgnum",
"als_d7_id_nbank_com_orgnum",
"als_d7_id_nbank_oth_orgnum",
"als_d7_id_nbank_nsloan_orgnum",
"als_d7_id_nbank_autofin_orgnum",
"als_d7_id_nbank_sloan_orgnum",
"als_d7_id_nbank_cons_orgnum",
"als_d7_id_nbank_finlea_orgnum",
"als_d7_id_nbank_else_orgnum",
"als_d7_id_nbank_week_allnum",
"als_d7_id_nbank_week_orgnum",
"als_d7_id_nbank_night_allnum",
"als_d7_id_nbank_night_orgnum",
"als_d7_cell_pdl_allnum",
"als_d7_cell_pdl_orgnum",
"als_d7_cell_caon_allnum",
"als_d7_cell_caon_orgnum",
"als_d7_cell_rel_allnum",
"als_d7_cell_rel_orgnum",
"als_d7_cell_caoff_allnum",
"als_d7_cell_caoff_orgnum",
"als_d7_cell_cooff_allnum",
"als_d7_cell_cooff_orgnum",
"als_d7_cell_af_allnum",
"als_d7_cell_af_orgnum",
"als_d7_cell_coon_allnum",
"als_d7_cell_coon_orgnum",
"als_d7_cell_oth_allnum",
"als_d7_cell_oth_orgnum",
"als_d7_cell_bank_selfnum",
"als_d7_cell_bank_allnum",
"als_d7_cell_bank_tra_allnum",
"als_d7_cell_bank_ret_allnum",
"als_d7_cell_bank_orgnum",
"als_d7_cell_bank_tra_orgnum",
"als_d7_cell_bank_ret_orgnum",
"als_d7_cell_bank_week_allnum",
"als_d7_cell_bank_week_orgnum",
"als_d7_cell_bank_night_allnum",
"als_d7_cell_bank_night_orgnum",
"als_d7_cell_nbank_selfnum",
"als_d7_cell_nbank_allnum",
"als_d7_cell_nbank_p2p_allnum",
"als_d7_cell_nbank_mc_allnum",
"als_d7_cell_nbank_ca_allnum",
"als_d7_cell_nbank_cf_allnum",
"als_d7_cell_nbank_com_allnum",
"als_d7_cell_nbank_oth_allnum",
"als_d7_cell_nbank_nsloan_allnum",
"als_d7_cell_nbank_autofin_allnum",
"als_d7_cell_nbank_sloan_allnum",
"als_d7_cell_nbank_cons_allnum",
"als_d7_cell_nbank_finlea_allnum",
"als_d7_cell_nbank_else_allnum",
"als_d7_cell_nbank_orgnum",
"als_d7_cell_nbank_p2p_orgnum",
"als_d7_cell_nbank_mc_orgnum",
"als_d7_cell_nbank_ca_orgnum",
"als_d7_cell_nbank_cf_orgnum",
"als_d7_cell_nbank_com_orgnum",
"als_d7_cell_nbank_oth_orgnum",
"als_d7_cell_nbank_nsloan_orgnum",
"als_d7_cell_nbank_autofin_orgnum",
"als_d7_cell_nbank_sloan_orgnum",
"als_d7_cell_nbank_cons_orgnum",
"als_d7_cell_nbank_finlea_orgnum",
"als_d7_cell_nbank_else_orgnum",
"als_d7_cell_nbank_week_allnum",
"als_d7_cell_nbank_week_orgnum",
"als_d7_cell_nbank_night_allnum",
"als_d7_cell_nbank_night_orgnum",
"als_d15_id_pdl_allnum",
"als_d15_id_pdl_orgnum",
"als_d15_id_caon_allnum",
"als_d15_id_caon_orgnum",
"als_d15_id_rel_allnum",
"als_d15_id_rel_orgnum",
"als_d15_id_caoff_allnum",
"als_d15_id_caoff_orgnum",
"als_d15_id_cooff_allnum",
"als_d15_id_cooff_orgnum",
"als_d15_id_af_allnum",
"als_d15_id_af_orgnum",
"als_d15_id_coon_allnum",
"als_d15_id_coon_orgnum",
"als_d15_id_oth_allnum",
"als_d15_id_oth_orgnum",
"als_d15_id_bank_selfnum",
"als_d15_id_bank_allnum",
"als_d15_id_bank_tra_allnum",
"als_d15_id_bank_ret_allnum",
"als_d15_id_bank_orgnum",
"als_d15_id_bank_tra_orgnum",
"als_d15_id_bank_ret_orgnum",
"als_d15_id_bank_week_allnum",
"als_d15_id_bank_week_orgnum",
"als_d15_id_bank_night_allnum",
"als_d15_id_bank_night_orgnum",
"als_d15_id_nbank_selfnum",
"als_d15_id_nbank_allnum",
"als_d15_id_nbank_p2p_allnum",
"als_d15_id_nbank_mc_allnum",
"als_d15_id_nbank_ca_allnum",
"als_d15_id_nbank_cf_allnum",
"als_d15_id_nbank_com_allnum",
"als_d15_id_nbank_oth_allnum",
"als_d15_id_nbank_nsloan_allnum",
"als_d15_id_nbank_autofin_allnum",
"als_d15_id_nbank_sloan_allnum",
"als_d15_id_nbank_cons_allnum",
"als_d15_id_nbank_finlea_allnum",
"als_d15_id_nbank_else_allnum",
"als_d15_id_nbank_orgnum",
"als_d15_id_nbank_p2p_orgnum",
"als_d15_id_nbank_mc_orgnum",
"als_d15_id_nbank_ca_orgnum",
"als_d15_id_nbank_cf_orgnum",
"als_d15_id_nbank_com_orgnum",
"als_d15_id_nbank_oth_orgnum",
"als_d15_id_nbank_nsloan_orgnum",
"als_d15_id_nbank_autofin_orgnum",
"als_d15_id_nbank_sloan_orgnum",
"als_d15_id_nbank_cons_orgnum",
"als_d15_id_nbank_finlea_orgnum",
"als_d15_id_nbank_else_orgnum",
"als_d15_id_nbank_week_allnum",
"als_d15_id_nbank_week_orgnum",
"als_d15_id_nbank_night_allnum",
"als_d15_id_nbank_night_orgnum",
"als_d15_cell_pdl_allnum",
"als_d15_cell_pdl_orgnum",
"als_d15_cell_caon_allnum",
"als_d15_cell_caon_orgnum",
"als_d15_cell_rel_allnum",
"als_d15_cell_rel_orgnum",
"als_d15_cell_caoff_allnum",
"als_d15_cell_caoff_orgnum",
"als_d15_cell_cooff_allnum",
"als_d15_cell_cooff_orgnum",
"als_d15_cell_af_allnum",
"als_d15_cell_af_orgnum",
"als_d15_cell_coon_allnum",
"als_d15_cell_coon_orgnum",
"als_d15_cell_oth_allnum",
"als_d15_cell_oth_orgnum",
"als_d15_cell_bank_selfnum",
"als_d15_cell_bank_allnum",
"als_d15_cell_bank_tra_allnum",
"als_d15_cell_bank_ret_allnum",
"als_d15_cell_bank_orgnum",
"als_d15_cell_bank_tra_orgnum",
"als_d15_cell_bank_ret_orgnum",
"als_d15_cell_bank_week_allnum",
"als_d15_cell_bank_week_orgnum",
"als_d15_cell_bank_night_allnum",
"als_d15_cell_bank_night_orgnum",
"als_d15_cell_nbank_selfnum",
"als_d15_cell_nbank_allnum",
"als_d15_cell_nbank_p2p_allnum",
"als_d15_cell_nbank_mc_allnum",
"als_d15_cell_nbank_ca_allnum",
"als_d15_cell_nbank_cf_allnum",
"als_d15_cell_nbank_com_allnum",
"als_d15_cell_nbank_oth_allnum",
"als_d15_cell_nbank_nsloan_allnum",
"als_d15_cell_nbank_autofin_allnum",
"als_d15_cell_nbank_sloan_allnum",
"als_d15_cell_nbank_cons_allnum",
"als_d15_cell_nbank_finlea_allnum",
"als_d15_cell_nbank_else_allnum",
"als_d15_cell_nbank_orgnum",
"als_d15_cell_nbank_p2p_orgnum",
"als_d15_cell_nbank_mc_orgnum",
"als_d15_cell_nbank_ca_orgnum",
"als_d15_cell_nbank_cf_orgnum",
"als_d15_cell_nbank_com_orgnum",
"als_d15_cell_nbank_oth_orgnum",
"als_d15_cell_nbank_nsloan_orgnum",
"als_d15_cell_nbank_autofin_orgnum",
"als_d15_cell_nbank_sloan_orgnum",
"als_d15_cell_nbank_cons_orgnum",
"als_d15_cell_nbank_finlea_orgnum",
"als_d15_cell_nbank_else_orgnum",
"als_d15_cell_nbank_week_allnum",
"als_d15_cell_nbank_week_orgnum",
"als_d15_cell_nbank_night_allnum",
"als_d15_cell_nbank_night_orgnum",
"als_m1_id_pdl_allnum",
"als_m1_id_pdl_orgnum",
"als_m1_id_caon_allnum",
"als_m1_id_caon_orgnum",
"als_m1_id_rel_allnum",
"als_m1_id_rel_orgnum",
"als_m1_id_caoff_allnum",
"als_m1_id_caoff_orgnum",
"als_m1_id_cooff_allnum",
"als_m1_id_cooff_orgnum",
"als_m1_id_af_allnum",
"als_m1_id_af_orgnum",
"als_m1_id_coon_allnum",
"als_m1_id_coon_orgnum",
"als_m1_id_oth_allnum",
"als_m1_id_oth_orgnum",
"als_m1_id_bank_selfnum",
"als_m1_id_bank_allnum",
"als_m1_id_bank_tra_allnum",
"als_m1_id_bank_ret_allnum",
"als_m1_id_bank_orgnum",
"als_m1_id_bank_tra_orgnum",
"als_m1_id_bank_ret_orgnum",
"als_m1_id_bank_week_allnum",
"als_m1_id_bank_week_orgnum",
"als_m1_id_bank_night_allnum",
"als_m1_id_bank_night_orgnum",
"als_m1_id_nbank_selfnum",
"als_m1_id_nbank_allnum",
"als_m1_id_nbank_p2p_allnum",
"als_m1_id_nbank_mc_allnum",
"als_m1_id_nbank_ca_allnum",
"als_m1_id_nbank_cf_allnum",
"als_m1_id_nbank_com_allnum",
"als_m1_id_nbank_oth_allnum",
"als_m1_id_nbank_nsloan_allnum",
"als_m1_id_nbank_autofin_allnum",
"als_m1_id_nbank_sloan_allnum",
"als_m1_id_nbank_cons_allnum",
"als_m1_id_nbank_finlea_allnum",
"als_m1_id_nbank_else_allnum",
"als_m1_id_nbank_orgnum",
"als_m1_id_nbank_p2p_orgnum",
"als_m1_id_nbank_mc_orgnum",
"als_m1_id_nbank_ca_orgnum",
"als_m1_id_nbank_cf_orgnum",
"als_m1_id_nbank_com_orgnum",
"als_m1_id_nbank_oth_orgnum",
"als_m1_id_nbank_nsloan_orgnum",
"als_m1_id_nbank_autofin_orgnum",
"als_m1_id_nbank_sloan_orgnum",
"als_m1_id_nbank_cons_orgnum",
"als_m1_id_nbank_finlea_orgnum",
"als_m1_id_nbank_else_orgnum",
"als_m1_id_nbank_week_allnum",
"als_m1_id_nbank_week_orgnum",
"als_m1_id_nbank_night_allnum",
"als_m1_id_nbank_night_orgnum",
"als_m1_cell_pdl_allnum",
"als_m1_cell_pdl_orgnum",
"als_m1_cell_caon_allnum",
"als_m1_cell_caon_orgnum",
"als_m1_cell_rel_allnum",
"als_m1_cell_rel_orgnum",
"als_m1_cell_caoff_allnum",
"als_m1_cell_caoff_orgnum",
"als_m1_cell_cooff_allnum",
"als_m1_cell_cooff_orgnum",
"als_m1_cell_af_allnum",
"als_m1_cell_af_orgnum",
"als_m1_cell_coon_allnum",
"als_m1_cell_coon_orgnum",
"als_m1_cell_oth_allnum",
"als_m1_cell_oth_orgnum",
"als_m1_cell_bank_selfnum",
"als_m1_cell_bank_allnum",
"als_m1_cell_bank_tra_allnum",
"als_m1_cell_bank_ret_allnum",
"als_m1_cell_bank_orgnum",
"als_m1_cell_bank_tra_orgnum",
"als_m1_cell_bank_ret_orgnum",
"als_m1_cell_bank_week_allnum",
"als_m1_cell_bank_week_orgnum",
"als_m1_cell_bank_night_allnum",
"als_m1_cell_bank_night_orgnum",
"als_m1_cell_nbank_selfnum",
"als_m1_cell_nbank_allnum",
"als_m1_cell_nbank_p2p_allnum",
"als_m1_cell_nbank_mc_allnum",
"als_m1_cell_nbank_ca_allnum",
"als_m1_cell_nbank_cf_allnum",
"als_m1_cell_nbank_com_allnum",
"als_m1_cell_nbank_oth_allnum",
"als_m1_cell_nbank_nsloan_allnum",
"als_m1_cell_nbank_autofin_allnum",
"als_m1_cell_nbank_sloan_allnum",
"als_m1_cell_nbank_cons_allnum",
"als_m1_cell_nbank_finlea_allnum",
"als_m1_cell_nbank_else_allnum",
"als_m1_cell_nbank_orgnum",
"als_m1_cell_nbank_p2p_orgnum",
"als_m1_cell_nbank_mc_orgnum",
"als_m1_cell_nbank_ca_orgnum",
"als_m1_cell_nbank_cf_orgnum",
"als_m1_cell_nbank_com_orgnum",
"als_m1_cell_nbank_oth_orgnum",
"als_m1_cell_nbank_nsloan_orgnum",
"als_m1_cell_nbank_autofin_orgnum",
"als_m1_cell_nbank_sloan_orgnum",
"als_m1_cell_nbank_cons_orgnum",
"als_m1_cell_nbank_finlea_orgnum",
"als_m1_cell_nbank_else_orgnum",
"als_m1_cell_nbank_week_allnum",
"als_m1_cell_nbank_week_orgnum",
"als_m1_cell_nbank_night_allnum",
"als_m1_cell_nbank_night_orgnum",
"als_m3_id_max_inteday",
"als_m3_id_min_inteday",
"als_m3_id_tot_mons",
"als_m3_id_avg_monnum",
"als_m3_id_max_monnum",
"als_m3_id_min_monnum",
"als_m3_id_pdl_allnum",
"als_m3_id_pdl_orgnum",
"als_m3_id_caon_allnum",
"als_m3_id_caon_orgnum",
"als_m3_id_rel_allnum",
"als_m3_id_rel_orgnum",
"als_m3_id_caoff_allnum",
"als_m3_id_caoff_orgnum",
"als_m3_id_cooff_allnum",
"als_m3_id_cooff_orgnum",
"als_m3_id_af_allnum",
"als_m3_id_af_orgnum",
"als_m3_id_coon_allnum",
"als_m3_id_coon_orgnum",
"als_m3_id_oth_allnum",
"als_m3_id_oth_orgnum",
"als_m3_id_bank_selfnum",
"als_m3_id_bank_allnum",
"als_m3_id_bank_tra_allnum",
"als_m3_id_bank_ret_allnum",
"als_m3_id_bank_orgnum",
"als_m3_id_bank_tra_orgnum",
"als_m3_id_bank_ret_orgnum",
"als_m3_id_bank_tot_mons",
"als_m3_id_bank_avg_monnum",
"als_m3_id_bank_max_monnum",
"als_m3_id_bank_min_monnum",
"als_m3_id_bank_max_inteday",
"als_m3_id_bank_min_inteday",
"als_m3_id_bank_week_allnum",
"als_m3_id_bank_week_orgnum",
"als_m3_id_bank_night_allnum",
"als_m3_id_bank_night_orgnum",
"als_m3_id_nbank_selfnum",
"als_m3_id_nbank_allnum",
"als_m3_id_nbank_p2p_allnum",
"als_m3_id_nbank_mc_allnum",
"als_m3_id_nbank_ca_allnum",
"als_m3_id_nbank_cf_allnum",
"als_m3_id_nbank_com_allnum",
"als_m3_id_nbank_oth_allnum",
"als_m3_id_nbank_nsloan_allnum",
"als_m3_id_nbank_autofin_allnum",
"als_m3_id_nbank_sloan_allnum",
"als_m3_id_nbank_cons_allnum",
"als_m3_id_nbank_finlea_allnum",
"als_m3_id_nbank_else_allnum",
"als_m3_id_nbank_orgnum",
"als_m3_id_nbank_p2p_orgnum",
"als_m3_id_nbank_mc_orgnum",
"als_m3_id_nbank_ca_orgnum",
"als_m3_id_nbank_cf_orgnum",
"als_m3_id_nbank_com_orgnum",
"als_m3_id_nbank_oth_orgnum",
"als_m3_id_nbank_nsloan_orgnum",
"als_m3_id_nbank_autofin_orgnum",
"als_m3_id_nbank_sloan_orgnum",
"als_m3_id_nbank_cons_orgnum",
"als_m3_id_nbank_finlea_orgnum",
"als_m3_id_nbank_else_orgnum",
"als_m3_id_nbank_tot_mons",
"als_m3_id_nbank_avg_monnum",
"als_m3_id_nbank_max_monnum",
"als_m3_id_nbank_min_monnum",
"als_m3_id_nbank_max_inteday",
"als_m3_id_nbank_min_inteday",
"als_m3_id_nbank_week_allnum",
"als_m3_id_nbank_week_orgnum",
"als_m3_id_nbank_night_allnum",
"als_m3_id_nbank_night_orgnum",
"als_m3_cell_max_inteday",
"als_m3_cell_min_inteday",
"als_m3_cell_tot_mons",
"als_m3_cell_avg_monnum",
"als_m3_cell_max_monnum",
"als_m3_cell_min_monnum",
"als_m3_cell_pdl_allnum",
"als_m3_cell_pdl_orgnum",
"als_m3_cell_caon_allnum",
"als_m3_cell_caon_orgnum",
"als_m3_cell_rel_allnum",
"als_m3_cell_rel_orgnum",
"als_m3_cell_caoff_allnum",
"als_m3_cell_caoff_orgnum",
"als_m3_cell_cooff_allnum",
"als_m3_cell_cooff_orgnum",
"als_m3_cell_af_allnum",
"als_m3_cell_af_orgnum",
"als_m3_cell_coon_allnum",
"als_m3_cell_coon_orgnum",
"als_m3_cell_oth_allnum",
"als_m3_cell_oth_orgnum",
"als_m3_cell_bank_selfnum",
"als_m3_cell_bank_allnum",
"als_m3_cell_bank_tra_allnum",
"als_m3_cell_bank_ret_allnum",
"als_m3_cell_bank_orgnum",
"als_m3_cell_bank_tra_orgnum",
"als_m3_cell_bank_ret_orgnum",
"als_m3_cell_bank_tot_mons",
"als_m3_cell_bank_avg_monnum",
"als_m3_cell_bank_max_monnum",
"als_m3_cell_bank_min_monnum",
"als_m3_cell_bank_max_inteday",
"als_m3_cell_bank_min_inteday",
"als_m3_cell_bank_week_allnum",
"als_m3_cell_bank_week_orgnum",
"als_m3_cell_bank_night_allnum",
"als_m3_cell_bank_night_orgnum",
"als_m3_cell_nbank_selfnum",
"als_m3_cell_nbank_allnum",
"als_m3_cell_nbank_p2p_allnum",
"als_m3_cell_nbank_mc_allnum",
"als_m3_cell_nbank_ca_allnum",
"als_m3_cell_nbank_cf_allnum",
"als_m3_cell_nbank_com_allnum",
"als_m3_cell_nbank_oth_allnum",
"als_m3_cell_nbank_nsloan_allnum",
"als_m3_cell_nbank_autofin_allnum",
"als_m3_cell_nbank_sloan_allnum",
"als_m3_cell_nbank_cons_allnum",
"als_m3_cell_nbank_finlea_allnum",
"als_m3_cell_nbank_else_allnum",
"als_m3_cell_nbank_orgnum",
"als_m3_cell_nbank_p2p_orgnum",
"als_m3_cell_nbank_mc_orgnum",
"als_m3_cell_nbank_ca_orgnum",
"als_m3_cell_nbank_cf_orgnum",
"als_m3_cell_nbank_com_orgnum",
"als_m3_cell_nbank_oth_orgnum",
"als_m3_cell_nbank_nsloan_orgnum",
"als_m3_cell_nbank_autofin_orgnum",
"als_m3_cell_nbank_sloan_orgnum",
"als_m3_cell_nbank_cons_orgnum",
"als_m3_cell_nbank_finlea_orgnum",
"als_m3_cell_nbank_else_orgnum",
"als_m3_cell_nbank_tot_mons",
"als_m3_cell_nbank_avg_monnum",
"als_m3_cell_nbank_max_monnum",
"als_m3_cell_nbank_min_monnum",
"als_m3_cell_nbank_max_inteday",
"als_m3_cell_nbank_min_inteday",
"als_m3_cell_nbank_week_allnum",
"als_m3_cell_nbank_week_orgnum",
"als_m3_cell_nbank_night_allnum",
"als_m3_cell_nbank_night_orgnum",
"als_m6_id_max_inteday",
"als_m6_id_min_inteday",
"als_m6_id_tot_mons",
"als_m6_id_avg_monnum",
"als_m6_id_max_monnum",
"als_m6_id_min_monnum",
"als_m6_id_pdl_allnum",
"als_m6_id_pdl_orgnum",
"als_m6_id_caon_allnum",
"als_m6_id_caon_orgnum",
"als_m6_id_rel_allnum",
"als_m6_id_rel_orgnum",
"als_m6_id_caoff_allnum",
"als_m6_id_caoff_orgnum",
"als_m6_id_cooff_allnum",
"als_m6_id_cooff_orgnum",
"als_m6_id_af_allnum",
"als_m6_id_af_orgnum",
"als_m6_id_coon_allnum",
"als_m6_id_coon_orgnum",
"als_m6_id_oth_allnum",
"als_m6_id_oth_orgnum",
"als_m6_id_bank_selfnum",
"als_m6_id_bank_allnum",
"als_m6_id_bank_tra_allnum",
"als_m6_id_bank_ret_allnum",
"als_m6_id_bank_orgnum",
"als_m6_id_bank_tra_orgnum",
"als_m6_id_bank_ret_orgnum",
"als_m6_id_bank_tot_mons",
"als_m6_id_bank_avg_monnum",
"als_m6_id_bank_max_monnum",
"als_m6_id_bank_min_monnum",
"als_m6_id_bank_max_inteday",
"als_m6_id_bank_min_inteday",
"als_m6_id_bank_week_allnum",
"als_m6_id_bank_week_orgnum",
"als_m6_id_bank_night_allnum",
"als_m6_id_bank_night_orgnum",
"als_m6_id_nbank_selfnum",
"als_m6_id_nbank_allnum",
"als_m6_id_nbank_p2p_allnum",
"als_m6_id_nbank_mc_allnum",
"als_m6_id_nbank_ca_allnum",
"als_m6_id_nbank_cf_allnum",
"als_m6_id_nbank_com_allnum",
"als_m6_id_nbank_oth_allnum",
"als_m6_id_nbank_nsloan_allnum",
"als_m6_id_nbank_autofin_allnum",
"als_m6_id_nbank_sloan_allnum",
"als_m6_id_nbank_cons_allnum",
"als_m6_id_nbank_finlea_allnum",
"als_m6_id_nbank_else_allnum",
"als_m6_id_nbank_orgnum",
"als_m6_id_nbank_p2p_orgnum",
"als_m6_id_nbank_mc_orgnum",
"als_m6_id_nbank_ca_orgnum",
"als_m6_id_nbank_cf_orgnum",
"als_m6_id_nbank_com_orgnum",
"als_m6_id_nbank_oth_orgnum",
"als_m6_id_nbank_nsloan_orgnum",
"als_m6_id_nbank_autofin_orgnum",
"als_m6_id_nbank_sloan_orgnum",
"als_m6_id_nbank_cons_orgnum",
"als_m6_id_nbank_finlea_orgnum",
"als_m6_id_nbank_else_orgnum",
"als_m6_id_nbank_tot_mons",
"als_m6_id_nbank_avg_monnum",
"als_m6_id_nbank_max_monnum",
"als_m6_id_nbank_min_monnum",
"als_m6_id_nbank_max_inteday",
"als_m6_id_nbank_min_inteday",
"als_m6_id_nbank_week_allnum",
"als_m6_id_nbank_week_orgnum",
"als_m6_id_nbank_night_allnum",
"als_m6_id_nbank_night_orgnum",
"als_m6_cell_max_inteday",
"als_m6_cell_min_inteday",
"als_m6_cell_tot_mons",
"als_m6_cell_avg_monnum",
"als_m6_cell_max_monnum",
"als_m6_cell_min_monnum",
"als_m6_cell_pdl_allnum",
"als_m6_cell_pdl_orgnum",
"als_m6_cell_caon_allnum",
"als_m6_cell_caon_orgnum",
"als_m6_cell_rel_allnum",
"als_m6_cell_rel_orgnum",
"als_m6_cell_caoff_allnum",
"als_m6_cell_caoff_orgnum",
"als_m6_cell_cooff_allnum",
"als_m6_cell_cooff_orgnum",
"als_m6_cell_af_allnum",
"als_m6_cell_af_orgnum",
"als_m6_cell_coon_allnum",
"als_m6_cell_coon_orgnum",
"als_m6_cell_oth_allnum",
"als_m6_cell_oth_orgnum",
"als_m6_cell_bank_selfnum",
"als_m6_cell_bank_allnum",
"als_m6_cell_bank_tra_allnum",
"als_m6_cell_bank_ret_allnum",
"als_m6_cell_bank_orgnum",
"als_m6_cell_bank_tra_orgnum",
"als_m6_cell_bank_ret_orgnum",
"als_m6_cell_bank_tot_mons",
"als_m6_cell_bank_avg_monnum",
"als_m6_cell_bank_max_monnum",
"als_m6_cell_bank_min_monnum",
"als_m6_cell_bank_max_inteday",
"als_m6_cell_bank_min_inteday",
"als_m6_cell_bank_week_allnum",
"als_m6_cell_bank_week_orgnum",
"als_m6_cell_bank_night_allnum",
"als_m6_cell_bank_night_orgnum",
"als_m6_cell_nbank_selfnum",
"als_m6_cell_nbank_allnum",
"als_m6_cell_nbank_p2p_allnum",
"als_m6_cell_nbank_mc_allnum",
"als_m6_cell_nbank_ca_allnum",
"als_m6_cell_nbank_cf_allnum",
"als_m6_cell_nbank_com_allnum",
"als_m6_cell_nbank_oth_allnum",
"als_m6_cell_nbank_nsloan_allnum",
"als_m6_cell_nbank_autofin_allnum",
"als_m6_cell_nbank_sloan_allnum",
"als_m6_cell_nbank_cons_allnum",
"als_m6_cell_nbank_finlea_allnum",
"als_m6_cell_nbank_else_allnum",
"als_m6_cell_nbank_orgnum",
"als_m6_cell_nbank_p2p_orgnum",
"als_m6_cell_nbank_mc_orgnum",
"als_m6_cell_nbank_ca_orgnum",
"als_m6_cell_nbank_cf_orgnum",
"als_m6_cell_nbank_com_orgnum",
"als_m6_cell_nbank_oth_orgnum",
"als_m6_cell_nbank_nsloan_orgnum",
"als_m6_cell_nbank_autofin_orgnum",
"als_m6_cell_nbank_sloan_orgnum",
"als_m6_cell_nbank_cons_orgnum",
"als_m6_cell_nbank_finlea_orgnum",
"als_m6_cell_nbank_else_orgnum",
"als_m6_cell_nbank_tot_mons",
"als_m6_cell_nbank_avg_monnum",
"als_m6_cell_nbank_max_monnum",
"als_m6_cell_nbank_min_monnum",
"als_m6_cell_nbank_max_inteday",
"als_m6_cell_nbank_min_inteday",
"als_m6_cell_nbank_week_allnum",
"als_m6_cell_nbank_week_orgnum",
"als_m6_cell_nbank_night_allnum",
"als_m6_cell_nbank_night_orgnum",
"als_m12_id_max_inteday",
"als_m12_id_min_inteday",
"als_m12_id_tot_mons",
"als_m12_id_avg_monnum",
"als_m12_id_max_monnum",
"als_m12_id_min_monnum",
"als_m12_id_pdl_allnum",
"als_m12_id_pdl_orgnum",
"als_m12_id_caon_allnum",
"als_m12_id_caon_orgnum",
"als_m12_id_rel_allnum",
"als_m12_id_rel_orgnum",
"als_m12_id_caoff_allnum",
"als_m12_id_caoff_orgnum",
"als_m12_id_cooff_allnum",
"als_m12_id_cooff_orgnum",
"als_m12_id_af_allnum",
"als_m12_id_af_orgnum",
"als_m12_id_coon_allnum",
"als_m12_id_coon_orgnum",
"als_m12_id_oth_allnum",
"als_m12_id_oth_orgnum",
"als_m12_id_bank_selfnum",
"als_m12_id_bank_allnum",
"als_m12_id_bank_tra_allnum",
"als_m12_id_bank_ret_allnum",
"als_m12_id_bank_orgnum",
"als_m12_id_bank_tra_orgnum",
"als_m12_id_bank_ret_orgnum",
"als_m12_id_bank_tot_mons",
"als_m12_id_bank_avg_monnum",
"als_m12_id_bank_max_monnum",
"als_m12_id_bank_min_monnum",
"als_m12_id_bank_max_inteday",
"als_m12_id_bank_min_inteday",
"als_m12_id_bank_week_allnum",
"als_m12_id_bank_week_orgnum",
"als_m12_id_bank_night_allnum",
"als_m12_id_bank_night_orgnum",
"als_m12_id_nbank_selfnum",
"als_m12_id_nbank_allnum",
"als_m12_id_nbank_p2p_allnum",
"als_m12_id_nbank_mc_allnum",
"als_m12_id_nbank_ca_allnum",
"als_m12_id_nbank_cf_allnum",
"als_m12_id_nbank_com_allnum",
"als_m12_id_nbank_oth_allnum",
"als_m12_id_nbank_nsloan_allnum",
"als_m12_id_nbank_autofin_allnum",
"als_m12_id_nbank_sloan_allnum",
"als_m12_id_nbank_cons_allnum",
"als_m12_id_nbank_finlea_allnum",
"als_m12_id_nbank_else_allnum",
"als_m12_id_nbank_orgnum",
"als_m12_id_nbank_p2p_orgnum",
"als_m12_id_nbank_mc_orgnum",
"als_m12_id_nbank_ca_orgnum",
"als_m12_id_nbank_cf_orgnum",
"als_m12_id_nbank_com_orgnum",
"als_m12_id_nbank_oth_orgnum",
"als_m12_id_nbank_nsloan_orgnum",
"als_m12_id_nbank_autofin_orgnum",
"als_m12_id_nbank_sloan_orgnum",
"als_m12_id_nbank_cons_orgnum",
"als_m12_id_nbank_finlea_orgnum",
"als_m12_id_nbank_else_orgnum",
"als_m12_id_nbank_tot_mons",
"als_m12_id_nbank_avg_monnum",
"als_m12_id_nbank_max_monnum",
"als_m12_id_nbank_min_monnum",
"als_m12_id_nbank_max_inteday",
"als_m12_id_nbank_min_inteday",
"als_m12_id_nbank_week_allnum",
"als_m12_id_nbank_week_orgnum",
"als_m12_id_nbank_night_allnum",
"als_m12_id_nbank_night_orgnum",
"als_m12_cell_max_inteday",
"als_m12_cell_min_inteday",
"als_m12_cell_tot_mons",
"als_m12_cell_avg_monnum",
"als_m12_cell_max_monnum",
"als_m12_cell_min_monnum",
"als_m12_cell_pdl_allnum",
"als_m12_cell_pdl_orgnum",
"als_m12_cell_caon_allnum",
"als_m12_cell_caon_orgnum",
"als_m12_cell_rel_allnum",
"als_m12_cell_rel_orgnum",
"als_m12_cell_caoff_allnum",
"als_m12_cell_caoff_orgnum",
"als_m12_cell_cooff_allnum",
"als_m12_cell_cooff_orgnum",
"als_m12_cell_af_allnum",
"als_m12_cell_af_orgnum",
"als_m12_cell_coon_allnum",
"als_m12_cell_coon_orgnum",
"als_m12_cell_oth_allnum",
"als_m12_cell_oth_orgnum",
"als_m12_cell_bank_selfnum",
"als_m12_cell_bank_allnum",
"als_m12_cell_bank_tra_allnum",
"als_m12_cell_bank_ret_allnum",
"als_m12_cell_bank_orgnum",
"als_m12_cell_bank_tra_orgnum",
"als_m12_cell_bank_ret_orgnum",
"als_m12_cell_bank_tot_mons",
"als_m12_cell_bank_avg_monnum",
"als_m12_cell_bank_max_monnum",
"als_m12_cell_bank_min_monnum",
"als_m12_cell_bank_max_inteday",
"als_m12_cell_bank_min_inteday",
"als_m12_cell_bank_week_allnum",
"als_m12_cell_bank_week_orgnum",
"als_m12_cell_bank_night_allnum",
"als_m12_cell_bank_night_orgnum",
"als_m12_cell_nbank_selfnum",
"als_m12_cell_nbank_allnum",
"als_m12_cell_nbank_p2p_allnum",
"als_m12_cell_nbank_mc_allnum",
"als_m12_cell_nbank_ca_allnum",
"als_m12_cell_nbank_cf_allnum",
"als_m12_cell_nbank_com_allnum",
"als_m12_cell_nbank_oth_allnum",
"als_m12_cell_nbank_nsloan_allnum",
"als_m12_cell_nbank_autofin_allnum",
"als_m12_cell_nbank_sloan_allnum",
"als_m12_cell_nbank_cons_allnum",
"als_m12_cell_nbank_finlea_allnum",
"als_m12_cell_nbank_else_allnum",
"als_m12_cell_nbank_orgnum",
"als_m12_cell_nbank_p2p_orgnum",
"als_m12_cell_nbank_mc_orgnum",
"als_m12_cell_nbank_ca_orgnum",
"als_m12_cell_nbank_cf_orgnum",
"als_m12_cell_nbank_com_orgnum",
"als_m12_cell_nbank_oth_orgnum",
"als_m12_cell_nbank_nsloan_orgnum",
"als_m12_cell_nbank_autofin_orgnum",
"als_m12_cell_nbank_sloan_orgnum",
"als_m12_cell_nbank_cons_orgnum",
"als_m12_cell_nbank_finlea_orgnum",
"als_m12_cell_nbank_else_orgnum",
"als_m12_cell_nbank_tot_mons",
"als_m12_cell_nbank_avg_monnum",
"als_m12_cell_nbank_max_monnum",
"als_m12_cell_nbank_min_monnum",
"als_m12_cell_nbank_max_inteday",
"als_m12_cell_nbank_min_inteday",
"als_m12_cell_nbank_week_allnum",
"als_m12_cell_nbank_week_orgnum",
"als_m12_cell_nbank_night_allnum",
"als_m12_cell_nbank_night_orgnum",
"als_fst_id_bank_inteday",
"als_fst_id_nbank_inteday",
"als_fst_cell_bank_inteday",
"als_fst_cell_nbank_inteday",
"als_lst_id_bank_inteday",
"als_lst_id_bank_consnum",
"als_lst_id_bank_csinteday",
"als_lst_id_nbank_inteday",
"als_lst_id_nbank_consnum",
"als_lst_id_nbank_csinteday",
"als_lst_cell_bank_inteday",
"als_lst_cell_bank_consnum",
"als_lst_cell_bank_csinteday",
"als_lst_cell_nbank_inteday",
"als_lst_cell_nbank_consnum",
"als_lst_cell_nbank_csinteday"
]

View File

View File

@ -1,51 +0,0 @@
const keyword = [
'als',
'd7', // 近7日
'id', // 身份证号
'pdl', // 线上小额现金贷
'allnum', // 次数
'orgnum', // 机构数、
'week', // 周末
'night', // 夜间申请
'caon', // 线上现金分期
'rel', // 信用卡(类信用卡)
'caoff', // 线下现金分期
'cooff', // 线下消费分期
'af', // 汽车金融
'coon', // 线上消费分期
'oth', // 申请其他
'bank', // 银行机构
'selfnum', // 本银行机构
'tra', // 传统银行
'ret', // 网络银行
'nbank', // 非银行机构
'p2p', // 改制机构
'mc', // 小贷机构
'ca', // 现金类分期机构
'cf', // 消费类分期机构
'com', // 代偿类分期机构
'nsloan', // 持牌网络小贷
'autofin', // 持牌汽车金融机构
'sloan', // 持牌小贷机构
'cons', // 持牌消费金融机构
'finlea', // 持牌融资租赁机构
'else', // 其他申请
'cell', // 10 按手机号查询,
'd15', // 近 15 天申
'm1', // 近 1 个月
'm3', // 3 个月
'max', // 最大
'inteday', // 间隔天数
'min', // 最小
'tot', // 申请记录
'mons', // 月份数
'avg', // 平均
'monnum', // 最大月
'm6', // 6 个月
'm12', // 12个月
'fst', // 最早
'lst', // 最近
'consnum', // 连续申请
'csinteday', // 连续申请持续天数
]
console.log(keyword)

View File

@ -1,65 +0,0 @@
{
"msg": "查询成功",
"code": "0000",
"orderNo": "20241028112921367340619",
"data": {
"total": 1,
"datalist": [
{
"orgName": "海南省学宇思网络科技有限公司",
"pName": "刘福思",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "40%",
"subscriptAmt": "40.000000",
"orgHolderName": "刘福思"
},
"relationship": [
"lp",
"sh",
"tm"
],
"fsource": "",
"basicInfo": {
"regStatus": "存续",
"regCapital": "100.0000万人民币",
"reccap": 0,
"city": "海口市",
"industry_code": "I",
"industry": "互联网和相关服务",
"type": "1",
"staffList": {
"result": [
{
"name": "刘福思",
"type": "2",
"typeJoin": [
"执行董事兼总经理"
]
}
]
},
"nic_code": "I64",
"legalPersonName": "刘福思",
"regNumber": "460108011261916",
"creditCode": "91460108MADNY3F43W",
"province": "海南省",
"regorg": "海南省市场监督管理局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "",
"estiblishTime": "2024-06-20",
"opscope": "一般经营项目品牌管理5G通信技术服务人工智能应用软件开发互联网安全服务量子计算技术服务技术服务、技术开发、技术咨询、技术交流、技术转让、技术推广网络技术服务专业设计服务互联网数据服务互联网销售除销售需要许可的商品食品互联网销售仅销售预包装食品软件开发动漫游戏开发计算机软硬件及辅助设备零售计算机软硬件及辅助设备批发计算器设备销售机械设备销售五金产品零售五金产品批发电子产品销售人工智能硬件销售通信设备销售光通信设备销售通信设备制造信息系统集成服务图文设计制作广告设计、代理广告发布数字内容制作服务不含出版发行数字文化创意软件开发软件销售市场营销策划企业管理咨询信息咨询服务不含许可类信息咨询服务市场调查不含涉外调查工业设计服务玩具销售化妆品零售化妆品批发摄像及视频制作服务平面设计法律咨询不含依法须律师事务所执业许可的业务旅游开发项目策划咨询体育用品及器材批发体育用品及器材零售户外用品销售体育赛事策划体育健康服务组织体育表演活动体育中介代理服务信息技术咨询服务数据处理服务数据处理和存储支持服务大数据服务云计算装备技术服务电子、机械设备维护不含特种设备智能机器人的研发经营范围中的一般经营项目依法自主开展经营活动通过国家企业信用信息公示系统海南向社会公示许可经营项目食品进出口货物进出口技术进出口在线数据处理与交易处理业务经营类电子商务互联网游戏服务第二类增值电信业务互联网信息服务许可经营项目凭许可证件经营",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "信息传输、软件和信息技术服务业-互联网和相关服务",
"candate": "",
"district": "秀英区",
"name": "海南省学宇思网络科技有限公司",
"base": "han",
"apprdate": "2024-09-14"
}
}
]
}
}

View File

@ -1,646 +0,0 @@
{
"msg": "查询成功",
"code": "0000",
"orderNo": "20241113191941335900073",
"data": {
"total": 8,
"datalist": [
{
"executedPerson": [
{
"caseCode": "2014城中执字第00062号",
"partyCardNum": "45252819740****3016",
"pname": "李强",
"caseCreateTime": "2014-02-11",
"execCourtName": "",
"execMoney": 220605
}
],
"dishonestExecutedPerson": [
{
"businessentity": "",
"areaname": "广西",
"courtname": "柳州市城中区人民法院",
"unperformPart": "",
"type": "0",
"performedPart": "",
"iname": "李强",
"disrupttypename": "其他有履行能力而拒不履行生效法律文书确定义务",
"casecode": "2014城中执字第00062号",
"cardnum": "4525281974****3016",
"performance": "全部未履行",
"regdate": "2014-02-11",
"duty": "中国农业银行股份有限公司柳州城中支行申请执行李强220604.73元",
"gistunit": "柳州市城中区人民法院",
"publishdate": "2014-06-19",
"gistid": "2010城中民二初字第480号民事判决书"
}
],
"orgName": "广西鼎铭房地产开发有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "10.0%",
"subscriptAmt": 100,
"orgHolderName": "李强"
},
"relationship": [
"sh",
"lp",
"tm"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "1000.000000万人民币",
"reccap": 0,
"city": "",
"industry_code": "K",
"industry": "房地产业",
"type": "1",
"nic_code": "K7010",
"staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
"监事"
]
}
]
},
"legalPersonName": "李强",
"regNumber": "450000200012318",
"creditCode": "91450100742080353R",
"province": "广西壮族自治区",
"regorg": "南宁市市场监督管理局高新技术产业开发区分局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "2016-03-19",
"estiblishTime": "2002-10-16",
"opscope": "房地产开发经营(取得相应资质后方可在其资质等级核定范围内从事房地产开发经营活动);建筑材料、装饰材料、农副土特产品、日用百货、五金交电、汽车零配件的购销;计算机销售及维修。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "房地产业-房地产业-房地产开发经营-房地产开发经营",
"candate": "",
"district": "",
"name": "广西鼎铭房地产开发有限公司",
"base": "gx",
"apprdate": "2016-03-19"
},
"adminPenalty": [
{
"departmentName": "南宁市工商行政管理局高新技术产业开发区分局",
"reason": "公司成立后无正当理由超过6个月未开业的或者开业后自行停业连续6个月以上",
"punishNumber": "南工商高新处字2016500010024号",
"type": "",
"content": "",
"decisionDate": "2016-03-19",
"legalPersonName": "李强"
},
{
"departmentName": "45011101",
"reason": "南宁恒发网络科技有限公司等3177户企业未依法进行企业信息网上年报公示。经我分局执法人员在以上企业的执照注册住所检查发现上述企业已不在其注册住所经营或办公根据企业注册登记时所留电话也联系不上上述企业。",
"punishNumber": "南工商高新处字2016500010024号",
"type": "吊销执照(登记证)",
"content": "-",
"decisionDate": "2016-03-19",
"legalPersonName": "李强"
}
]
},
{
"executedPerson": [
{
"caseCode": "2010青执字第01000号",
"partyCardNum": "452528********3012",
"pname": "李健",
"caseCreateTime": "2010-09-06",
"execCourtName": "",
"execMoney": 283845
},
{
"caseCode": "2010青执字第00188号",
"partyCardNum": "45252819691****3012",
"pname": "李健",
"caseCreateTime": "2010-02-08",
"execCourtName": "",
"execMoney": 308464
}
],
"orgName": "南宁市铭鼎商贸有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "20.0%",
"subscriptAmt": 20,
"orgHolderName": "李强"
},
"relationship": [
"sh"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "100.000000万人民币",
"reccap": 0,
"city": "南宁市",
"industry_code": "F",
"industry": "零售业",
"type": "1",
"nic_code": "F5211",
"legalPersonName": "李健",
"regNumber": "4501002508737",
"creditCode": "91450107MA5KK3PU6A",
"province": "广西壮族自治区",
"regorg": "南宁市西乡塘区市场监督管理局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "2016-05-28",
"estiblishTime": "2004-07-02",
"opscope": "窗帘布艺,家居用品,装饰材料(危险化学品除外),日用百货,服装,纺织品。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-零售业-综合零售-百货零售",
"candate": "",
"district": "",
"name": "南宁市铭鼎商贸有限公司",
"base": "gx",
"apprdate": "2016-05-28"
}
},
{
"executedPerson": [
{
"caseCode": "2014城中执字第00062号",
"partyCardNum": "45252819740****3016",
"pname": "李强",
"caseCreateTime": "2014-02-11",
"execCourtName": "",
"execMoney": 220605
}
],
"dishonestExecutedPerson": [
{
"businessentity": "",
"areaname": "广西",
"courtname": "柳州市城中区人民法院",
"unperformPart": "",
"type": "0",
"performedPart": "",
"iname": "李强",
"disrupttypename": "其他有履行能力而拒不履行生效法律文书确定义务",
"casecode": "2014城中执字第00062号",
"cardnum": "4525281974****3016",
"performance": "全部未履行",
"regdate": "2014-02-11",
"duty": "中国农业银行股份有限公司柳州城中支行申请执行李强220604.73元",
"gistunit": "柳州市城中区人民法院",
"publishdate": "2014-06-19",
"gistid": "2010城中民二初字第480号民事判决书"
}
],
"orgName": "广西鼎铭房地产置换服务有限公司南宁分公司",
"pName": "李强",
"relationship": [
"lp",
"tm",
"his_tm"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "5.0万人民币",
"reccap": 0,
"city": "南宁市",
"industry_code": "K",
"industry": "房地产业",
"type": "1",
"nic_code": "K7030",
"staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
""
]
}
]
},
"legalPersonName": "李强",
"regNumber": "4501001005198",
"creditCode": "",
"province": "广西壮族自治区",
"his_staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
""
]
}
]
},
"regorg": "南宁市青秀区市场监督管理局",
"companyOrgType": "有限责任公司分公司(自然人投资或控股)",
"revdate": "2018-06-25",
"estiblishTime": "2002-01-28",
"opscope": "房地产信息咨询服务,房地产交易居间、代理、行纪;商品信息咨询(不含期货、金融、保险、证券等国家专项规定),商品交易居间、代理、行纪。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "房地产业-房地产业-房地产中介服务-房地产中介服务",
"candate": "",
"district": "青秀区",
"name": "广西鼎铭房地产置换服务有限公司南宁分公司",
"base": "gx",
"apprdate": "2018-06-25"
}
},
{
"executedPerson": [
{
"caseCode": "2014城中执字第00062号",
"partyCardNum": "45252819740****3016",
"pname": "李强",
"caseCreateTime": "2014-02-11",
"execCourtName": "",
"execMoney": 220605
}
],
"dishonestExecutedPerson": [
{
"businessentity": "",
"areaname": "广西",
"courtname": "柳州市城中区人民法院",
"unperformPart": "",
"type": "0",
"performedPart": "",
"iname": "李强",
"disrupttypename": "其他有履行能力而拒不履行生效法律文书确定义务",
"casecode": "2014城中执字第00062号",
"cardnum": "4525281974****3016",
"performance": "全部未履行",
"regdate": "2014-02-11",
"duty": "中国农业银行股份有限公司柳州城中支行申请执行李强220604.73元",
"gistunit": "柳州市城中区人民法院",
"publishdate": "2014-06-19",
"gistid": "2010城中民二初字第480号民事判决书"
}
],
"orgName": "深圳市亿讯时空信息技术有限公司北京分公司",
"pName": "李强",
"relationship": [
"lp",
"tm"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销",
"regCapital": "",
"reccap": 0,
"city": "北京市",
"industry_code": "I",
"industry": "软件和信息技术服务业",
"type": "1",
"nic_code": "I659",
"staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
"负责人"
]
}
]
},
"legalPersonName": "李强",
"regNumber": "1101081949120",
"creditCode": "91110108MA0464P97H",
"province": "北京市",
"regorg": "北京市工商行政管理局海淀分局",
"companyOrgType": "其他有限责任公司分公司",
"revdate": "2010-11-25",
"estiblishTime": "2006-04-13",
"opscope": "计算机软件和系统集成及辅助设备;网络工程;通讯设备的技术开发、咨询;广告设计。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "信息传输、软件和信息技术服务业-软件和信息技术服务业-其他信息技术服务业",
"candate": "",
"district": "海淀区",
"name": "深圳市亿讯时空信息技术有限公司北京分公司",
"base": "bj",
"apprdate": "2006-04-13"
},
"adminPenalty": [
{
"departmentName": "海淀分局",
"reason": "",
"punishNumber": "京工商海处字2010第D2389号",
"type": "逾期年检",
"content": "",
"decisionDate": "2010-08-23",
"legalPersonName": "李强"
}
]
},
{
"executedPerson": [
{
"caseCode": "2014城中执字第00062号",
"partyCardNum": "45252819740****3016",
"pname": "李强",
"caseCreateTime": "2014-02-11",
"execCourtName": "",
"execMoney": 220605
},
{
"caseCode": "2010青执字第00198号",
"partyCardNum": "36042819721****0037",
"pname": "秦学文",
"caseCreateTime": "2010-02-08",
"execCourtName": "",
"execMoney": 444028
}
],
"dishonestExecutedPerson": [
{
"businessentity": "",
"areaname": "广西",
"courtname": "柳州市城中区人民法院",
"unperformPart": "",
"type": "0",
"performedPart": "",
"iname": "李强",
"disrupttypename": "其他有履行能力而拒不履行生效法律文书确定义务",
"casecode": "2014城中执字第00062号",
"cardnum": "4525281974****3016",
"performance": "全部未履行",
"regdate": "2014-02-11",
"duty": "中国农业银行股份有限公司柳州城中支行申请执行李强220604.73元",
"gistunit": "柳州市城中区人民法院",
"publishdate": "2014-06-19",
"gistid": "2010城中民二初字第480号民事判决书"
}
],
"orgName": "深圳市亿讯时空信息技术有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "17.0%",
"subscriptAmt": 170,
"orgHolderName": "李强"
},
"relationship": [
"sh",
"tm"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "1000.000000万人民币",
"reccap": 0,
"city": "深圳市",
"industry_code": "M",
"industry": "科技推广和应用服务业",
"type": "1",
"nic_code": "M7590",
"staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
"董事,总经理"
]
}
]
},
"legalPersonName": "李铭",
"regNumber": "440301103603769",
"creditCode": "91440300786556245H",
"province": "广东省",
"regorg": "福田局",
"companyOrgType": "有限责任公司",
"revdate": "2020-04-07",
"estiblishTime": "2006-03-23",
"opscope": "一般经营项目是:计算机软件和系统集成及辅助设备、网络工程、通讯设备的技术开发、咨询、销售,国内贸易(不含专营、专控、专卖商品),从事货物、技术进出口业务(不含分销、国家专营专控商品);广告业务。,许可经营项目是:",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "科学研究和技术服务业-科技推广和应用服务业-其他科技推广服务业-其他科技推广服务业",
"candate": "2020-04-07",
"district": "福田区",
"name": "深圳市亿讯时空信息技术有限公司",
"base": "gd",
"apprdate": "2008-09-04"
}
},
{
"executedPerson": [
{
"caseCode": "2010青执字第01000号",
"partyCardNum": "452528********3012",
"pname": "李健",
"caseCreateTime": "2010-09-06",
"execCourtName": "",
"execMoney": 283845
},
{
"caseCode": "2010青执字第00188号",
"partyCardNum": "45252819691****3012",
"pname": "李健",
"caseCreateTime": "2010-02-08",
"execCourtName": "",
"execMoney": 308464
}
],
"orgName": "南宁市豆花香食品有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "2003-08-06",
"investRate": "50.0%",
"subscriptAmt": 25,
"orgHolderName": "李强"
},
"relationship": [
"sh"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "50万元人民币",
"reccap": 0,
"city": "南宁市",
"industry_code": "F",
"industry": "零售业",
"type": "1",
"nic_code": "F5227",
"legalPersonName": "李健",
"regNumber": "4501002505675",
"creditCode": "91450100MA5KJ83P3J",
"province": "广西壮族自治区",
"regorg": "南宁市行政审批局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "2007-02-08",
"estiblishTime": "2003-08-06",
"opscope": "豆制品的生产及销售;农副土特产品,日用百货,五金交电的销售。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-零售业-食品、饮料及烟草制品专门零售-烟草制品零售",
"candate": "",
"district": "",
"name": "南宁市豆花香食品有限公司",
"base": "gx",
"apprdate": "2004-06-30"
}
},
{
"executedPerson": [
{
"caseCode": "2010青执字第01000号",
"partyCardNum": "452528********3012",
"pname": "李健",
"caseCreateTime": "2010-09-06",
"execCourtName": "",
"execMoney": 283845
},
{
"caseCode": "2010青执字第00188号",
"partyCardNum": "45252819691****3012",
"pname": "李健",
"caseCreateTime": "2010-02-08",
"execCourtName": "",
"execMoney": 308464
},
{
"caseCode": "2014城中执字第00062号",
"partyCardNum": "45252819740****3016",
"pname": "李强",
"caseCreateTime": "2014-02-11",
"execCourtName": "",
"execMoney": 220605
}
],
"dishonestExecutedPerson": [
{
"businessentity": "",
"areaname": "广西",
"courtname": "柳州市城中区人民法院",
"unperformPart": "",
"type": "0",
"performedPart": "",
"iname": "李强",
"disrupttypename": "其他有履行能力而拒不履行生效法律文书确定义务",
"casecode": "2014城中执字第00062号",
"cardnum": "4525281974****3016",
"performance": "全部未履行",
"regdate": "2014-02-11",
"duty": "中国农业银行股份有限公司柳州城中支行申请执行李强220604.73元",
"gistunit": "柳州市城中区人民法院",
"publishdate": "2014-06-19",
"gistid": "2010城中民二初字第480号民事判决书"
}
],
"orgName": "广西鼎铭房地产置换服务有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "10.87%",
"subscriptAmt": 50,
"orgHolderName": "李强"
},
"relationship": [
"sh",
"tm"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "250万元人民币",
"reccap": 200,
"city": "柳州市",
"industry_code": "I",
"industry": "软件和信息技术服务业",
"type": "1",
"nic_code": "I6513",
"staffList": {
"result": [
{
"name": "李强",
"type": "2",
"typeJoin": [
"监事"
]
}
]
},
"legalPersonName": "李健",
"regNumber": "4502002501968",
"creditCode": "91450200MA5KPNEG3T",
"province": "广西壮族自治区",
"regorg": "柳州市市场监督管理局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "2009-01-04",
"estiblishTime": "2001-04-11",
"opscope": "连锁经营:房地产信息咨询服务,房地产交易居间、代理、行纪;商品信息咨询(不含期货、金融、保险、证券等国家专项规定),商品交易居间、代理、行纪。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "信息传输、软件和信息技术服务业-软件和信息技术服务业-软件开发-应用软件开发",
"candate": "",
"district": "",
"name": "广西鼎铭房地产置换服务有限公司",
"base": "gx",
"apprdate": "2005-09-26"
}
},
{
"orgName": "广西鼎铭装饰工程有限公司",
"pName": "李强",
"stockHolderItem": {
"orgHolderType": "自然人",
"investDate": "",
"investRate": "5.26%",
"subscriptAmt": 30,
"orgHolderName": "李强"
},
"relationship": [
"sh"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "300万元人民币",
"reccap": 0,
"city": "南宁市",
"industry_code": "E",
"industry": "建筑装饰、装修和其他建筑业",
"type": "1",
"nic_code": "E5011",
"legalPersonName": "李健",
"regNumber": "4500002501464",
"creditCode": "914500007479525012",
"province": "广西壮族自治区",
"regorg": "广西壮族自治区市场监督管理局",
"companyOrgType": "有限责任公司(自然人投资或控股)",
"revdate": "2007-09-14",
"estiblishTime": "2003-02-27",
"opscope": "建筑装修装饰工程专业承包(暂定)叁级;五金交电、日用百货、建筑材料、装饰材料、机电产品、汽车配件、摩托车配件的购销。",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "建筑业-建筑装饰、装修和其他建筑业-建筑装饰和装修业-公共建筑装饰和装修",
"candate": "",
"district": "",
"name": "广西鼎铭装饰工程有限公司",
"base": "gx",
"apprdate": "2005-03-10"
}
}
]
}
}

View File

@ -1,150 +0,0 @@
{
"msg": "查询成功",
"code": "0000",
"orderNo": "20241113214538120270654",
"data": {
"total": 4,
"datalist": [
{
"orgName": "厦门市湖里区肖山泗建材店",
"pName": "李金桂",
"relationship": [
"lp"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "",
"reccap": 0,
"city": "厦门市",
"industry_code": "F",
"industry": "批发业",
"type": "1",
"nic_code": "F516",
"legalPersonName": "李金桂",
"regNumber": "350206800393889",
"creditCode": "92350206MA3212DY6N",
"province": "福建省",
"regorg": "厦门市湖里区市场监督管理局",
"companyOrgType": "个体",
"revdate": "2024-09-06",
"estiblishTime": "2018-08-21",
"opscope": "",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-批发业-矿产品、建材及化工产品批发",
"candate": "",
"district": "湖里区",
"name": "厦门市湖里区肖山泗建材店",
"base": "fj",
"apprdate": "2018-08-21"
}
},
{
"orgName": "南安市仑苍巢李水暖配件店",
"pName": "李金桂",
"relationship": [
"lp"
],
"fsource": "1",
"basicInfo": {
"regStatus": "存续(在营、开业、在册)",
"regCapital": "",
"reccap": 0,
"city": "泉州市",
"industry_code": "F",
"industry": "零售业",
"type": "1",
"nic_code": "F5281",
"legalPersonName": "李金桂",
"regNumber": "350583601550067",
"creditCode": "92350583MA34MA8K8Y",
"province": "福建省",
"regorg": "福建省南安市市场监督管理局",
"companyOrgType": "个体",
"revdate": "",
"estiblishTime": "2020-09-08",
"opscope": "",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-零售业-五金、家具及室内装饰材料专门零售-五金零售",
"candate": "",
"district": "南安市",
"name": "南安市仑苍巢李水暖配件店",
"base": "fj",
"apprdate": "2021-03-22"
}
},
{
"orgName": "厦门市湖里区苑熙照建材店",
"pName": "李金桂",
"relationship": [
"lp"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "",
"reccap": 0,
"city": "厦门市",
"industry_code": "F",
"industry": "零售业",
"type": "1",
"nic_code": "F528",
"legalPersonName": "李金桂",
"regNumber": "350206800392843",
"creditCode": "92350206MA320UEM5W",
"province": "福建省",
"regorg": "厦门市湖里区市场监督管理局",
"companyOrgType": "个体",
"revdate": "2024-09-06",
"estiblishTime": "2018-08-17",
"opscope": "",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-零售业-五金、家具及室内装饰材料专门零售",
"candate": "",
"district": "湖里区",
"name": "厦门市湖里区苑熙照建材店",
"base": "fj",
"apprdate": "2018-08-17"
}
},
{
"orgName": "厦门市湖里区镜永捷亦服饰店",
"pName": "李金桂",
"relationship": [
"lp"
],
"fsource": "1",
"basicInfo": {
"regStatus": "吊销,未注销",
"regCapital": "",
"reccap": 0,
"city": "厦门市",
"industry_code": "F",
"industry": "零售业",
"type": "1",
"nic_code": "F523",
"legalPersonName": "李金桂",
"regNumber": "350206800389905",
"creditCode": "92350206MA320JJ58B",
"province": "福建省",
"regorg": "厦门市湖里区市场监督管理局",
"companyOrgType": "个体",
"revdate": "2024-09-06",
"estiblishTime": "2018-08-15",
"opscope": "",
"reccapcur": "人民币",
"regCapitalCurrency": "人民币",
"nic_name": "批发和零售业-零售业-纺织、服装及日用品专门零售",
"candate": "",
"district": "湖里区",
"name": "厦门市湖里区镜永捷亦服饰店",
"base": "fj",
"apprdate": "2018-08-15"
}
}
]
}
}

View File

@ -1,154 +0,0 @@
{
"als_fst_cell_nbank_inteday": "290",
"als_fst_id_nbank_inteday": "138",
"als_lst_cell_nbank_consnum": "1",
"als_lst_cell_nbank_csinteday": "1",
"als_lst_cell_nbank_inteday": "33",
"als_lst_id_nbank_consnum": "1",
"als_lst_id_nbank_csinteday": "1",
"als_lst_id_nbank_inteday": "94",
"als_m12_cell_avg_monnum": "1.20",
"als_m12_cell_caon_allnum": "2",
"als_m12_cell_caon_orgnum": "1",
"als_m12_cell_max_inteday": "128",
"als_m12_cell_max_monnum": "2",
"als_m12_cell_min_inteday": "14",
"als_m12_cell_min_monnum": "0",
"als_m12_cell_nbank_allnum": "6",
"als_m12_cell_nbank_avg_monnum": "1.20",
"als_m12_cell_nbank_ca_allnum": "2",
"als_m12_cell_nbank_ca_orgnum": "1",
"als_m12_cell_nbank_cf_allnum": "4",
"als_m12_cell_nbank_cf_orgnum": "1",
"als_m12_cell_nbank_max_inteday": "128",
"als_m12_cell_nbank_max_monnum": "2",
"als_m12_cell_nbank_min_inteday": "14",
"als_m12_cell_nbank_min_monnum": "0",
"als_m12_cell_nbank_night_allnum": "1",
"als_m12_cell_nbank_night_orgnum": "1",
"als_m12_cell_nbank_orgnum": "2",
"als_m12_cell_nbank_selfnum": "0",
"als_m12_cell_nbank_sloan_allnum": "6",
"als_m12_cell_nbank_sloan_orgnum": "2",
"als_m12_cell_nbank_tot_mons": "5",
"als_m12_cell_nbank_week_allnum": "2",
"als_m12_cell_nbank_week_orgnum": "2",
"als_m12_cell_rel_allnum": "4",
"als_m12_cell_rel_orgnum": "1",
"als_m12_cell_tot_mons": "5",
"als_m12_id_avg_monnum": "1.00",
"als_m12_id_caon_allnum": "2",
"als_m12_id_caon_orgnum": "2",
"als_m12_id_max_inteday": "44",
"als_m12_id_max_monnum": "1",
"als_m12_id_min_inteday": "44",
"als_m12_id_min_monnum": "0",
"als_m12_id_nbank_allnum": "2",
"als_m12_id_nbank_avg_monnum": "1.00",
"als_m12_id_nbank_ca_allnum": "1",
"als_m12_id_nbank_ca_orgnum": "1",
"als_m12_id_nbank_max_inteday": "44",
"als_m12_id_nbank_max_monnum": "1",
"als_m12_id_nbank_min_inteday": "44",
"als_m12_id_nbank_min_monnum": "0",
"als_m12_id_nbank_night_allnum": "0",
"als_m12_id_nbank_night_orgnum": "0",
"als_m12_id_nbank_nsloan_allnum": "1",
"als_m12_id_nbank_nsloan_orgnum": "1",
"als_m12_id_nbank_orgnum": "2",
"als_m12_id_nbank_oth_allnum": "1",
"als_m12_id_nbank_oth_orgnum": "1",
"als_m12_id_nbank_selfnum": "0",
"als_m12_id_nbank_sloan_allnum": "1",
"als_m12_id_nbank_sloan_orgnum": "1",
"als_m12_id_nbank_tot_mons": "2",
"als_m12_id_nbank_week_allnum": "0",
"als_m12_id_nbank_week_orgnum": "0",
"als_m12_id_tot_mons": "2",
"als_m3_cell_avg_monnum": "1.00",
"als_m3_cell_max_inteday": "31",
"als_m3_cell_max_monnum": "1",
"als_m3_cell_min_inteday": "31",
"als_m3_cell_min_monnum": "0",
"als_m3_cell_nbank_allnum": "2",
"als_m3_cell_nbank_avg_monnum": "1.00",
"als_m3_cell_nbank_cf_allnum": "2",
"als_m3_cell_nbank_cf_orgnum": "1",
"als_m3_cell_nbank_max_inteday": "31",
"als_m3_cell_nbank_max_monnum": "1",
"als_m3_cell_nbank_min_inteday": "31",
"als_m3_cell_nbank_min_monnum": "0",
"als_m3_cell_nbank_night_allnum": "1",
"als_m3_cell_nbank_night_orgnum": "1",
"als_m3_cell_nbank_orgnum": "1",
"als_m3_cell_nbank_selfnum": "0",
"als_m3_cell_nbank_sloan_allnum": "2",
"als_m3_cell_nbank_sloan_orgnum": "1",
"als_m3_cell_nbank_tot_mons": "2",
"als_m3_cell_nbank_week_allnum": "1",
"als_m3_cell_nbank_week_orgnum": "1",
"als_m3_cell_rel_allnum": "2",
"als_m3_cell_rel_orgnum": "1",
"als_m3_cell_tot_mons": "2",
"als_m6_cell_avg_monnum": "1.00",
"als_m6_cell_caon_allnum": "2",
"als_m6_cell_caon_orgnum": "1",
"als_m6_cell_max_inteday": "46",
"als_m6_cell_max_monnum": "1",
"als_m6_cell_min_inteday": "31",
"als_m6_cell_min_monnum": "0",
"als_m6_cell_nbank_allnum": "4",
"als_m6_cell_nbank_avg_monnum": "1.00",
"als_m6_cell_nbank_ca_allnum": "2",
"als_m6_cell_nbank_ca_orgnum": "1",
"als_m6_cell_nbank_cf_allnum": "2",
"als_m6_cell_nbank_cf_orgnum": "1",
"als_m6_cell_nbank_max_inteday": "46",
"als_m6_cell_nbank_max_monnum": "1",
"als_m6_cell_nbank_min_inteday": "31",
"als_m6_cell_nbank_min_monnum": "0",
"als_m6_cell_nbank_night_allnum": "1",
"als_m6_cell_nbank_night_orgnum": "1",
"als_m6_cell_nbank_orgnum": "2",
"als_m6_cell_nbank_selfnum": "0",
"als_m6_cell_nbank_sloan_allnum": "4",
"als_m6_cell_nbank_sloan_orgnum": "2",
"als_m6_cell_nbank_tot_mons": "4",
"als_m6_cell_nbank_week_allnum": "2",
"als_m6_cell_nbank_week_orgnum": "2",
"als_m6_cell_rel_allnum": "2",
"als_m6_cell_rel_orgnum": "1",
"als_m6_cell_tot_mons": "4",
"als_m6_id_avg_monnum": "1.00",
"als_m6_id_caon_allnum": "2",
"als_m6_id_caon_orgnum": "2",
"als_m6_id_max_inteday": "44",
"als_m6_id_max_monnum": "1",
"als_m6_id_min_inteday": "44",
"als_m6_id_min_monnum": "0",
"als_m6_id_nbank_allnum": "2",
"als_m6_id_nbank_avg_monnum": "1.00",
"als_m6_id_nbank_ca_allnum": "1",
"als_m6_id_nbank_ca_orgnum": "1",
"als_m6_id_nbank_max_inteday": "44",
"als_m6_id_nbank_max_monnum": "1",
"als_m6_id_nbank_min_inteday": "44",
"als_m6_id_nbank_min_monnum": "0",
"als_m6_id_nbank_night_allnum": "0",
"als_m6_id_nbank_night_orgnum": "0",
"als_m6_id_nbank_nsloan_allnum": "1",
"als_m6_id_nbank_nsloan_orgnum": "1",
"als_m6_id_nbank_orgnum": "2",
"als_m6_id_nbank_oth_allnum": "1",
"als_m6_id_nbank_oth_orgnum": "1",
"als_m6_id_nbank_selfnum": "0",
"als_m6_id_nbank_sloan_allnum": "1",
"als_m6_id_nbank_sloan_orgnum": "1",
"als_m6_id_nbank_tot_mons": "2",
"als_m6_id_nbank_week_allnum": "0",
"als_m6_id_nbank_week_orgnum": "0",
"als_m6_id_tot_mons": "2",
"code": "00",
"flag_applyloanstr": "1",
"flag_datastrategy": "1"
}

View File

@ -1,133 +0,0 @@
{
"code": "00",
"data": {
"tl_id_t11_nbank_org": "1",
"tl_id_m6_nbank_passnum": "2",
"tl_cell_t2_nbank_lendamt": "10",
"tl_cell_t5_nbank_org": "1",
"tl_id_t5_nbank_num": "1",
"tl_id_t0_nbank_org": "1",
"tl_cell_t9_nbank_num": "1",
"tl_id_t7_nbank_org": "1",
"tl_id_m1_nbank_passlendamt": "5",
"tl_cell_m9_nbank_passnum": "2",
"flag_datastrategy": "1",
"tl_cell_m6_nbank_passorg": "1",
"tl_cell_m1_nbank_passorg": "1",
"tl_id_m12_nbank_passorg": "1",
"tl_id_m3_nbank_passnum": "1",
"DataStrategy": {
"strategy_version": "1.0",
"product_type": "",
"strategy_id": "DTA_BR0008250",
"product_name": "预置_借贷行为验证",
"scene": "lend"
},
"tl_id_t6_nbank_lendamt": "9",
"tl_id_t6_nbank_org": "1",
"tl_cell_m12_nbank_passlendamt": "18",
"tl_cell_m3_nbank_passlendamt": "9",
"tl_cell_t7_nbank_lendamt": "9",
"tl_cell_m12_nbank_passnum": "2",
"tl_cell_t2_nbank_num": "2",
"tl_cell_t6_nbank_org": "1",
"tl_cell_t11_nbank_num": "1",
"tl_id_m3_nbank_passlendamt": "9",
"tl_cell_m6_nbank_passnum": "2",
"tl_id_t7_nbank_lendamt": "9",
"tl_cell_t11_nbank_org": "1",
"tl_id_m3_nbank_passorg": "1",
"tl_cell_t8_nbank_num": "1",
"tl_id_t6_nbank_num": "1",
"tl_cell_m12_nbank_passorg": "1",
"tl_id_t6_nbank_reamt": "3",
"tl_id_t7_nbank_reamt": "3",
"tl_id_t3_nbank_num": "2",
"tl_cell_t8_nbank_lendamt": "9",
"tl_id_t9_nbank_org": "1",
"tl_id_t1_nbank_lendamt": "14",
"tl_cell_t7_nbank_org": "1",
"tl_id_t9_nbank_reamt": "3",
"tl_id_t8_nbank_reamt": "3",
"tl_id_t1_nbank_org": "1",
"tl_cell_t3_nbank_num": "2",
"tl_id_t8_nbank_lendamt": "9",
"tl_cell_t11_nbank_lendamt": "5",
"tl_cell_m3_nbank_passorg": "1",
"tl_id_t0_nbank_num": "2",
"tl_cell_t4_nbank_org": "1",
"tl_cell_t0_nbank_num": "2",
"tl_id_t0_nbank_lendamt": "18",
"tl_cell_t1_nbank_org": "1",
"tl_id_t9_nbank_lendamt": "9",
"tl_cell_t9_nbank_lendamt": "9",
"tl_cell_t0_nbank_lendamt": "18",
"tl_id_t1_nbank_num": "2",
"tl_cell_t0_nbank_reamt": "7",
"tl_cell_t1_nbank_reamt": "7",
"tl_id_t5_nbank_lendamt": "9",
"tl_cell_m3_nbank_passnum": "1",
"tl_id_m6_nbank_passlendamt": "10",
"tl_cell_t6_nbank_lendamt": "9",
"tl_id_m1_nbank_passorg": "1",
"tl_cell_t6_nbank_num": "1",
"tl_id_t8_nbank_num": "1",
"tl_id_t4_nbank_org": "1",
"tl_cell_t1_nbank_lendamt": "14",
"tl_cell_t2_nbank_org": "1",
"tl_cell_t3_nbank_lendamt": "10",
"tl_id_t2_nbank_num": "2",
"tl_cell_t5_nbank_num": "1",
"swift_number": "3034309_20241113153507_46522614A19",
"tl_id_t5_nbank_reamt": "3",
"tl_cell_t7_nbank_reamt": "3",
"tl_cell_t9_nbank_org": "1",
"tl_cell_t9_nbank_reamt": "3",
"tl_id_t4_nbank_reamt": "3",
"tl_id_t3_nbank_reamt": "4",
"tl_cell_t8_nbank_reamt": "3",
"tl_cell_t4_nbank_reamt": "3",
"tl_id_t1_nbank_reamt": "7",
"tl_id_t2_nbank_reamt": "4",
"tl_cell_t5_nbank_reamt": "3",
"tl_cell_t3_nbank_reamt": "4",
"tl_cell_t6_nbank_reamt": "3",
"tl_cell_m9_nbank_passorg": "1",
"tl_cell_t2_nbank_reamt": "4",
"tl_cell_m9_nbank_passlendamt": "10",
"tl_id_m12_nbank_passlendamt": "18",
"tl_id_t9_nbank_num": "1",
"tl_id_m9_nbank_passorg": "1",
"tl_id_t0_nbank_reamt": "7",
"tl_id_t2_nbank_lendamt": "10",
"tl_id_t3_nbank_org": "1",
"tl_cell_t4_nbank_num": "1",
"tl_cell_t3_nbank_org": "1",
"tl_cell_m1_nbank_passnum": "1",
"code": "00",
"tl_id_t2_nbank_org": "1",
"tl_id_m12_nbank_passnum": "2",
"tl_cell_t4_nbank_lendamt": "9",
"tl_id_m9_nbank_passlendamt": "10",
"tl_cell_t0_nbank_org": "1",
"tl_id_m9_nbank_passnum": "2",
"tl_id_t3_nbank_lendamt": "10",
"tl_cell_m1_nbank_passlendamt": "5",
"tl_cell_t1_nbank_num": "2",
"tl_id_m6_nbank_passorg": "1",
"tl_id_t11_nbank_lendamt": "5",
"tl_id_t11_nbank_num": "1",
"tl_cell_t5_nbank_lendamt": "9",
"tl_id_t5_nbank_org": "1",
"tl_id_t4_nbank_lendamt": "9",
"tl_cell_t8_nbank_org": "1",
"tl_id_t7_nbank_num": "1",
"tl_cell_m6_nbank_passlendamt": "10",
"tl_id_t4_nbank_num": "1",
"tl_id_m1_nbank_passnum": "1",
"tl_id_t8_nbank_org": "1",
"tl_cell_t7_nbank_num": "1",
"flag_totalloan": "1"
},
"flag_totalloan": "1"
}

View File

@ -1,17 +0,0 @@
{
"code": "100002",
"flag_specialList_c": "0",
"data": {
"code": "100002",
"flag_specialList_c": "0",
"swift_number": "3034309_20241113140028_45772614A19",
"flag_datastrategy": "0",
"DataStrategy": {
"strategy_version": "1.0",
"product_type": "100099",
"strategy_id": "DTA_BR0007511",
"product_name": "预置_特殊名单验证",
"scene": "lend"
}
}
}

View File

@ -0,0 +1,53 @@
# 环境变量配置说明
## 环境变量文件
本项目使用 Vite 的环境变量功能,支持以下环境变量文件:
- `.env`:所有环境都会加载的默认变量
- `.env.development`:开发环境变量(`npm run dev` 时加载)
- `.env.production`:生产环境变量(`npm run build` 时加载)
## 已配置的环境变量
| 变量名 | 说明 | 示例值 |
|--------|------|--------|
| VITE_APP_BASE_URL | API 基础URL | https://www.quannengcha.com |
| VITE_APP_DEBUG | 调试模式 | true/false |
## 在项目中使用环境变量
### 在 Vue 组件中使用
```vue
<script setup>
// 使用 import.meta.env 访问环境变量
const baseUrl = import.meta.env.VITE_APP_BASE_URL
const isDebug = import.meta.env.VITE_APP_DEBUG === 'true'
</script>
```
### 在 JS/TS 文件中使用
```js
// 使用 import.meta.env 访问环境变量
const baseUrl = import.meta.env.VITE_APP_BASE_URL
const isDebug = import.meta.env.VITE_APP_DEBUG === 'true'
// 获取当前环境模式
const mode = import.meta.env.MODE
```
## 获取当前环境
```js
// 获取当前环境模式development、production等
const mode = import.meta.env.MODE
```
## 注意事项
1. 所有环境变量必须以 `VITE_` 开头才能在客户端代码中访问
2. 环境变量默认为字符串类型,需要自行转换为其他类型(如布尔值)
3. 修改环境变量后需要重启开发服务器才能生效
4. 不要在环境变量文件中存储敏感信息如API密钥等

View File

@ -1,15 +0,0 @@
import uni from '@uni-helper/eslint-config'
export default uni(
{
globals: {
uni: true,
wx: true, // 如果您同时使用了微信小程序的全局变量
},
unocss: true,
rules: {
'no-console': 'off', // 关闭 no-console 规则
'no-unused-vars': 'warn',
},
},
)

View File

@ -26,6 +26,7 @@ export default defineManifestConfig({
/* 模块配置 */
modules: {
Payment: {},
Share: {},
},
/* 应用发布信息 */
distribute: {
@ -60,6 +61,19 @@ export default defineManifestConfig({
// #endif
},
// share: {
// weixin: {
// appid: 'wx开头的微信开放平台AppID',
// UniversalLinks: 'https://www.quannengcha.com/app/',
// }
// },
// oauth: {
// weixin: {
// appid: 'wx开头的微信开放平台AppID',
// appsecret: '微信开放平台AppSecret',
// UniversalLinks: 'https://www.quannengcha.com/app/'
// }
// }
},
icons: {
android: {
@ -124,4 +138,24 @@ export default defineManifestConfig({
enable: false,
},
'vueVersion': '3',
/* UTS 插件配置 */
'uts': {
'plugins': {
'webview': {
'version': '1.0.0',
'description': 'Web视图插件支持在App内打开网页',
'platforms': {
'android': {
'appid': '',
'autostart': false
},
'ios': {
'appid': '',
'autostart': false
}
}
}
}
}
})

View File

@ -41,39 +41,42 @@
"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",
"type-check": "vue-tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4020420240722002",
"@dcloudio/uni-app-plus": "3.0.0-4020420240722002",
"@dcloudio/uni-components": "3.0.0-4020420240722002",
"@dcloudio/uni-h5": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-alipay": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-baidu": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-jd": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-lark": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-qq": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-toutiao": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-weixin": "3.0.0-4020420240722002",
"@dcloudio/uni-mp-xhs": "3.0.0-4020420240722002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4020420240722002",
"@dcloudio/uni-app": "3.0.0-4050520250307001",
"@dcloudio/uni-app-harmony": "3.0.0-4050520250307001",
"@dcloudio/uni-app-plus": "3.0.0-4050520250307001",
"@dcloudio/uni-components": "3.0.0-4050520250307001",
"@dcloudio/uni-h5": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-alipay": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-baidu": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-jd": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-lark": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-qq": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-toutiao": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-weixin": "3.0.0-4050520250307001",
"@dcloudio/uni-mp-xhs": "3.0.0-4050520250307001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4050520250307001",
"@rollup/rollup-win32-x64-msvc": "^4.27.4",
"@vant/area-data": "^2.0.0",
"@vueuse/core": "^11.1.0",
"crypto-js": "^4.2.0",
"pinia": "^3.0.1",
"qrcode": "^1.5.4",
"uqrcodejs": "^4.0.7",
"vue": "~3.4.21",
"vue-i18n": "^9.14.1",
"wot-design-uni": "^1.3.12"
},
"devDependencies": {
"@dcloudio/types": "^3.4.12",
"@dcloudio/uni-automator": "3.0.0-4020420240722002",
"@dcloudio/uni-cli-shared": "3.0.0-4020420240722002",
"@dcloudio/uni-stacktracey": "3.0.0-4020420240722002",
"@dcloudio/types": "^3.4.14",
"@dcloudio/uni-automator": "3.0.0-4050520250307001",
"@dcloudio/uni-cli-shared": "3.0.0-4050520250307001",
"@dcloudio/uni-stacktracey": "3.0.0-4050520250307001",
"@dcloudio/uni-vue-devtools": "3.0.0-4020420240722002",
"@dcloudio/vite-plugin-uni": "3.0.0-4020420240722002",
"@dcloudio/vite-plugin-uni": "3.0.0-4050520250307001",
"@iconify-json/carbon": "^1.2.3",
"@mini-types/alipay": "^3.0.14",
"@types/node": "^20.16.12",
@ -89,14 +92,14 @@
"@unocss/eslint-config": "^0.62.4",
"@vue/runtime-core": "^3.5.12",
"@vue/tsconfig": "^0.5.1",
"eslint": "^9.12.0",
"miniprogram-api-typings": "^3.12.3",
"sass": "~1.79.0",
"sass-embedded": "~1.79.0",
"typescript": "~5.5.4",
"unocss": "^0.62.4",
"unplugin-auto-import": "^0.18.3",
"vite": "^5.4.9",
"unplugin-vue-components": "^28.4.1",
"vite": "^5.2.8",
"vue-tsc": "^2.1.6"
}
}

View File

@ -24,6 +24,11 @@ export default defineUniPages({
text: '',
visible: false,
},
{
pagePath: 'pages/agent',
text: '',
visible: false,
},
{
pagePath: 'pages/ai',
text: '',

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,88 @@
<script setup>
import { onLaunch } from '@dcloudio/uni-app'
import { refreshToken, getUserInfo } from '@/api/apis'
import { getAgentInfo } from '@/apis/agent'
onLaunch(() => {
refreshTokenIfNeeded()
getUser()
getAgentInformation()
})
const refreshTokenIfNeeded = async () => {
const token = uni.getStorageSync("token")
const refreshAfter = uni.getStorageSync("refreshAfter")
const accessExpire = uni.getStorageSync("accessExpire")
const currentTime = new Date().getTime()
// token
if (accessExpire) {
const accessExpireInMilliseconds = parseInt(accessExpire) * 1000 //
if (currentTime > accessExpireInMilliseconds) {
return
}
}
// token
if (!token) {
return
}
// refreshAfter refreshAfter
if (refreshAfter) {
const refreshAfterInMilliseconds = parseInt(refreshAfter) * 1000 //
if (currentTime < refreshAfterInMilliseconds) {
return
}
}
// refreshAfter refreshAfter token
try {
const res = await refreshToken()
if (res.code === 200) {
uni.setStorageSync("token", res.data.accessToken)
uni.setStorageSync("refreshAfter", res.data.refreshAfter)
uni.setStorageSync("accessExpire", res.data.accessExpire)
}
} catch (error) {
console.error('刷新token失败', error)
}
}
const getAgentInformation = async () => {
const token = uni.getStorageSync("token")
if (!token) {
return
}
try {
const res = await getAgentInfo()
if (res.code === 200 && res.data) {
//
uni.setStorageSync("agentInfo", {
level: res.data.level,
isAgent: res.data.is_agent, //
status: res.data.status, // 0=1=2=3=
agentID: res.data.agent_id,
mobile: res.data.mobile
})
console.log('代理信息已获取并存入缓存')
}
} catch (error) {
console.error('获取代理信息失败', error)
}
}
const getUser = async () => {
const token = uni.getStorageSync("token")
if (!token) {
return
}
const res = await getUserInfo()
if (res.code === 200) {
console.log(res.data)
uni.setStorageSync("userInfo", res.data.userInfo)
}
}
</script>

View File

@ -119,3 +119,17 @@ export function iapPaymentCallback(data) {
data,
})
}
export function getAgentRevenue() {
return request({
url: '/agent/revenue',
method: 'GET'
})
}
export function refreshToken() {
return request({
url: '/user/getToken',
method: 'POST',
});
}

138
src/apis/agent.js Normal file
View File

@ -0,0 +1,138 @@
// 代理相关API
import request from '@/utils/request'
/**
* 获取代理信息
*/
export const getAgentInfo = () => {
return request({
url: '/agent/info',
method: 'GET'
})
}
/**
* 获取代理佣金列表
* @param {Object} params 查询参数 {page, page_size}
*/
export const getAgentCommission = (params) => {
return request({
url: '/agent/commission',
method: 'GET',
params
})
}
/**
* 获取代理奖励列表
* @param {Object} params 查询参数 {page, page_size}
*/
export const getAgentRewards = (params) => {
return request({
url: '/agent/rewards',
method: 'GET',
params
})
}
/**
* 获取代理状态
*/
export const getAgentStatus = () => {
return request({
url: '/agent/status',
method: 'GET'
})
}
/**
* 代理申请
* @param {Object} data 申请数据 {region, mobile, wechat_id, code, ancestor?}
*/
export const applyAgent = (data) => {
return request({
url: '/agent/apply',
method: 'POST',
data
})
}
/**
* 获取代理会员用户配置
* @param {Object} params 查询参数 {product_id}
*/
export const getAgentMembershipUserConfig = (params) => {
return request({
url: '/agent/membership/user_config',
method: 'GET',
params
})
}
/**
* 保存代理会员用户配置
* @param {Object} data 配置数据
*/
export const saveAgentMembershipUserConfig = (data) => {
return request({
url: '/agent/membership/save_user_config',
method: 'POST',
data
})
}
/**
* 获取产品配置
*/
export const getProductConfig = () => {
return request({
url: '/agent/product_config',
method: 'GET'
})
}
/**
* 生成推广链接
* @param {Object} data 推广数据 {product, price}
*/
export const generatePromotionLink = (data) => {
return request({
url: '/agent/generating_link',
method: 'POST',
data
})
}
/**
* 获取代理收益
*/
export const getAgentRevenue = () => {
return request({
url: '/agent/revenue',
method: 'GET'
})
}
/**
* 代理提现
* @param {Object} data 提现数据 {payee_account, amount, payee_name}
*/
export const agentWithdrawal = (data) => {
return request({
url: '/agent/withdrawal',
method: 'POST',
data
})
}
/**
* 获取提现记录
* @param {Object} params 查询参数 {page, page_size}
*/
export const getWithdrawalRecords = (params) => {
return request({
url: '/agent/withdrawal',
method: 'GET',
params
})
}

View File

@ -3,6 +3,8 @@
}
html {
margin: auto !important;
@apply max-w-lg;
font-size: 4px; // * 方便unocss计算1单位 = 0.25rem = 1px
}
@ -40,3 +42,9 @@ html.dark {
display: none; /* Chrome, Safari, and Edge */
}
.safe-area-top {
padding-top: env(safe-area-inset-top);
}
.safe-area-bottom {
padding-bottom: env(safe-area-inset-bottom);
}

11
src/auto-imports.d.ts vendored
View File

@ -11,6 +11,8 @@ declare global {
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const chatCrypto: typeof import('./utils/chatCrypto.js')['default']
const chatEncrypt: typeof import('./utils/chatEncrypt.js')['default']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
@ -111,6 +113,8 @@ declare global {
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const routerGuard: typeof import('./utils/routerGuard.js')['default']
const setupRouterGuard: typeof import('./utils/routerGuard.js')['setupRouterGuard']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
@ -247,6 +251,7 @@ declare global {
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRouterGuard: typeof import('./composables/useRouterGuard')['useRouterGuard']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
@ -283,6 +288,7 @@ declare global {
const useToggle: typeof import('@vueuse/core')['useToggle']
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUser: typeof import('./composables/useUser.js')['useUser']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
@ -329,6 +335,8 @@ declare module 'vue' {
readonly aesEncrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesEncrypt']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
readonly chatCrypto: UnwrapRef<typeof import('./utils/chatCrypto.js')['default']>
readonly chatEncrypt: UnwrapRef<typeof import('./utils/chatEncrypt.js')['default']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>
@ -429,6 +437,7 @@ declare module 'vue' {
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
readonly setupRouterGuard: UnwrapRef<typeof import('./utils/routerGuard.js')['setupRouterGuard']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
@ -480,7 +489,6 @@ declare module 'vue' {
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
readonly useCount: UnwrapRef<typeof import('./composables/useCount')['useCount']>
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
@ -561,7 +569,6 @@ declare module 'vue' {
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']>
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']>
readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']>
readonly useQuery: UnwrapRef<typeof import('./composables/useQuery')['useQuery']>
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>

36
src/components.d.ts vendored
View File

@ -7,37 +7,27 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AppFooter: typeof import('./components/AppFooter.vue')['default']
AppLogos: typeof import('./components/AppLogos.vue')['default']
HiCounter: typeof import('./components/HiCounter.vue')['default']
InputEntry: typeof import('./components/InputEntry.vue')['default']
LButtonGroup: typeof import('./components/LButtonGroup.vue')['default']
LExpandCollapse: typeof import('./components/LExpandCollapse.vue')['default']
LTabbar: typeof import('./components/LTabbar.vue')['default']
LTable: typeof import('./components/LTable.vue')['default']
LTitle: typeof import('./components/LTitle.vue')['default']
AgentApplicationForm: typeof import('./components/AgentApplicationForm.vue')['default']
EnvDemo: typeof import('./components/EnvDemo.vue')['default']
PriceInputPopup: typeof import('./components/PriceInputPopup.vue')['default']
PrivacyModel: typeof import('./components/PrivacyModel.vue')['default']
QiunDataChartsQiunDataCharts: typeof import('./components/qiun-data-charts/qiun-data-charts.vue')['default']
QiunErrorQiunError: typeof import('./components/qiun-error/qiun-error.vue')['default']
QiunLoadingLoading1: typeof import('./components/qiun-loading/loading1.vue')['default']
QiunLoadingLoading2: typeof import('./components/qiun-loading/loading2.vue')['default']
QiunLoadingLoading3: typeof import('./components/qiun-loading/loading3.vue')['default']
QiunLoadingLoading4: typeof import('./components/qiun-loading/loading4.vue')['default']
QiunLoadingLoading5: typeof import('./components/qiun-loading/loading5.vue')['default']
QiunLoadingQiunLoading: typeof import('./components/qiun-loading/qiun-loading.vue')['default']
QRcode: typeof import('./components/QRcode.vue')['default']
VipBanner: typeof import('./components/VipBanner.vue')['default']
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default']
WdDivider: typeof import('wot-design-uni/components/wd-divider/wd-divider.vue')['default']
WdColPicker: typeof import('wot-design-uni/components/wd-col-picker/wd-col-picker.vue')['default']
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
WdFormItem: typeof import('wot-design-uni/components/wd-form-item/wd-form-item.vue')['default']
WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default']
WdImg: typeof import('wot-design-uni/components/wd-img/wd-img.vue')['default']
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
WdLoadmore: typeof import('wot-design-uni/components/wd-loadmore/wd-loadmore.vue')['default']
WdNavbar: typeof import('wot-design-uni/components/wd-navbar/wd-navbar.vue')['default']
WdNoticeBar: typeof import('wot-design-uni/components/wd-notice-bar/wd-notice-bar.vue')['default']
WdRadio: typeof import('wot-design-uni/components/wd-radio/wd-radio.vue')['default']
WdRadioGroup: typeof import('wot-design-uni/components/wd-radio-group/wd-radio-group.vue')['default']
WdPicker: typeof import('wot-design-uni/components/wd-picker/wd-picker.vue')['default']
WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default']
WdProgress: typeof import('wot-design-uni/components/wd-progress/wd-progress.vue')['default']
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
}
}

View File

@ -0,0 +1,341 @@
<template>
<wd-popup v-model="popupVisible" position="bottom" close-on-click-modal @close="handleClose">
<view class="bg-white rounded-t-lg p-4">
<view class="flex justify-between items-center mb-4">
<text class="text-gray-400" @click="cancel">取消</text>
<text class="text-lg font-medium">申请成为代理</text>
<text class="text-gray-400" @click="cancel">关闭</text>
</view>
<wd-form :model="form" :rules="rules">
<wd-cell-group border>
<!-- 区域选择 -->
<wd-col-picker v-model="region" label="代理区域" label-width="100px" prop="region" placeholder="请选择代理区域"
:columns="columns" :column-change="handleColumnChange" @confirm="handleRegionConfirm"
:display-format="displayFormat" />
<!-- 手机号 -->
<wd-input label="手机号码" label-width="100px" type="number" v-model="form.mobile" prop="mobile"
placeholder="请输入您的手机号" :rules="[
{ required: true, message: '请输入手机号' },
{ required: true, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号' }
]" />
<!-- 验证码 -->
<wd-input label="验证码" label-width="100px" type="number" v-model="form.code" prop="code" placeholder="请输入验证码"
:rules="[{ required: true, message: '请输入验证码' }]" use-suffix-slot>
<template #suffix>
<button class="verify-btn" :disabled="countdown > 0" @click.stop="sendVerifyCode">
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</button>
</template>
</wd-input>
<!-- 微信号 -->
<wd-input label="微信号" label-width="100px" v-model="form.wechat_id" prop="wechat_id" placeholder="请输入您的微信号"
:rules="[{ required: true, message: '请输入微信号' }]" />
</wd-cell-group>
<!-- 同意条款的复选框 -->
<view class="p-4">
<view class="flex items-start">
<wd-checkbox v-model="isAgreed" size="16px" class="flex-shrink-0 mr-2"></wd-checkbox>
<view class="text-xs text-gray-400 leading-tight">
我已阅读并同意
<text class="text-blue-400" @click.stop="toUserAgreement">用户协议</text>
<text class="text-blue-400" @click.stop="toServiceAgreement">信息技术服务合同</text>
<text class="text-blue-400" @click.stop="toAgentManageAgreement">推广方管理制度协议</text>
<view class="text-xs text-gray-400 mt-1">点击勾选即代表您同意上述法律文书的相关条款并签署上述法律文书</view>
<view class="text-xs text-gray-400 mt-1">手机号未在本平台注册账号则申请后将自动生成账号</view>
</view>
</view>
</view>
<view class="p-4">
<wd-button type="primary" block @click="submitForm">提交申请</wd-button>
<wd-button type="default" block class="mt-2" @click="cancel">取消</wd-button>
</view>
</wd-form>
</view>
</wd-popup>
<wd-toast />
</template>
<script setup>
import { ref, computed, watch, onUnmounted } from 'vue'
import { useColPickerData } from '../hooks/useColPickerData'
import { useToast } from 'wot-design-uni'
import { getCode } from '@/api/apis.js' // getCode API
const props = defineProps({
show: {
type: Boolean,
default: false
},
ancestor: {
type: String,
default: ''
}
})
const region = ref([]) //
const regionText = ref('') //
const isAgreed = ref(false) //
//
const displayFormat = (selectedItems) => {
if (selectedItems.length === 0) return ''
return selectedItems.map(item => item.label).join(' ')
}
const emit = defineEmits(['update:show', 'submit', 'close'])
const form = ref({
mobile: '',
code: '',
wechat_id: ''
})
// 使wot-design-uitoast
const toast = useToast()
// region
// watch(region, (newVal) => {
// // region
// if (formRef.value) {
// formRef.value.validate(['region'])
// }
// })
const popupVisible = ref(false)
const countdown = ref(0)
let timer = null
//
const { colPickerData, findChildrenByCode } = useColPickerData()
const columns = ref([
colPickerData.map((item) => {
return {
value: item.value,
label: item.text
}
})
])
// - wd-form使
const rules = {
region: [{
required: true,
message: '请选择代理区域',
validator: (value) => {
// region.valuevalue
if (Array.isArray(region.value) && region.value.length === 3) {
return Promise.resolve()
}
return Promise.reject('请选择完整的省市区')
}
}],
mobile: [
{ required: true, message: '请输入手机号' },
{ required: true, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号' }
],
code: [{ required: true, message: '请输入验证码' }],
wechat_id: [{ required: true, message: '请输入微信号' }]
}
//
const toUserAgreement = () => {
uni.navigateTo({
url: '/pages/agreement?type=user'
})
}
const toServiceAgreement = () => {
uni.navigateTo({
url: '/pages/agreement?type=service'
})
}
const toAgentManageAgreement = () => {
uni.navigateTo({
url: '/pages/agreement?type=manage'
})
}
// show
watch(() => props.show, (newVal) => {
popupVisible.value = newVal
})
// popupVisibleprops.show
watch(() => popupVisible.value, (newVal) => {
emit('update:show', newVal)
})
// Popup
const handleClose = () => {
emit('close')
}
//
const cancel = () => {
popupVisible.value = false
emit('close')
}
//
const handleColumnChange = ({ selectedItem, resolve, finish }) => {
const children = findChildrenByCode(colPickerData, selectedItem.value)
if (children && children.length) {
resolve(children.map(item => ({
label: item.text,
value: item.value
})))
} else {
finish()
}
}
// -
const handleRegionConfirm = ({ value, selectedItems }) => {
//
regionText.value = selectedItems.map(item => item.label).join('-')
console.log('地区选择完成', regionText.value)
}
//
const isPhoneNumberValid = computed(() => {
return /^1[3-9]\d{9}$/.test(form.value.mobile)
})
//
const sendVerifyCode = async () => {
//
if (!form.value.mobile) {
toast.info('请输入手机号')
return
}
if (!isPhoneNumberValid.value) {
toast.info('手机号格式不正确')
return
}
//
getCode({
mobile: form.value.mobile,
actionType: 'agentApply',
}).then((res) => {
if (res.code === 200) {
toast.success('验证码已发送')
//
startCountdown()
} else {
toast.error(res.msg || '发送失败')
}
}).catch((err) => {
toast.error('网络错误')
})
}
//
const startCountdown = () => {
countdown.value = 60
if (timer) clearInterval(timer)
timer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
clearInterval(timer)
timer = null
}
}, 1000)
}
//
onUnmounted(() => {
if (timer) {
clearInterval(timer)
timer = null
}
})
// - 使formRef
const submitForm = () => {
try {
//
if (!Array.isArray(region.value) || region.value.length < 3) {
console.log('区域选择不完整:', region.value)
toast.info('请选择完整的代理区域')
return
}
if (!regionText.value) {
toast.info('请选择代理区域')
return
}
//
if (!form.value.mobile) {
console.log('手机号为空')
toast.info('请输入手机号')
return
}
if (!isPhoneNumberValid.value) {
console.log('手机号格式不正确:', form.value.mobile)
toast.info('手机号格式不正确')
return
}
//
if (!form.value.code) {
console.log('验证码为空')
toast.info('请输入验证码')
return
}
//
if (!form.value.wechat_id) {
console.log('微信号为空')
toast.info('请输入微信号')
return
}
//
if (!isAgreed.value) {
toast.info('请阅读并同意相关协议')
return
}
//
const formData = {
...form.value,
region: regionText.value,
}
console.log('提交的表单数据:', formData)
//
emit('submit', formData)
} catch (error) {
console.error('提交表单过程中出现异常:', error)
toast.error('系统错误,请稍后重试')
}
}
</script>
<style scoped>
.verify-btn {
height: 32px;
padding: 0 12px;
background-color: #3b82f6;
color: white;
border-radius: 4px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
}
.verify-btn[disabled] {
background-color: #a0aec0;
}
</style>

View File

@ -1,25 +0,0 @@
<script lang="ts" setup>
function handleClickGithub() {
if (window?.open) {
window.open('https://github.com/uni-helper/vitesse-uni-app')
}
else {
uni.showToast({
icon: 'none',
title: '请使用浏览器打开',
})
}
}
</script>
<template>
<view text="xl gray4" m-5 flex items-center justify-center gap-3>
<navigator url="/pages/index" open-type="redirect">
<view i-carbon-campsite />
</navigator>
<view cursor-pointer @click="handleClickGithub">
<view i-carbon:logo-github />
</view>
</view>
</template>

View File

@ -1,27 +0,0 @@
<template>
<view inline-flex cursor-default text-2xl font-300>
<view
flex
flex-col
items-center
hover-class="drop-shadow-md drop-shadow-color-green5"
>
<image inline-block h-18 w-18 src="/static/logo.svg" />
<text mt--2 text-green5>
uni-helper
</text>
</view>
<view
text="3xl gray4"
m="x-4 y-auto"
i-carbon-add transform transition-all-500 hover:rotate-135
/>
<view flex flex-col hover-class="drop-shadow-md drop-shadow-color-purple5">
<image inline-block h-18 w-18 src="/static/vite.png" />
<text mt--2 text-purple5>
Vite
</text>
</view>
</view>
</template>

View File

@ -0,0 +1,84 @@
<script setup lang="ts">
// Vue访
const baseUrl = import.meta.env.VITE_APP_BASE_URL
const isDebug = import.meta.env.VITE_APP_DEBUG === 'true'
//
const mode = import.meta.env.MODE
//
function testApiCall() {
// 使API URL
const apiUrl = `${baseUrl}/api/v1/test`
console.log('请求地址:', apiUrl)
// API
uni.showToast({
title: `环境: ${mode}, API: ${apiUrl}`,
icon: 'none'
})
}
</script>
<template>
<view class="env-demo">
<view class="env-info">
<text class="info-title">环境变量信息</text>
<view class="info-item">
<text class="label">基础URL:</text>
<text class="value">{{ baseUrl }}</text>
</view>
<view class="info-item">
<text class="label">调试模式:</text>
<text class="value">{{ isDebug ? '已开启' : '已关闭' }}</text>
</view>
<view class="info-item">
<text class="label">当前环境:</text>
<text class="value">{{ mode }}</text>
</view>
</view>
<button class="test-btn" @click="testApiCall">测试API调用</button>
</view>
</template>
<style>
.env-demo {
padding: 20px;
}
.env-info {
background-color: #f5f5f5;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.info-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
display: block;
}
.info-item {
display: flex;
margin-bottom: 8px;
}
.label {
font-weight: bold;
margin-right: 10px;
width: 80px;
}
.value {
flex: 1;
word-break: break-all;
}
.test-btn {
background-color: #007aff;
color: #ffffff;
}
</style>

View File

@ -1,23 +0,0 @@
<script setup lang="ts">
const { count, inc, dec } = useCount()
</script>
<template>
<view inline-flex m="y-3">
<view class="btn" @click="dec()">
<text i-carbon-subtract />
</view>
<view font="mono" w="15" m-auto inline-block>
{{ count }}
</view>
<view class="btn" @click="inc()">
<text i-carbon-add />
</view>
</view>
</template>
<style>
.btn {
--at-apply: w-8 h-8 flex items-center justify-center rounded-full bg-teal-600 text-white cursor-pointer
}
</style>

View File

@ -1,47 +0,0 @@
<script setup lang="ts">
const name = ref('')
function go() {
if (name.value) {
uni.navigateTo({
url: `/pages/hi?name=${name.value}`,
})
}
}
</script>
<template>
<view>
<view
p="x-4 y-2"
w="250px"
m="t-5 auto"
text="center"
bg="transparent"
border="~ rounded gray-200 dark:gray-700 solid"
outline="none active:none"
box-border
w-full
>
<input
v-model="name"
placeholder="What's your name?"
type="text"
autocomplete="off"
mr-0 w-full
>
</view>
<view>
<button
:disabled="!name"
m="t-3 auto"
m-auto w-120rpx rounded bg-teal-600 px-4 py-1 text-sm text-white
hover-class="bg-teal-700"
@click="go"
>
GO
</button>
</view>
</view>
</template>

View File

@ -1,87 +0,0 @@
<script setup>
// type options props v-model
const props = defineProps({
type: {
type: String,
default: 'purple-pink', //
},
options: {
type: Array,
required: true, //
},
modelValue: {
type: String,
default: '', // v-model
},
})
const emit = defineEmits(['update:modelValue'])
// v-model
const selected = ref(props.modelValue)
// v-model
watch(() => props.modelValue, (newValue) => {
selected.value = newValue
})
// type线
const lineClass = computed(() => {
switch (props.type) {
case 'blue-green':
return 'bg-gradient-to-r from-blue-400 via-green-500 to-teal-500'
case 'orange-yellow':
return 'bg-gradient-to-r from-orange-400 via-yellow-500 to-yellow-600'
case 'red-purple':
return 'bg-gradient-to-r from-red-500 via-purple-500 to-purple-600'
default:
return 'bg-gradient-to-r from-purple-400 via-pink-500 to-red-500'
}
})
// 线
const slideLineStyle = computed(() => {
const index = props.options.findIndex(option => option.value === selected.value)
const buttonWidth = 100 / props.options.length
return {
width: `${buttonWidth}%`,
transform: `translateX(${index * 100}%)`,
}
})
//
function selectOption(option) {
selected.value = option.value
// v-model
emit('update:modelValue', option.value)
}
</script>
<template>
<div class="relative flex">
<div
v-for="(option, index) in options"
:key="index"
class="flex-1 shrink-0 cursor-pointer py-2 text-center text-size-sm font-bold transition-transform duration-200 ease-in-out"
:class="{ 'text-gray-900': selected === option.value, 'text-gray-500': selected !== option.value }"
@click="selectOption(option)"
>
{{ option.label }}
</div>
<div
class="absolute bottom-0 h-[3px] rounded transition-all duration-300"
:style="slideLineStyle"
:class="lineClass"
/>
</div>
</template>
<style scoped>
/* 自定义样式 */
button {
outline: none;
border: none;
cursor: pointer;
}
button:focus {
outline: none;
}
</style>

View File

@ -1,61 +0,0 @@
<script setup>
import { computed, ref, useSlots } from 'vue'
// prop 100
const props = defineProps({
maxLength: {
type: Number,
default: 100,
},
})
//
const isExpanded = ref(false)
// slot
const slots = useSlots()
//
const truncatedContent = computed(() => {
const slotContent = getSlotContent()
return slotContent.length > props.maxLength
? `${slotContent.slice(0, props.maxLength)}...`
: slotContent
})
// slot
function getSlotContent() {
const slotVNode = slots.default ? slots.default()[0] : null
return slotVNode ? slotVNode.children.toString().trim() : '' //
}
// /
function toggleExpand() {
isExpanded.value = !isExpanded.value
}
</script>
<template>
<view>
<!-- 展开/收起按钮 -->
<!-- 展开/收起的内容 -->
<text v-if="isExpanded">
<slot /> <!-- 使用 slot 来展示传递的内容 -->
</text>
<text v-else>
<text>{{ truncatedContent }}</text>
</text>
<text
:title="isExpanded ? '点击收起' : '点击展开'"
class="cursor-pointer text-blue-500"
@click="toggleExpand"
>
{{ isExpanded ? '收起' : '展开' }}
</text>
</view>
</template>
<style scoped>
</style>

View File

@ -1,30 +0,0 @@
<script setup>
const tabbar = ref('index')
const menu = reactive([{ title: '首页', icon: 'home', name: 'index' }, { title: 'AI律师', icon: 'chat', name: 'ai' }, { title: '我的', icon: 'user', name: 'me' }])
function tabChange({ value }) {
uni.switchTab({
url: `/pages/${value}`,
})
}
onShow(() => {
const currentPage = getCurrentPages()[getCurrentPages().length - 1].route
const pageName = currentPage.split('/').pop()
tabbar.value = pageName
})
onMounted(() => {
uni.hideTabBar()
})
</script>
<template>
<wd-tabbar v-model="tabbar" custom-class="qnc-tabbar" shape="round" safe-area-inset-bottom fixed @change="tabChange">
<wd-tabbar-item v-for="(item, index) in menu" :key="index" :name="item.name" :title="item.title" :icon="item.icon" />
</wd-tabbar>
</template>
<style scoped>
:deep(.qnc-tabbar) {
bottom: 16px !important;
}
</style>

View File

@ -1,98 +0,0 @@
<script setup>
import { computed } from 'vue'
// props
const props = defineProps({
data: {
type: Array,
required: true,
},
type: {
type: String,
default: 'purple-pink', //
},
})
// type
const evenClass = computed(() => {
switch (props.type) {
case 'blue-green':
return 'bg-teal-100/40'
// return 'bg-gradient-to-r from-blue-50 via-green-50 to-teal-50'
case 'orange-yellow':
return 'bg-gradient-to-r from-orange-50 via-yellow-50 to-yellow-100'
case 'red-purple':
return 'bg-gradient-to-r from-red-50 via-purple-50 to-purple-100'
default:
return 'bg-gradient-to-r from-purple-50 via-pink-50 to-red-50'
}
})
//
const headerClass = computed(() => {
switch (props.type) {
case 'blue-green':
return 'bg-teal-200'
// return 'bg-gradient-to-r from-blue-200 via-green-200 to-teal-200'
case 'orange-yellow':
return 'bg-gradient-to-r from-orange-200 via-yellow-200 to-yellow-200'
case 'red-purple':
return 'bg-gradient-to-r from-red-200 via-purple-200 to-purple-200'
default:
return 'bg-gradient-to-r from-purple-200 via-pink-200 to-red-200'
}
})
//
function zebraClass(index) {
return index % 2 === 1 ? evenClass.value : ''
}
</script>
<template>
<div class="l-table overflow-x-auto">
<table class="min-w-full border-collapse table-auto text-center text-size-xs">
<thead :class="headerClass">
<tr>
<!-- 插槽渲染表头 -->
<slot name="header" />
</tr>
</thead>
<tbody>
<tr
v-for="(row, index) in data"
:key="index"
:class="zebraClass(index)"
class="border-t"
>
<!-- 插槽渲染每一列的内容 -->
<slot :row="row" />
</tr>
</tbody>
</table>
</div>
</template>
<style scoped>
/* 基础表格样式 */
th {
font-weight: bold;
padding: 12px;
text-align: left;
border: 1px solid #e5e7eb;
}
/* 表格行样式 */
td {
padding: 12px;
border: 1px solid #e5e7eb;
}
table {
width: 100%;
border-spacing: 0;
}
.l-table{
@apply rounded-xl;;
overflow: hidden;
}
</style>

View File

@ -1,58 +0,0 @@
<script setup>
// props
const props = defineProps({
title: String,
type: {
type: String,
default: 'purple-pink', //
},
})
// type
const titleClass = computed(() => {
switch (props.type) {
case 'blue-green':
return 'bg-gradient-to-r from-blue-400 via-green-500 to-teal-500'
case 'orange-yellow':
return 'bg-gradient-to-r from-orange-400 via-yellow-500 to-yellow-600'
case 'red-purple':
return 'bg-gradient-to-r from-red-500 via-purple-500 to-purple-600'
default:
return 'bg-gradient-to-r from-purple-400 via-pink-500 to-red-500'
}
})
// 线
const lineClass = computed(() => {
switch (props.type) {
case 'blue-green':
return 'bg-gradient-to-r from-blue-400 via-green-500 to-teal-500'
case 'orange-yellow':
return 'bg-gradient-to-r from-orange-400 via-yellow-500 to-yellow-600'
case 'red-purple':
return 'bg-gradient-to-r from-red-500 via-purple-500 to-purple-600'
default:
return 'bg-gradient-to-r from-purple-400 via-pink-500 to-red-500'
}
})
</script>
<template>
<div class="relative">
<!-- 标题部分 -->
<div :class="titleClass" class="inline-block rounded-lg px-2 py-1 text-white font-bold shadow-md">
{{ title }}
</div>
<!-- 左上角修饰 -->
<div class="absolute left-0 top-0 h-4 w-4 transform rounded-full bg-white shadow-md -translate-x-2 -translate-y-2" />
<!-- 分割线 -->
<div class="relative mt-1.5">
<div :class="lineClass" class="h-[2px] w-full rounded" />
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,179 @@
<template>
<wd-popup v-model="show" position="bottom" round close-on-click-modal destroy-on-close>
<div class="min-h-[500px] bg-gray-50 text-gray-600">
<div class="h-10 bg-white flex items-center justify-center font-semibold text-lg">设置客户查询价
</div>
<div class="card m-4">
<div class="flex items-center justify-between">
<div class="text-lg">
客户查询价 ()</div>
</div>
<div class="border-b border-gray-200">
<wd-input v-model="price" type="number" label="¥" label-width="28px" size="large"
:placeholder="`${productConfig.price_range_min} - ${productConfig.price_range_max}`"
@blur="onBlurPrice" custom-class="wd-input" />
</div>
<div class="flex items-center justify-between mt-2">
<div>推广收益为<span class="text-orange-500"> {{ promotionRevenue }} </span></div>
<div>我的成本为<span class="text-orange-500"> {{ costPrice }} </span></div>
</div>
</div>
<div class="card m-4">
<div class="text-lg mb-2">收益与成本说明</div>
<div>推广收益 = 客户查询价 - 我的成本</div>
<div>我的成本 = 提价成本 + 底价成本</div>
<div class="mt-1">提价成本超过平台标准定价部分平台会收取部分成本价</div>
<div class="">设定范围<span class="text-orange-500">{{
productConfig.price_range_min }}</span> - <span class="text-orange-500">{{
productConfig.price_range_max }}</span></div>
</div>
<div class="px-4 pb-4">
<wd-button class="w-full" round type="primary" size="large" @click="onConfirm">确认</wd-button>
</div>
</div>
</wd-popup>
<wd-toast />
</template>
<script setup>
import { ref, computed, watch, toRefs } from 'vue'
import { useToast } from 'wot-design-uni'
const props = defineProps({
defaultPrice: {
type: Number,
required: true
},
productConfig: {
type: Object,
required: true
}
})
const { defaultPrice, productConfig } = toRefs(props)
const emit = defineEmits(["change"])
const show = defineModel("show")
const price = ref(null)
const toast = useToast()
watch(show, () => {
price.value = defaultPrice.value
})
const costPrice = computed(() => {
if (!productConfig.value) return 0.00
//
let platformPricing = 0
platformPricing += productConfig.value.cost_price
if (price.value > productConfig.value.p_pricing_standard) {
platformPricing += (price.value - productConfig.value.p_pricing_standard) * productConfig.value.p_overpricing_ratio
}
if (productConfig.value.a_pricing_standard > platformPricing && productConfig.value.a_pricing_end > platformPricing && productConfig.value.a_overpricing_ratio > 0) {
if (price.value > productConfig.value.a_pricing_standard) {
if (price.value > productConfig.value.a_pricing_end) {
platformPricing += (productConfig.value.a_pricing_end - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
} else {
platformPricing += (price.value - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
}
}
}
return safeTruncate(platformPricing)
})
const promotionRevenue = computed(() => {
return safeTruncate(price.value - costPrice.value)
});
//
const validatePrice = (currentPrice) => {
const min = productConfig.value.price_range_min;
const max = productConfig.value.price_range_max;
let newPrice = Number(currentPrice);
let message = '';
//
if (isNaN(newPrice)) {
newPrice = defaultPrice.value;
return { newPrice, message: '输入无效,请输入价格' };
}
//
try {
const priceString = newPrice.toString()
const [_, decimalPart = ""] = priceString.split('.');
console.log(priceString, decimalPart)
// 2
if (decimalPart.length > 2) {
newPrice = parseFloat(safeTruncate(newPrice));
message = '价格已自动格式化为两位小数';
}
} catch (e) {
console.error('价格格式化异常:', e);
}
//
if (newPrice < min) {
message = `价格不能低于 ${min}`;
newPrice = min;
} else if (newPrice > max) {
message = `价格不能高于 ${max}`;
newPrice = max;
}
console.log(newPrice, message)
return { newPrice, message };
}
function safeTruncate(num, decimals = 2) {
if (isNaN(num) || !isFinite(num)) return "0.00";
const factor = 10 ** decimals;
const scaled = Math.trunc(num * factor);
const truncated = scaled / factor;
return truncated.toFixed(decimals);
}
const isManualConfirm = ref(false)
const onConfirm = () => {
if (isManualConfirm.value) return
const { newPrice, message } = validatePrice(price.value)
if (message) {
price.value = newPrice
toast.show(message)
} else {
emit("change", price.value)
show.value = false
}
}
const onBlurPrice = () => {
const { newPrice, message } = validatePrice(price.value)
if (message) {
isManualConfirm.value = true
price.value = newPrice
toast.show(message)
}
setTimeout(() => {
isManualConfirm.value = false
}, 0)
}
</script>
<style lang="scss" scoped>
.wd-input {
display: flex !important;
align-items: center !important;
justify-content: center !important;
:deep(.wd-input__label-inner) {
font-size: 24px !important; /* 增大label字体 */
}
:deep(.wd-input__inner) {
font-size: 24px !important; /* 增大输入框内字体 */
}
:deep(.wd-input) {
height: auto !important; /* 确保高度自适应 */
padding: 8px 0 !important; /* 增加垂直内边距 */
}
}
</style>

View File

@ -51,11 +51,11 @@ onMounted(() => {
</view>
<view class="modal-message">
感谢您使用全能查APP! 我们非常重视您的隐私保护和个人信息保护在您使用全能查APP前请您仔细阅读充分理解
<text class="link" @click="openPage('/pages/userAgreement')">
<text class="link" @click="openPage('/pages/agreement?type=user')">
用户协议
</text>
<text class="link" @click="openPage('/pages/privacyPolicy')">
<text class="link" @click="openPage('/pages/agreement?type=privacy')">
隐私政策
</text>
的各项条款如果您同意请点击下方按钮开始接受我们的服务

545
src/components/QRcode.vue Normal file
View File

@ -0,0 +1,545 @@
<template>
<wd-popup v-model="show" position="bottom" round>
<view class="max-h-[calc(100vh-100px)] m-4">
<view class="p-4 flex justify-center">
<!-- 添加最大高度限制容器 -->
<view class="max-h-[70vh] rounded-xl overflow-hidden">
<canvas canvas-id="posterCanvas" id="posterCanvas" class="rounded-xl shadow"
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }" ref="posterCanvas"></canvas>
</view>
</view>
<view class="divider">分享到好友</view>
<view class="flex items-center justify-around">
<view class="flex flex-col items-center justify-center" @click="savePoster">
<image src="/static/image/icon_share_img.svg" class="w-10 h-10 rounded-full" />
<view class="text-center mt-1 text-gray-600 text-xs">保存图片</view>
</view>
<!-- <view class="flex flex-col items-center justify-center" @click="shareToWechatFriend">
<image src="/static/image/icon_share_wechat.svg" class="w-10 h-10 rounded-full" />
<view class="text-center mt-1 text-gray-600 text-xs">微信好友</view>
</view>
<view class="flex flex-col items-center justify-center" @click="shareToWechatMoments">
<image src="/static/image/icon_share_friends.svg" class="w-10 h-10 rounded-full" />
<view class="text-center mt-1 text-gray-600 text-xs">微信朋友圈</view>
</view> -->
<view class="flex flex-col items-center justify-center" @click="copyUrl">
<image src="/static/image/icon_share_url.svg" class="w-10 h-10 rounded-full" />
<view class="text-center mt-1 text-gray-600 text-xs">复制链接</view>
</view>
</view>
</view>
</wd-popup>
</template>
<script setup>
import { ref, watch, nextTick, computed, onMounted, toRefs, getCurrentInstance } from 'vue';
import UQRCode from 'uqrcodejs';
const props = defineProps({
linkIdentifier: {
type: String,
required: true,
},
mode: {
type: String,
default: "promote", // "promote" | "invitation"
},
});
const { linkIdentifier, mode } = toRefs(props);
const posterCanvas = ref(null); // canvas
const posterGenerated = ref(false); //
const show = defineModel('show');
const instance = getCurrentInstance();
// -
const canvasWidth = ref(300); //
const canvasHeight = ref(500); //
const url = computed(() => {
// uniappURL
const baseUrl = import.meta.env.VITE_APP_SHARE_URL || 'https://www.tianyuandata.com';
return mode.value === "promote"
? `${baseUrl}/agent/promotionInquire/`
: `${baseUrl}/agent/invitationAgentApply/`;
});
const qrcodeImage = ref(null);
const loadPosterImage = async () => {
if (mode.value === "promote") {
return '/static/image/tg_qrcode_1.png';
} else {
return '/static/image/yq_qrcode_1.png';
}
};
onMounted(async () => {
//
qrcodeImage.value = await loadPosterImage();
});
//
const calculateCanvasSize = (imgWidth, imgHeight) => {
//
const sysInfo = uni.getSystemInfoSync();
// 70%
const maxHeight = sysInfo.windowHeight * 0.6;
// 80%
const maxWidth = sysInfo.windowWidth * 0.8;
//
let width = 300;
let height = width * (imgHeight / imgWidth);
//
if (height > maxHeight) {
height = maxHeight;
width = height * (imgWidth / imgHeight);
}
//
if (width > maxWidth) {
width = maxWidth;
height = width * (imgHeight / imgWidth);
}
//
return {
width: Math.floor(width),
height: Math.floor(height)
};
};
//
const generatePoster = async () => {
console.log('[DEBUG] generatePoster: 开始生成海报');
//
if (posterGenerated.value) {
console.log('[DEBUG] generatePoster: 海报已生成,跳过');
return;
}
// DOM
await nextTick();
console.log('[DEBUG] generatePoster: DOM已渲染完成');
try {
//
uni.showLoading({ title: '生成海报中...' });
console.log('[DEBUG] generatePoster: 在APP环境中执行');
const canvasContext = uni.createCanvasContext('posterCanvas', instance.proxy);
if (!canvasContext) {
throw new Error('创建Canvas上下文失败');
}
console.log('[DEBUG] generatePoster: 创建Canvas上下文成功', !!canvasContext);
// -
const posterImagePath = mode.value === "promote"
? '/static/image/tg_qrcode_1.png'
: '/static/image/yq_qrcode_1.png';
console.log('[DEBUG] generatePoster: 开始加载海报图片', posterImagePath);
try {
//
const posterImgInfo = await new Promise((resolve, reject) => {
uni.getImageInfo({
src: posterImagePath,
success: res => {
console.log('[DEBUG] generatePoster: 海报图片加载成功', res);
//
const size = calculateCanvasSize(res.width, res.height);
canvasWidth.value = size.width;
canvasHeight.value = size.height;
console.log('[DEBUG] generatePoster: 计算画布尺寸', size);
resolve(res);
},
fail: err => {
console.error('[DEBUG] generatePoster: 海报图片加载失败', err);
reject(err);
}
});
});
//
canvasContext.clearRect(0, 0, canvasWidth.value, canvasHeight.value);
// -
// canvas
canvasContext.setFillStyle('#ffffff');
canvasContext.fillRect(0, 0, canvasWidth.value, canvasHeight.value);
//
console.log('[DEBUG] generatePoster: 绘制白色背景');
canvasContext.draw(false, () => {
console.log('[DEBUG] generatePoster: 白色背景绘制完成');
//
setTimeout(() => {
console.log('[DEBUG] generatePoster: 开始绘制背景图片', posterImgInfo.path);
canvasContext.drawImage(posterImgInfo.path, 0, 0, canvasWidth.value, canvasHeight.value);
console.log('[DEBUG] generatePoster: 背景图片绘制完成');
canvasContext.draw(true, () => {
console.log('[DEBUG] generatePoster: 背景图绘制完成,准备绘制二维码');
//
setTimeout(async () => {
try {
// - 使
const scaleFactor = canvasWidth.value / posterImgInfo.width;
//
const qrSize = mode.value === "promote"
? Math.min(Math.floor(300 * scaleFactor), canvasWidth.value * 0.4) //
: Math.min(Math.floor(360 * scaleFactor), canvasWidth.value * 0.4);
//
const qrX = mode.value === "promote"
? Math.min(Math.floor(180 * scaleFactor), canvasWidth.value - qrSize)
: Math.min(Math.floor(360 * scaleFactor), canvasWidth.value - qrSize);
//
const qrY = mode.value === "promote"
? canvasHeight.value - Math.min(Math.floor(480 * scaleFactor), canvasHeight.value * 0.4)
: canvasHeight.value - Math.min(Math.floor(1370 * scaleFactor), canvasHeight.value * 0.8);
console.log('[DEBUG] generatePoster: 二维码参数', { qrX, qrY, qrSize, mode: mode.value, scaleFactor });
// 3. 使UQRCode
// uQRCode
const qr = new UQRCode();
//
qr.data = generalUrl();
//
qr.size = qrSize;
//
qr.make();
// QR
//
const drawModules = qr.getDrawModules();
for (const drawModule of drawModules) {
if (drawModule.type === 'tile') {
canvasContext.setFillStyle(drawModule.color);
canvasContext.fillRect(
qrX + drawModule.x,
qrY + drawModule.y,
drawModule.width,
drawModule.height
);
}
}
// 4.
canvasContext.draw(true, () => {
console.log('[DEBUG] generatePoster: 画布完整绘制完成');
posterGenerated.value = true;
uni.hideLoading();
});
} catch (error) {
console.error('[DEBUG] generatePoster: 二维码生成异常', error);
uni.hideLoading();
uni.showToast({
title: '生成二维码失败',
icon: 'none'
});
}
}, 300);
});
}, 300);
});
} catch (error) {
console.error('[DEBUG] generatePoster: APP环境图片处理失败', error);
uni.hideLoading();
uni.showToast({
title: '生成海报失败',
icon: 'none'
});
}
} catch (error) {
console.error('[DEBUG] generatePoster: 生成海报发生未捕获异常', error);
uni.hideLoading();
uni.showToast({
title: '生成海报失败',
icon: 'none'
});
}
};
// show show true
watch(show, (newVal) => {
if (newVal && !posterGenerated.value) {
generatePoster(); //
}
});
//
const savePoster = () => {
if (!posterGenerated.value) {
uni.showToast({
title: '海报生成中,请稍后再试',
icon: 'none'
});
return;
}
uni.canvasToTempFilePath({
canvasId: 'posterCanvas',
width: canvasWidth.value,
height: canvasHeight.value,
destWidth: canvasWidth.value * 2, // canvas 2
destHeight: canvasHeight.value * 2, // canvas 2
success: (res) => {
//
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: (err) => {
console.error('保存失败:', err);
//
if (err.errMsg && err.errMsg.includes('auth deny')) {
uni.showModal({
title: '提示',
content: '需要您授权保存图片到相册',
success: (res) => {
if (res.confirm) {
uni.openSetting();
}
}
});
} else {
uni.showToast({
title: '保存失败',
icon: 'none'
});
}
}
});
},
fail: (err) => {
console.error('Canvas转图片失败:', err);
uni.showToast({
title: '保存失败',
icon: 'none'
});
}
}, instance.proxy);
};
//
const shareToWechatFriend = () => {
if (!posterGenerated.value) {
uni.showToast({
title: '海报生成中,请稍后再试',
icon: 'none'
});
return;
}
uni.canvasToTempFilePath({
canvasId: 'posterCanvas',
width: canvasWidth.value,
height: canvasHeight.value,
destWidth: canvasWidth.value * 2,
destHeight: canvasHeight.value * 2,
success: (res) => {
// #ifdef APP-PLUS
shareWithSystem('WXSceneSession', res.tempFilePath);
// #endif
// #ifndef APP-PLUS
uni.showToast({
title: '分享功能仅支持APP',
icon: 'none'
});
// #endif
},
fail: (err) => {
console.error('Canvas转图片失败:', err);
uni.showToast({
title: '分享准备失败',
icon: 'none'
});
}
}, instance.proxy);
};
//
const shareToWechatMoments = () => {
if (!posterGenerated.value) {
uni.showToast({
title: '海报生成中,请稍后再试',
icon: 'none'
});
return;
}
uni.canvasToTempFilePath({
canvasId: 'posterCanvas',
width: canvasWidth.value,
height: canvasHeight.value,
destWidth: canvasWidth.value * 2,
destHeight: canvasHeight.value * 2,
success: (res) => {
// #ifdef APP-PLUS
shareWithSystem('WXSceneTimeline', res.tempFilePath);
// #endif
// #ifndef APP-PLUS
uni.showToast({
title: '分享功能仅支持APP',
icon: 'none'
});
// #endif
},
fail: (err) => {
console.error('Canvas转图片失败:', err);
uni.showToast({
title: '分享准备失败',
icon: 'none'
});
}
}, instance.proxy);
};
//
const shareWithSystem = (scene, tempFilePath) => {
try {
//
plus.share.getServices((services) => {
const wechatService = services.find((s) => s.id === 'weixin');
if (!wechatService) {
uni.showToast({
title: '未检测到微信应用',
icon: 'none'
});
return;
}
//
wechatService.authorize(() => {
const shareOptions = {
provider: 'weixin',
scene: scene, // WXSceneSessionWXSceneTimeline
type: 2, //
imageUrl: tempFilePath,
title: mode.value === "promote" ? '推广海报' : '邀请海报',
href: generalUrl(),
success: (res) => {
uni.showToast({
title: '分享成功',
icon: 'success'
});
},
fail: (err) => {
console.error('分享失败:', err);
uni.showToast({
title: '分享失败',
icon: 'none'
});
}
};
wechatService.send(shareOptions, () => {
console.log('分享成功');
}, (err) => {
console.error('分享失败:', err);
});
}, (err) => {
console.error('微信认证失败:', err);
uni.showToast({
title: '微信认证失败',
icon: 'none'
});
});
}, (err) => {
console.error('获取分享服务列表失败:', err);
// 使
try {
plus.share.sendWithSystem({
pictures: [tempFilePath]
}, () => {
uni.showToast({
title: '分享成功',
icon: 'success'
});
}, (err) => {
uni.showToast({
title: '分享失败',
icon: 'none'
});
});
} catch (e) {
uni.showToast({
title: '当前设备不支持分享',
icon: 'none'
});
}
});
} catch (error) {
console.error('分享出错:', error);
uni.showToast({
title: '分享失败',
icon: 'none'
});
}
};
const generalUrl = () => {
return url.value + encodeURIComponent(linkIdentifier.value);
};
const copyUrl = () => {
uni.setClipboardData({
data: generalUrl(),
success: () => {
uni.showToast({
title: '链接已复制!',
icon: 'success'
});
}
});
};
</script>
<style lang="scss" scoped>
.divider {
position: relative;
display: flex;
align-items: center;
margin: 16px 0;
color: #969799;
font-size: 14px;
&::before,
&::after {
content: '';
height: 1px;
flex: 1;
background-color: #ebedf0;
}
&::before {
margin-right: 16px;
}
&::after {
margin-left: 16px;
}
}
</style>

View File

@ -0,0 +1,36 @@
<template>
<view class="card mb-4 relative overflow-hidden" @click="goToVip">
<view class="absolute inset-0 bg-gradient-to-r from-yellow-400 to-yellow-300 opacity-40"></view>
<view class="p-2 relative z-10">
<view class="flex justify-between items-center">
<view>
<view class="text-lg font-bold text-yellow-800">会员专享特权</view>
<view class="text-sm text-yellow-700 mt-1">升级VIP获得更多收益</view>
</view>
<view class="bg-yellow-500 px-3 py-1 rounded-full text-white text-sm shadow-sm">
立即查看
</view>
</view>
</view>
<!-- 装饰元素 -->
<view class="absolute -right-4 -top-4 w-16 h-16 bg-yellow-200 rounded-full opacity-60"></view>
<view class="absolute right-5 -bottom-4 w-12 h-12 bg-yellow-100 rounded-full opacity-40"></view>
</view>
</template>
<script setup>
// VIP
const goToVip = () => {
uni.navigateTo({
url: '/pages/agentVip'
})
}
</script>
<style scoped>
.card {
border-radius: 12px;
background-color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
</style>

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,162 +0,0 @@
<template>
<view class="container loading1">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading1',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading1 {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading1 .shape1 {
-webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
animation: animation1shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
@keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
.loading1 .shape2 {
-webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
animation: animation1shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
@keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
.loading1 .shape3 {
-webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
animation: animation1shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
@keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
.loading1 .shape4 {
-webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
animation: animation1shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
@keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
</style>

View File

@ -1,170 +0,0 @@
<template>
<view class="container loading2">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading2',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading2 {
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
.container.loading2 .shape {
border-radius: 5px;
}
.container.loading2{
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading2 .shape1 {
-webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
animation: animation2shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
@keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
.loading2 .shape2 {
-webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
animation: animation2shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
@keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
.loading2 .shape3 {
-webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
animation: animation2shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
@keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
.loading2 .shape4 {
-webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
animation: animation2shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
@keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
</style>

View File

@ -1,173 +0,0 @@
<template>
<view class="container loading3">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading3',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading3 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading3 .shape1 {
border-top-left-radius: 10px;
}
.container.loading3 .shape2 {
border-top-right-radius: 10px;
}
.container.loading3 .shape3 {
border-bottom-left-radius: 10px;
}
.container.loading3 .shape4 {
border-bottom-right-radius: 10px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading3 .shape1 {
-webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
animation: animation3shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
@keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
.loading3 .shape2 {
-webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
animation: animation3shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
@keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
.loading3 .shape3 {
-webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
animation: animation3shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
@keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
.loading3 .shape4 {
-webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
animation: animation3shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
@keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
</style>

View File

@ -1,222 +0,0 @@
<template>
<view class="container loading5">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading5',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading5 .shape {
width: 15px;
height: 15px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading5 .shape1 {
animation: animation5shape1 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
@keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
.loading5 .shape2 {
animation: animation5shape2 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
@keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
.loading5 .shape3 {
animation: animation5shape3 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
@keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
.loading5 .shape4 {
animation: animation5shape4 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
@keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
</style>

View File

@ -1,229 +0,0 @@
<template>
<view class="container loading6">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading6',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading6 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading6 .shape {
width: 12px;
height: 12px;
border-radius: 2px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading6 .shape1 {
-webkit-animation: animation6shape1 2s linear 0s infinite normal;
animation: animation6shape1 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
@keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
.loading6 .shape2 {
-webkit-animation: animation6shape2 2s linear 0s infinite normal;
animation: animation6shape2 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
@keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
.loading6 .shape3 {
-webkit-animation: animation6shape3 2s linear 0s infinite normal;
animation: animation6shape3 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
@keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
.loading6 .shape4 {
-webkit-animation: animation6shape4 2s linear 0s infinite normal;
animation: animation6shape4 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
@keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
</style>

View File

@ -1,36 +0,0 @@
<template>
<view>
<Loading1 v-if="loadingType==1"/>
<Loading2 v-if="loadingType==2"/>
<Loading3 v-if="loadingType==3"/>
<Loading4 v-if="loadingType==4"/>
<Loading5 v-if="loadingType==5"/>
</view>
</template>
<script>
import Loading1 from "./loading1.vue";
import Loading2 from "./loading2.vue";
import Loading3 from "./loading3.vue";
import Loading4 from "./loading4.vue";
import Loading5 from "./loading5.vue";
export default {
components:{Loading1,Loading2,Loading3,Loading4,Loading5},
name: 'qiun-loading',
props: {
loadingType: {
type: Number,
default: 2
},
},
data() {
return {
};
},
}
</script>
<style>
</style>

View File

@ -1,422 +0,0 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 通用配置项
// 主题颜色配置如每个图表类型需要不同主题请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
const cfe = {
//demotype为自定义图表类型
"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
//增加自定义图表类型如果需要categories请在这里加入您的图表类型例如最后的"demotype"
"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
//instance为实例变量承载属性option为eopts承载属性不要删除
"instance": {},
"option": {},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter":{
"tooltipDemo1":function(res){
let result = ''
for (let i in res) {
if (i == 0) {
result += res[i].axisValueLabel + '年销售额'
}
let value = '--'
if (res[i].data !== null) {
value = res[i].data
}
// #ifdef H5
result += '\n' + res[i].seriesName + '' + value + ' 万元'
// #endif
// #ifdef APP-PLUS
result += '<br/>' + res[i].marker + res[i].seriesName + '' + value + ' 万元'
// #endif
}
return result;
},
legendFormat:function(name){
return "自定义图例+"+name;
},
yAxisFormatDemo:function (value, index) {
return value + '元';
},
seriesFormatDemo:function(res){
return res.name + '年' + res.value + '元';
}
},
//这里演示了自定义您的图表类型的option可以随意命名之后在组件上 type="demotype" 后组件会调用这个花括号里的option如果组件上还存在eopts参数会将demotype与eopts中option合并后渲染图表。
"demotype":{
"color": color,
//在这里填写echarts的option即可
},
//下面是自定义配置,请添加项目所需的通用配置
"column": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'bar',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"line": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"area": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"areaStyle": {},
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"pie": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": '50%',
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"ring": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": ['40%', '70%'],
"avoidLabelOverlap": false,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
"labelLine": {
"show": true
},
},
},
"rose": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": "55%",
"center": ['50%', '50%'],
"roseType": 'area',
},
},
"funnel": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item',
"formatter": "{b} : {c}%"
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'funnel',
"left": '10%',
"top": 60,
"bottom": 60,
"width": '80%',
"min": 0,
"max": 100,
"minSize": '0%',
"maxSize": '100%',
"sort": 'descending',
"gap": 2,
"label": {
"show": true,
"position": 'inside'
},
"labelLine": {
"length": 10,
"lineStyle": {
"width": 1,
"type": 'solid'
}
},
"itemStyle": {
"bordercolor": '#fff',
"borderwidth": 1
},
"emphasis": {
"label": {
"fontSize": 20
}
},
"data": [],
},
},
"gauge": {
"color": color,
"tooltip": {
"formatter": '{a} <br/>{b} : {c}%'
},
"seriesTemplate": {
"name": '业务指标',
"type": 'gauge',
"detail": {"formatter": '{value}%'},
"data": [{"value": 50, "name": '完成率'}]
},
},
"candle": {
"xAxis": {
"data": []
},
"yAxis": {},
"color": color,
"title": {
"text": ''
},
"dataZoom": [{
"type": 'inside',
"xAxisIndex": [0, 1],
"start": 10,
"end": 100
},
{
"show": true,
"xAxisIndex": [0, 1],
"type": 'slider',
"bottom": 10,
"start": 10,
"end": 100
}
],
"seriesTemplate": {
"name": '',
"type": 'k',
"data": [],
},
}
}
export default cfe;

View File

@ -1,606 +0,0 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 主题颜色配置如每个图表类型需要不同主题请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
//事件转换函数主要用作格式化x轴为时间轴根据需求自行修改
const formatDateTime = (timeStamp, returnType)=>{
var date = new Date();
date.setTime(timeStamp * 1000);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if(returnType == 'full'){return y + '-' + m + '-' + d + ' '+ h +':' + minute + ':' + second;}
if(returnType == 'y-m-d'){return y + '-' + m + '-' + d;}
if(returnType == 'h:m'){return h +':' + minute;}
if(returnType == 'h:m:s'){return h +':' + minute +':' + second;}
return [y, m, d, h, minute, second];
}
const cfu = {
//demotype为自定义图表类型一般不需要自定义图表类型只需要改根节点上对应的类型即可
"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","mount","bar","area","radar","gauge","candle","mix","tline","tarea","scatter","bubble","demotype"],
"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","山峰图","条状图","区域图","雷达图","仪表盘","K线图","混合图","时间轴折线","时间轴区域","散点图","气泡图","自定义类型"],
//增加自定义图表类型如果需要categories请在这里加入您的图表类型例如最后的"demotype"
//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴矢量x轴类图表没有categories不需要加入categories
"categories":["line","column","mount","bar","area","radar","gauge","candle","mix","demotype"],
//instance为实例变量承载属性不要删除
"instance":{},
//option为opts及eopts承载属性不要删除
"option":{},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter":{
"yAxisDemo1":function(val, index, opts){return val+'元'},
"yAxisDemo2":function(val, index, opts){return val.toFixed(2)},
"xAxisDemo1":function(val, index, opts){return val+'年';},
"xAxisDemo2":function(val, index, opts){return formatDateTime(val,'h:m')},
"seriesDemo1":function(val, index, series, opts){return val+'元'},
"tooltipDemo1":function(item, category, index, opts){
if(index==0){
return '随便用'+item.data+'年'
}else{
return '其他我没改'+item.data+'天'
}
},
"pieDemo":function(val, index, series, opts){
if(index !== undefined){
return series[index].name+''+series[index].data+'元'
}
},
},
//这里演示了自定义您的图表类型的option可以随意命名之后在组件上 type="demotype" 后组件会调用这个花括号里的option如果组件上还存在opts参数会将demotype与opts中option合并后渲染图表。
"demotype":{
//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2
},
}
},
//下面是自定义配置,请添加项目所需的通用配置
"pie":{
"type": "pie",
"color": color,
"padding": [5,5,5,5],
"extra": {
"pie": {
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
}
},
"ring":{
"type": "ring",
"color": color,
"padding": [5,5,5,5],
"rotate": false,
"dataLabel": true,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"title": {
"name": "收益率",
"fontSize": 15,
"color": "#666666"
},
"subtitle": {
"name": "70%",
"fontSize": 25,
"color": "#7cb5ec"
},
"extra": {
"ring": {
"ringWidth":30,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
},
},
"rose":{
"type": "rose",
"color": color,
"padding": [5,5,5,5],
"legend": {
"show": true,
"position": "left",
"lineHeight": 25,
},
"extra": {
"rose": {
"type": "area",
"minRadius": 50,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": false,
"borderWidth": 2,
"borderColor": "#FFFFFF"
},
}
},
"word":{
"type": "word",
"color": color,
"extra": {
"word": {
"type": "normal",
"autoColors": false
}
}
},
"funnel":{
"type": "funnel",
"color": color,
"padding": [15,15,0,15],
"extra": {
"funnel": {
"activeOpacity": 0.3,
"activeWidth": 10,
"border": true,
"borderWidth": 2,
"borderColor": "#FFFFFF",
"fillOpacity": 1,
"labelAlign": "right"
},
}
},
"map":{
"type": "map",
"color": color,
"padding": [0,0,0,0],
"dataLabel": true,
"extra": {
"map": {
"border": true,
"borderWidth": 1,
"borderColor": "#666666",
"fillOpacity": 0.6,
"activeBorderColor": "#F04864",
"activeFillColor": "#FACC14",
"activeFillOpacity": 1
},
}
},
"arcbar":{
"type": "arcbar",
"color": color,
"title": {
"name": "百分比",
"fontSize": 25,
"color": "#00FF00"
},
"subtitle": {
"name": "默认标题",
"fontSize": 15,
"color": "#666666"
},
"extra": {
"arcbar": {
"type": "default",
"width": 12,
"backgroundColor": "#E9E9E9",
"startAngle": 0.75,
"endAngle": 0.25,
"gap": 2
}
}
},
"line":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "straight",
"width": 2,
"activeType": "hollow"
},
}
},
"tline":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": false,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2,
"activeType": "hollow"
},
}
},
"tarea":{
"type": "area",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"area": {
"type": "curve",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": true,
"activeType": "hollow"
},
}
},
"column":{
"type": "column",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"column": {
"type": "group",
"width": 30,
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"mount":{
"type": "mount",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"mount": {
"type": "mount",
"widthRatio": 1.5,
},
}
},
"bar":{
"type": "bar",
"color": color,
"padding": [15,30,0,5],
"xAxis": {
"boundaryGap":"justify",
"disableGrid":false,
"min":0,
"axisLine":false
},
"yAxis": {
},
"legend": {
},
"extra": {
"bar": {
"type": "group",
"width": 30,
"meterBorde": 1,
"meterFillColor": "#FFFFFF",
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"area":{
"type": "area",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"area": {
"type": "straight",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": false,
"activeType": "hollow"
},
}
},
"radar":{
"type": "radar",
"color": color,
"padding": [5,5,5,5],
"dataLabel": false,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"extra": {
"radar": {
"gridType": "radar",
"gridColor": "#CCCCCC",
"gridCount": 3,
"opacity": 0.2,
"max": 200,
"labelShow": true
},
}
},
"gauge":{
"type": "gauge",
"color": color,
"title": {
"name": "66Km/H",
"fontSize": 25,
"color": "#2fc25b",
"offsetY": 50
},
"subtitle": {
"name": "实时速度",
"fontSize": 15,
"color": "#1890ff",
"offsetY": -50
},
"extra": {
"gauge": {
"type": "default",
"width": 30,
"labelColor": "#666666",
"startAngle": 0.75,
"endAngle": 0.25,
"startNumber": 0,
"endNumber": 100,
"labelFormat": "",
"splitLine": {
"fixRadius": 0,
"splitNumber": 10,
"width": 30,
"color": "#FFFFFF",
"childNumber": 5,
"childWidth": 12
},
"pointer": {
"width": 24,
"color": "auto"
}
}
}
},
"candle":{
"type": "candle",
"color": color,
"padding": [15,15,0,15],
"enableScroll": true,
"enableMarkLine": true,
"dataLabel": false,
"xAxis": {
"labelCount": 4,
"itemCount": 40,
"disableGrid": true,
"gridColor": "#CCCCCC",
"gridType": "solid",
"dashLength": 4,
"scrollShow": true,
"scrollAlign": "left",
"scrollColor": "#A6A6A6",
"scrollBackgroundColor": "#EFEBEF"
},
"yAxis": {
},
"legend": {
},
"extra": {
"candle": {
"color": {
"upLine": "#f04864",
"upFill": "#f04864",
"downLine": "#2fc25b",
"downFill": "#2fc25b"
},
"average": {
"show": true,
"name": ["MA5","MA10","MA30"],
"day": [5,10,20],
"color": ["#1890ff","#2fc25b","#facc14"]
}
},
"markLine": {
"type": "dash",
"dashLength": 5,
"data": [
{
"value": 2150,
"lineColor": "#f04864",
"showLabel": true
},
{
"value": 2350,
"lineColor": "#f04864",
"showLabel": true
}
]
}
}
},
"mix":{
"type": "mix",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"disabled": false,
"disableGrid": false,
"splitNumber": 5,
"gridType": "dash",
"dashLength": 4,
"gridColor": "#CCCCCC",
"padding": 10,
"showTitle": true,
"data": []
},
"legend": {
},
"extra": {
"mix": {
"column": {
"width": 20
}
},
}
},
"scatter":{
"type": "scatter",
"color":color,
"padding":[15,15,0,15],
"dataLabel":false,
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
},
"legend": {
},
"extra": {
"scatter": {
},
}
},
"bubble":{
"type": "bubble",
"color":color,
"padding":[15,15,0,15],
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0,
"max":250
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
"data":[{
"min":0,
"max":150
}]
},
"legend": {
},
"extra": {
"bubble": {
"border":2,
"opacity": 0.5,
},
}
}
}
export default cfu;

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,5 +0,0 @@
# uCharts JSSDK说明
1、如不使用uCharts组件可直接引用u-charts.js打包编译后会`自动压缩`,压缩后体积约为`120kb`。
2、如果120kb的体积仍需压缩请手到uCharts官网通过在线定制选择您需要的图表。
3、config-ucharts.js为uCharts组件的用户配置文件升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
4、config-echarts.js为ECharts组件的用户配置文件升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

View File

@ -1,16 +0,0 @@
export function useCount() {
const count = ref(Math.round(Math.random() * 20))
function inc() {
count.value += 1
}
function dec() {
count.value -= 1
}
return {
count,
inc,
dec,
}
}

View File

@ -1,10 +0,0 @@
import type { MaybeRef } from '@vueuse/core'
export function useQuery(key?: MaybeRef<string>) {
const query = ref<AnyObject>({})
onLoad((q) => {
query.value = q || {}
})
const value = computed(() => (key ? query.value[unref(key)] : null))
return { query, value }
}

View File

@ -0,0 +1,38 @@
// 可以将此代码放置于项目src/hooks/useColPickerData.ts中
import { useCascaderAreaData } from '@vant/area-data'
export type CascaderOption = {
text: string
value: string
children?: CascaderOption[]
}
/**
* 使'@vant/area-data'ColPicker组件的数据
* @returns
*/
export function useColPickerData() {
// '@vant/area-data' 数据源
const colPickerData: CascaderOption[] = useCascaderAreaData()
// 根据code查找子节点不传code则返回所有节点
function findChildrenByCode(data: CascaderOption[], code?: string): CascaderOption[] | null {
if (!code) {
return data
}
for (const item of data) {
if (item.value === code) {
return item.children || null
}
if (item.children) {
const childrenResult = findChildrenByCode(item.children, code)
if (childrenResult) {
return childrenResult
}
}
}
return null
}
return { colPickerData, findChildrenByCode }
}

View File

@ -2,8 +2,8 @@
import PrivacyModal from '@/components/PrivacyModel.vue'
const tabbar = ref('index')
const menu = reactive([{ title: '首页', icon: 'home', name: 'index' }, { title: '代理', icon: 'share', name: 'agent' }, { title: 'AI律师', icon: 'user-avatar', name: 'ai' }, { title: '我的', icon: 'user', name: 'me' }])
const menu = reactive([{ title: '首页', icon: 'home', name: 'index' }, { title: 'AI律师', icon: 'chat', name: 'ai' }, { title: '我的', icon: 'user', name: 'me' }])
function tabChange({ value }) {
uni.switchTab({
@ -25,9 +25,14 @@ onMounted(() => {
})
function toComplaint() {
uni.navigateTo({
url: '/pages/complaint',
})
// 使plus.runtime.openURL
// #ifdef APP-PLUS
plus.runtime.openURL('https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9');
// #endif
// #ifdef H5
window.location.href = 'https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9';
// #endif
}
</script>
@ -40,13 +45,18 @@ export default {
</script>
<template>
<slot />
<view class=" min-h-screen from-blue-100 to-white bg-gradient-to-b min-h-screen flex flex-col flex-1 pb-16 box-border">
<slot />
</view>
<view>
<wd-tabbar v-model="tabbar" custom-class="qnc-tabbar" shape="round" safe-area-inset-bottom fixed @change="tabChange">
<wd-tabbar-item v-for="(item, index) in menu" :key="index" :name="item.name" :title="item.title" :icon="item.icon" />
<wd-tabbar v-model="tabbar" custom-class="qnc-tabbar" shape="round" safe-area-inset-bottom fixed
@change="tabChange">
<wd-tabbar-item v-for="(item, index) in menu" :key="index" :name="item.name" :title="item.title"
:icon="item.icon" />
</wd-tabbar>
</view>
<view class="fixed bottom-24 right-4 z-1000 flex items-center rounded-3xl from-red-500 to-red-400 bg-gradient-to-b px-2 py-1 text-center text-white shadow-2xl">
<view
class="fixed bottom-24 right-4 z-1000 flex items-center rounded-3xl from-red-500 to-red-400 bg-gradient-to-b px-2 py-1 text-center text-white shadow-2xl">
<wd-icon name="warning" class="mr-1" size="18px" />
<view class="text-xs" @click="toComplaint">
投诉
@ -59,4 +69,6 @@ export default {
:deep(.qnc-tabbar) {
bottom: 16px !important;
}
</style>

View File

@ -2,10 +2,15 @@ import { createSSRApp } from 'vue'
import App from './App.vue'
import 'uno.css'
import '@/app.scss'
import { setupRouterGuard } from '@/utils/routerGuard'
export function createApp() {
const app = createSSRApp(App)
// 初始化路由守卫
setupRouterGuard()
return {
app,
app
}
}

View File

@ -16,7 +16,8 @@
"delay": 0
},
"modules": {
"Payment": {}
"Payment": {},
"Share": {}
},
"distribute": {
"android": {
@ -111,5 +112,23 @@
"h5": {
"darkmode": false,
"themeLocation": "theme.json"
},
"uts": {
"plugins": {
"webview": {
"version": "1.0.0",
"description": "Web视图插件支持在App内打开网页",
"platforms": {
"android": {
"appid": "",
"autostart": false
},
"ios": {
"appid": "",
"autostart": false
}
}
}
}
}
}

View File

@ -3,42 +3,56 @@
{
"path": "pages/index",
"type": "home",
"layout": "home",
"style": {
"navigationBarTextStyle": "white",
"transparentTitle": "always"
}
},
{
"path": "pages/agent",
"type": "page",
"layout": "home"
},
{
"path": "pages/agentVip",
"type": "page",
"layout": "page",
"title": "代理会员",
"agent": true,
"auth": true
},
{
"path": "pages/agentVipConfig",
"type": "page",
"layout": "page",
"title": "会员代理报告配置",
"agent": true,
"auth": true
},
{
"path": "pages/agreement",
"type": "page"
},
{
"path": "pages/ai",
"type": "page",
"layout": "home"
},
{
"path": "pages/authorization",
"path": "pages/invitation",
"type": "page",
"layout": "page",
"title": "授权书"
"title": "邀请下级",
"auth": true,
"agent": true
},
{
"path": "pages/complaint",
"path": "pages/invitationAgentApply",
"type": "page",
"layout": "page",
"title": "投诉服务"
},
{
"path": "pages/example copy",
"type": "page",
"layout": "page",
"title": "报告示例"
},
{
"path": "pages/example",
"type": "page",
"layout": "page",
"title": "示例报告"
},
{
"path": "pages/inquire",
"type": "page",
"layout": "page",
"title": "报告查询"
"title": "代理申请",
"auth": true
},
{
"path": "pages/login",
@ -52,52 +66,55 @@
"layout": "home"
},
{
"path": "pages/pay",
"path": "pages/promote",
"type": "page",
"layout": "page",
"title": "全能查收款"
"title": "推广",
"agent": true,
"auth": true
},
{
"path": "pages/payb",
"path": "pages/promoteDetails",
"type": "page",
"layout": "page",
"title": "全能查收款"
},
{
"path": "pages/privacyPolicy",
"type": "page",
"layout": "page",
"title": "隐私政策"
"title": "直推报告",
"agent": true,
"auth": true
},
{
"path": "pages/queryHistory",
"type": "page",
"layout": "page",
"title": "历史报告"
"title": "历史报告",
"auth": true
},
{
"path": "pages/result copy",
"path": "pages/rewardsDetails",
"type": "page",
"layout": "page",
"title": "报告结果"
"title": "收益明细",
"agent": true,
"auth": true
},
{
"path": "pages/result",
"type": "page",
"layout": "page",
"title": "报告结果"
"path": "pages/vip",
"type": "page"
},
{
"path": "pages/service",
"path": "pages/withdraw",
"type": "page",
"layout": "page",
"title": "客户服务"
"title": "提现",
"auth": true,
"agent": true
},
{
"path": "pages/userAgreement",
"path": "pages/withdrawDetails",
"type": "page",
"layout": "page",
"title": "用户协议"
"title": "提现记录",
"auth": true,
"agent": true
}
],
"globalStyle": {
@ -121,6 +138,11 @@
"text": "",
"visible": false
},
{
"pagePath": "pages/agent",
"text": "",
"visible": false
},
{
"pagePath": "pages/ai",
"text": "",

249
src/pages/agent.vue Normal file
View File

@ -0,0 +1,249 @@
<script setup>
import { ref, computed } from 'vue'
import { getAgentRevenue } from '@/api/apis'
//
const dateRangeMap = {
today: 'today',
week: 'last7d',
month: 'last30d'
}
//
const promoteDateOptions = [
{ label: '今日', value: 'today' },
{ label: '近7天', value: 'week' },
{ label: '近1月', value: 'month' }
]
const selectedPromoteDate = ref('today')
//
const activeDateOptions = [
{ label: '今日', value: 'today' },
{ label: '近7天', value: 'week' },
{ label: '近1月', value: 'month' }
]
const selectedActiveDate = ref('today')
const data = ref(null)
//
const currentPromoteData = computed(() => {
const range = dateRangeMap[selectedPromoteDate.value]
return data.value?.direct_push?.[range] || { commission: 0, report: 0 }
})
//
const currentActiveData = computed(() => {
const range = dateRangeMap[selectedActiveDate.value]
return data.value?.active_reward?.[range] || {
active_reward: 0,
sub_promote_reward: 0,
sub_upgrade_reward: 0,
sub_withdraw_reward: 0
}
})
const getData = async () => {
try {
const res = await getAgentRevenue()
if (res.code === 200) {
data.value = res.data
}
} catch (error) {
console.error(error)
}
}
onBeforeMount(() => {
if (uni.getStorageSync('token')) {
getData()
}
})
//
function goToPromoteDetail() {
uni.navigateTo({
url: '/pages/promoteDetails'
})
}
function goToActiveDetail() {
uni.navigateTo({
url: '/pages/rewardsDetails'
})
}
function toWithdraw() {
uni.navigateTo({
url: '/pages/withdraw'
})
}
function toWithdrawDetails() {
uni.navigateTo({
url: '/pages/withdrawDetails'
})
}
</script>
<template>
<view class="safe-area-top p-4 min-h-screen">
<!-- 资产卡片 -->
<view class="rounded-xl shadow-lg mb-4 bg-gradient-to-r from-blue-50/70 to-blue-100/50 p-6">
<view class="flex justify-between items-center mb-3">
<view class="flex items-center">
<wd-icon name="balance-pay" class="text-blue-500 text-xl mr-2" />
<text class="text-lg font-bold text-gray-800">余额</text>
</view>
<text class="text-3xl text-blue-600 font-bold">¥ {{ (data?.balance || 0).toFixed(2) }}</text>
</view>
<view class="text-sm text-gray-500 mb-2">累计收益¥ {{ (data?.total_earnings || 0).toFixed(2) }}</view>
<view class="text-sm text-gray-500 mb-6">冻结余额¥ {{ (data?.frozen_balance || 0).toFixed(2) }}</view>
<view class="grid grid-cols-2 gap-3">
<view @click="toWithdraw"
class="bg-gradient-to-r from-blue-500 to-blue-400 text-white rounded-full py-2 px-4 shadow-md flex items-center justify-center">
<wd-icon name="gold-coin" class="mr-1" />
<text>提现</text>
</view>
<view @click="toWithdrawDetails"
class="bg-white/90 text-gray-600 border border-gray-200/50 rounded-full py-2 px-4 shadow-sm flex items-center justify-center">
<wd-icon name="notes" class="mr-1" />
<text>提现记录</text>
</view>
</view>
</view>
<!-- 直推报告收益 -->
<view class="rounded-xl shadow-lg mb-4 bg-gradient-to-r from-blue-50/40 to-cyan-50/50 p-6">
<view class="flex justify-between items-center mb-4">
<view class="flex items-center">
<wd-icon name="balance-list" class="text-blue-400 text-xl mr-2" />
<text class="text-lg font-bold text-gray-800">直推报告收益</text>
</view>
<view class="text-right">
<text class="text-2xl text-blue-600 font-bold">¥ {{ (data?.direct_push?.total_commission || 0).toFixed(2)
}}</text>
<view class="text-sm text-gray-500 mt-1">有效报告 {{ data?.direct_push?.total_report || 0 }} </view>
</view>
</view>
<!-- 日期选择 -->
<view class="grid grid-cols-3 gap-2 mb-6">
<view v-for="item in promoteDateOptions" :key="item.value" @click="selectedPromoteDate = item.value" :class="[
'rounded-full transition-all py-1 px-4 text-sm',
selectedPromoteDate === item.value
? 'bg-blue-500 text-white shadow-md'
: 'bg-white/90 text-gray-600 border border-gray-200/50'
]">
{{ item.label }}
</view>
</view>
<view class="grid grid-cols-2 gap-4 mb-6">
<view class="bg-blue-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="gold-coin" class="mr-1" />
<text>本日收益</text>
</view>
<text class="text-xl text-blue-600 font-bold mt-1">¥ {{ currentPromoteData.commission?.toFixed(2) || '0.00'
}}</text>
</view>
<view class="bg-blue-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="description" class="mr-1" />
<text>有效报告</text>
</view>
<text class="text-xl text-blue-600 font-bold mt-1">{{ currentPromoteData.report || 0 }} </text>
</view>
</view>
<view class="flex items-center justify-between text-blue-500 text-sm font-semibold" @click="goToPromoteDetail">
<text>查看收益明细</text>
<text class="text-lg"></text>
</view>
</view>
<!-- 活跃下级奖励 -->
<view class="rounded-xl shadow-lg bg-gradient-to-r from-green-50/40 to-cyan-50/30 p-6">
<view class="flex justify-between items-center mb-4">
<view class="flex items-center">
<wd-icon name="friends" class="text-green-500 text-xl mr-2" />
<text class="text-lg font-bold text-gray-800">活跃下级奖励</text>
</view>
<view class="text-right">
<text class="text-2xl text-green-600 font-bold">¥ {{ (data?.active_reward?.total_reward || 0).toFixed(2)
}}</text>
<view class="text-sm text-gray-500 mt-1">活跃下级 0 </view>
</view>
</view>
<!-- 日期选择 -->
<view class="grid grid-cols-3 gap-2 mb-6">
<view v-for="item in activeDateOptions" :key="item.value" @click="selectedActiveDate = item.value" :class="[
'rounded-full transition-all py-1 px-4 text-sm',
selectedActiveDate === item.value
? 'bg-green-500 text-white shadow-md'
: 'bg-white/90 text-gray-600 border border-gray-200/50'
]">
{{ item.label }}
</view>
</view>
<view class="grid grid-cols-2 gap-2 mb-6">
<view class="bg-green-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="medal" class="mr-1" />
<text>本日奖励</text>
</view>
<text class="text-xl text-green-600 font-bold mt-1">¥ {{ (currentActiveData.active_reward || 0).toFixed(2)
}}</text>
</view>
<view class="bg-green-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="discount" class="mr-1" />
<text>下级推广奖励</text>
</view>
<text class="text-xl text-green-600 font-bold mt-1">¥ {{ (currentActiveData.sub_promote_reward ||
0).toFixed(2) }}</text>
</view>
<view class="bg-green-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="contact" class="mr-1" />
<text>新增活跃奖励</text>
</view>
<text class="text-xl text-green-600 font-bold mt-1">¥ {{ (currentActiveData.sub_upgrade_reward ||
0).toFixed(2) }}</text>
</view>
<view class="bg-green-50/60 p-3 rounded-lg backdrop-blur-sm">
<view class="flex items-center text-sm text-gray-500">
<wd-icon name="fire" class="mr-1" />
<text>下级转化奖励</text>
</view>
<text class="text-xl text-green-600 font-bold mt-1">¥ {{ (currentActiveData.sub_withdraw_reward ||
0).toFixed(2) }}</text>
</view>
</view>
<view class="flex items-center justify-between text-green-500 text-sm font-semibold" @click="goToActiveDetail">
<text>查看奖励明细</text>
<text class="text-lg"></text>
</view>
</view>
</view>
</template>
<style>
button {
transition: all 0.2s ease;
}
button:hover {
transform: translateY(-1px);
}
</style>
<route lang="json">{
"layout": "home"
}</route>

63
src/pages/agentVip.vue Normal file
View File

@ -0,0 +1,63 @@
<template>
<view class="relative">
<image class="w-full" src="/static/image/vip_bg.png" mode="widthFix" />
<view @click="toService" class="service-btn">
点击马上报名
</view>
</view>
</template>
<script setup>
function toService() {
// 使plus.runtime.openURL
// #ifdef APP-PLUS
plus.runtime.openURL('https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9');
// #endif
// #ifdef H5
window.location.href = 'https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9';
// #endif
// #ifdef MP
uni.navigateTo({
url: '/pages/agreement?url=' + encodeURIComponent('https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9')
});
// #endif
}
</script>
<style lang="scss" scoped>
.relative {
position: relative;
width: 100%;
height: 100%;
}
.service-btn {
position: absolute;
left: 50%;
bottom: 600rpx;
transform: translateX(-50%);
background: linear-gradient(to right, #2d3748, #000000, #2d3748);
padding: 10rpx 20rpx;
border-radius: 16rpx;
color: #ffffff;
font-size: 48rpx;
font-weight: bold;
box-shadow: 0 0 30rpx rgba(255, 255, 255, 0.3);
transition: transform 0.3s;
&:active {
transform: translateX(-50%) scale(1.05);
}
}
</style>
<route lang="json">
{
"layout": "page",
"title": "代理会员",
"agent": true,
"auth": true
}
</route>

View File

@ -0,0 +1,504 @@
<template>
<view class="p-4 mx-auto min-h-screen">
<!-- 标题部分 -->
<view class="card mb-4 p-4 bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg shadow-lg text-white">
<text class="text-2xl font-extrabold mb-2 block">专业报告定价配置</text>
<text class="opacity-90 block">请选择报告类型并设置定价策略助您实现精准定价</text>
</view>
<view class="mb-4 bg-white rounded-lg overflow-hidden px-4 flex items-center justify-between">
<span class="text-blue-600 font-medium text-sm">📝 选择报告</span>
<wd-picker custom-class="flex-1" v-model="selectedReportText" :columns="reportOptions" title="选择报告类型"
@confirm="onConfirm" />
</view>
<view v-if="selectedReportText" class="space-y-6">
<!-- 配置卡片 -->
<view class="card">
<!-- 当前报告标题 -->
<view class="flex items-center mb-6">
<text class="text-xl font-semibold text-gray-800">
{{ selectedReportText }}配置
</text>
</view>
<!-- 显示当前产品的基础成本信息 -->
<view v-if="productConfigData && productConfigData.cost_price"
class="px-4 py-2 mb-4 bg-gray-50 border border-gray-200 rounded-lg shadow-sm">
<text class="text-lg font-semibold text-gray-700 block">报告基础配置信息</text>
<view class="mt-1 text-sm text-gray-600">
<text class="block">基础成本价<text class="font-medium">{{ productConfigData.cost_price }}</text> </text>
<text class="block">最高设定金额上限<text class="font-medium">{{ productConfigData.price_range_max }}</text>
</text>
<text class="block">最高设定比例上限<text class="font-medium">{{ priceRatioMax }}</text> %</text>
</view>
</view>
<!-- 分隔线 -->
<view class="my-6 flex items-center justify-center">
<view class="bg-gray-200 h-px flex-1"></view>
<text class="mx-2 text-gray-400 text-sm">成本策略配置</text>
<view class="bg-gray-200 h-px flex-1"></view>
</view>
<!-- 表单部分 -->
<wd-form>
<!-- 加价金额 -->
<wd-form-item label="加价金额" prop="price_increase_amount">
<wd-input v-model="configData.price_increase_amount" type="number" placeholder="0"
@blur="validateDecimal('price_increase_amount')" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示最大加价金额为{{ priceIncreaseAmountMax }}</text>
<text class="block">说明加价金额是在基础成本价上增加的额外费用决定下级报告的最低定价您将获得所有输入的金额利润</text>
</view>
<!-- 分隔线 -->
<view class="my-6 flex items-center justify-center">
<view class="bg-gray-200 h-px flex-1"></view>
<text class="mx-2 text-gray-400 text-sm">定价策略配置</text>
<view class="bg-gray-200 h-px flex-1"></view>
</view>
<!-- 定价区间最低 -->
<wd-form-item label="定价区间最低" prop="price_range_from">
<wd-input v-model="configData.price_range_from" type="number" placeholder="0"
@blur="() => { validateDecimal('price_range_from'); validateRange(); }" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示定价区间最低金额不能低于基础最低 {{ productConfigData?.price_range_min || 0 }} + 加价金额</text>
<text class="block">说明设定的定价区间最低金额为定价区间的起始值若下级设定的报告金额在区间内则区间内部分将按比例获得收益</text>
</view>
<!-- 定价区间最高 -->
<wd-form-item label="定价区间最高" prop="price_range_to">
<wd-input v-model="configData.price_range_to" type="number" placeholder="0"
@blur="() => { validateDecimal('price_range_to'); validateRange(); }" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示定价区间最高金额不能超过上限{{ productConfigData?.price_range_max || 0 }}和大于定价区间最低金额{{
priceIncreaseMax
}}</text>
<text class="block">说明设定的定价区间最高金额为定价区间的结束值若下级设定的报告金额在区间内则区间内部分将按比例获得收益</text>
</view>
<!-- 收取比例 -->
<wd-form-item label="收取比例" prop="price_ratio">
<wd-input v-model="configData.price_ratio" type="number" placeholder="0" @blur="validateRatio" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示最大收取比例为{{ priceRatioMax }}%</text>
<text class="block">说明收取比例表示对定价区间内即报告金额超过最低金额小于最高金额的部分的金额按此比例进行利润分成</text>
</view>
</wd-form>
</view>
<!-- 保存按钮 -->
<button type="primary" class="bg-blue-500 text-white py-1 rounded-xl w-full" @click="handleSubmit">
保存当前报告配置
</button>
</view>
<!-- 未选择提示 -->
<view v-else class="text-center py-12">
<text class="text-gray-400 text-4xl block mb-4"></text>
<text class="text-gray-500 block">请先选择需要配置的报告类型</text>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { getAgentMembershipUserConfig, saveAgentMembershipUserConfig } from '@/apis/agent'
//
const reportOptions = [
{ label: '人事背调', value: 1 },
{ label: '老板企业报告', value: 2 },
{ label: '家政风险', value: 3 },
{ label: '婚恋风险', value: 4 },
{ label: '贷前背调', value: 5 },
{ label: '租赁风险', value: 6 },
{ label: '个人风险', value: 7 },
]
//
const showPicker = ref(false)
const selectedReportId = ref(1)
const selectedReportText = ref('人事背调')
const configData = ref({})
const productConfigData = ref({})
const priceIncreaseMax = ref(null)
const priceIncreaseAmountMax = ref(null)
const priceRatioMax = ref(null)
const rangeError = ref(false)
const ratioError = ref(false)
const increaseError = ref(false)
//
const validateDecimal = (field) => {
console.log(`validateDecimal开始: field=${field}, 值=${configData.value[field]}`)
const value = configData.value[field]
if (value === null || value === undefined) {
console.log(`validateDecimal: ${field}为空,退出验证`)
return
}
const numValue = Number(value)
if (isNaN(numValue)) {
console.log(`validateDecimal: ${field}无法转换为数字设置为null`)
configData.value[field] = null
return
}
const fixedValue = parseFloat(numValue.toFixed(2))
console.log(`validateDecimal: ${field}原值=${numValue},处理后=${fixedValue}`)
configData.value[field] = fixedValue
if (field === 'price_increase_amount') {
console.log(`validateDecimal: 检查加价金额上限 ${fixedValue} vs ${priceIncreaseAmountMax.value}`)
if (fixedValue > priceIncreaseAmountMax.value) {
configData.value[field] = priceIncreaseAmountMax.value
console.log(`validateDecimal: 加价金额超过上限,已修正为${priceIncreaseAmountMax.value}`)
uni.showToast({
title: `加价金额最大为${priceIncreaseAmountMax.value}`,
icon: 'none'
})
increaseError.value = true
setTimeout(() => {
increaseError.value = false
}, 2000)
} else {
increaseError.value = false
}
//
validateRange()
}
console.log(`validateDecimal结束: ${field}最终值=${configData.value[field]}`)
}
//
const validateRange = () => {
console.log('validateRange开始:',
`最低=${configData.value.price_range_from}`,
`最高=${configData.value.price_range_to}`)
// if (configData.value.price_range_from === null || configData.value.price_range_to === null) {
// console.log('validateRange: null退')
// rangeError.value = false
// return
// }
if (isNaN(configData.value.price_range_from) || isNaN(configData.value.price_range_to)) {
console.log('validateRange: 价格区间值非数字,退出验证')
return
}
const additional = configData.value.price_increase_amount || 0
console.log(`validateRange: 加价金额=${additional}`)
const minAllowed = parseFloat(
(Number(productConfigData.value.cost_price) + Number(additional)).toFixed(2)
) // 使
const maxAllowed = productConfigData.value.price_range_max // 使
console.log(`validateRange: 最低允许=${minAllowed}, 最高允许=${maxAllowed}`)
//
if (configData.value.price_range_from < minAllowed) {
console.log(`validateRange: 定价区间最低金额(${configData.value.price_range_from})小于允许最低值(${minAllowed}),进行修正`)
configData.value.price_range_from = minAllowed
uni.showToast({
title: `定价区间最低金额不能低于成本价 ${minAllowed}`,
icon: 'none'
})
rangeError.value = true
closeRangeError()
configData.value.price_range_to = parseFloat(
(Number(configData.value.price_range_from) + Number(priceIncreaseMax.value)).toFixed(2)
)
console.log(`validateRange: 已调整最高金额为 ${configData.value.price_range_to}`)
return
}
//
if (configData.value.price_range_to < configData.value.price_range_from) {
console.log(`validateRange: 定价区间最高金额(${configData.value.price_range_to})小于最低金额(${configData.value.price_range_from}),进行修正`)
uni.showToast({
title: '定价区间最高金额不能低于定价区间最低金额',
icon: 'none'
})
if (configData.value.price_range_from + priceIncreaseMax.value > maxAllowed) {
configData.value.price_range_to = maxAllowed
console.log(`validateRange: 最高值已修正为最大允许值 ${maxAllowed}`)
} else {
configData.value.price_range_to = configData.value.price_range_from + priceIncreaseMax.value
console.log(`validateRange: 最高值已修正为最低金额+最大增加值 ${configData.value.price_range_to}`)
}
rangeError.value = true
closeRangeError()
return
}
//
const diff = parseFloat(
(configData.value.price_range_to - configData.value.price_range_from).toFixed(2)
)
console.log(`validateRange: 价格区间差值=${diff}, 最大允许差值=${priceIncreaseMax.value}`)
if (diff > priceIncreaseMax.value) {
console.log(`validateRange: 价格区间差值超过最大允许值,进行修正`)
uni.showToast({
title: `价格区间最大差值为${priceIncreaseMax.value}`,
icon: 'none'
})
configData.value.price_range_to = parseFloat(
(Number(configData.value.price_range_from) + Number(priceIncreaseMax.value)).toFixed(2)
)
console.log(`validateRange: 已调整最高金额为 ${configData.value.price_range_to}`)
closeRangeError()
return
}
//
if (configData.value.price_range_to > maxAllowed) {
console.log(`validateRange: 定价区间最高金额(${configData.value.price_range_to})超过上限(${maxAllowed}),进行修正`)
configData.value.price_range_to = maxAllowed
uni.showToast({
title: `定价区间最高金额不能超过 ${maxAllowed}`,
icon: 'none'
})
closeRangeError()
}
if (!rangeError.value) {
rangeError.value = false
}
console.log('validateRange结束:',
`最终最低=${configData.value.price_range_from}`,
`最终最高=${configData.value.price_range_to}`)
}
//
const validateRatio = () => {
console.log(`validateRatio开始: 值=${configData.value.price_ratio}`)
let value = configData.value.price_ratio
if (value === null || value === undefined) {
console.log('validateRatio: 值为空,退出验证')
return
}
const numValue = Number(value)
if (isNaN(numValue)) {
console.log('validateRatio: 值无法转换为数字设置为null')
configData.value.price_ratio = null
ratioError.value = true
return
}
console.log(`validateRatio: 检查比例范围 ${numValue} vs 最大值${priceRatioMax.value}`)
if (numValue > priceRatioMax.value) {
console.log(`validateRatio: 比例超过最大值,已修正为${priceRatioMax.value}`)
configData.value.price_ratio = priceRatioMax.value
uni.showToast({
title: `收取比例最大为${priceRatioMax.value}%`,
icon: 'none'
})
ratioError.value = true
setTimeout(() => {
ratioError.value = false
}, 1000)
} else if (numValue < 0) {
console.log('validateRatio: 比例小于0已修正为0')
configData.value.price_ratio = 0
ratioError.value = true
} else {
configData.value.price_ratio = parseFloat(numValue.toFixed(2))
ratioError.value = false
}
console.log(`validateRatio结束: 最终值=${configData.value.price_ratio}`)
}
//
const getConfig = async () => {
try {
console.log(`getConfig开始: 获取产品ID=${selectedReportId.value}的配置`)
const res = await getAgentMembershipUserConfig({ product_id: selectedReportId.value })
if (res.code === 200) {
const respConfigData = res.data.agent_membership_user_config
console.log("respConfigData", respConfigData)
configData.value = {
id: respConfigData.product_id,
price_range_from: respConfigData.price_range_from || null,
price_range_to: respConfigData.price_range_to || null,
price_ratio: respConfigData.price_ratio * 100 || null, //
price_increase_amount: respConfigData.price_increase_amount || null,
}
productConfigData.value = res.data.product_config
//
priceIncreaseMax.value = res.data.price_increase_max
priceIncreaseAmountMax.value = res.data.price_increase_amount
priceRatioMax.value = res.data.price_ratio * 100
console.log('getConfig: 配置加载成功',
`最大差值=${priceIncreaseMax.value}`,
`最大加价=${priceIncreaseAmountMax.value}`,
`最大比例=${priceRatioMax.value}%`)
console.log('getConfig: 当前配置', configData.value)
}
} catch (error) {
console.error("getConfig错误:", error)
uni.showToast({
title: '配置加载失败',
icon: 'none'
})
}
}
//
const handleSubmit = async () => {
try {
if (!finalValidation()) {
return
}
//
const submitData = {
product_id: configData.value.id,
price_range_from: configData.value.price_range_from || 0,
price_range_to: configData.value.price_range_to || 0,
price_ratio: (configData.value.price_ratio || 0) / 100, //
price_increase_amount: configData.value.price_increase_amount || 0,
}
const res = await saveAgentMembershipUserConfig(submitData)
if (res.code === 200) {
uni.showToast({
title: '保存成功',
icon: 'success'
})
getConfig()
}
} catch (error) {
uni.showToast({
title: '保存失败,请稍后重试',
icon: 'none'
})
}
}
//
const finalValidation = () => {
// 0
if (!configData.value.price_range_from || configData.value.price_range_from <= 0) {
uni.showToast({
title: "定价区间最低金额不能为空",
icon: 'none'
})
return false
}
// 0
if (!configData.value.price_range_to || configData.value.price_range_to <= 0) {
uni.showToast({
title: "定价区间最高金额不能为空",
icon: 'none'
})
return false
}
// 0
if (!configData.value.price_ratio || configData.value.price_ratio <= 0) {
uni.showToast({
title: "收取比例不能为空",
icon: 'none'
})
return false
}
//
if (configData.value.price_range_from >= configData.value.price_range_to) {
uni.showToast({
title: "定价区间最低金额必须小于定价区间最高金额",
icon: 'none'
})
return false
}
//
const finalDiff = parseFloat(
(configData.value.price_range_to - configData.value.price_range_from).toFixed(2)
)
if (finalDiff > priceIncreaseMax.value) {
uni.showToast({
title: `价格区间最大差值为${priceIncreaseMax.value}`,
icon: 'none'
})
return false
}
//
if (configData.value.price_range_to > productConfigData.value.price_range_max) {
uni.showToast({
title: `定价区间最高金额不能超过${productConfigData.value.price_range_max}`,
icon: 'none'
})
return false
}
// +
const additional = configData.value.price_increase_amount || 0
if (configData.value.price_range_from < productConfigData.value.cost_price + additional) {
uni.showToast({
title: `定价区间最低金额不能低于成本价${productConfigData.value.cost_price + additional}`,
icon: 'none'
})
return false
}
return true
}
//
const onConfirm = (e) => {
const { selectedItems } = e
selectedReportId.value = selectedItems.value
selectedReportText.value = selectedItems.label
showPicker.value = false
//
rangeError.value = false
ratioError.value = false
increaseError.value = false
getConfig()
}
const closeRangeError = () => {
setTimeout(() => {
rangeError.value = false
}, 2000)
}
onMounted(() => {
getConfig()
})
</script>
<style scoped>
.card {
border-radius: 12px;
background-color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
padding: 16px;
margin-bottom: 16px;
}
.space-y-6>* {
margin-bottom: 24px;
}
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "会员代理报告配置",
"agent": true,
"auth": true
}</route>

63
src/pages/agreement.vue Normal file
View File

@ -0,0 +1,63 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
// URL
const BASE_URL = import.meta.env.VITE_APP_BASE_URL || 'https://www.quannengcha.com'
//
const agreementMap = {
user: {
path: '/app/userAgreement',
title: '用户协议'
},
privacy: {
path: '/app/privacyPolicy',
title: '隐私政策'
},
authorization: {
path: '/app/authorization',
title: '授权书'
},
service: {
path: '/app/agentSerivceAgreement',
title: '信息技术服务合同'
},
manage: {
path: '/app/agentManageAgreement',
title: '推广方管理制度协议'
}
}
const agreementUrl = ref('')
const pageTitle = ref('协议')
// 使 uniapp onLoad
onLoad((option) => {
const type = option.type || 'user'
if (agreementMap[type]) {
agreementUrl.value = `${BASE_URL}${agreementMap[type].path}`
pageTitle.value = agreementMap[type].title
// - page wd-navbar
uni.setNavigationBarTitle({
title: pageTitle.value
})
}
})
function handleClickLeft() {
uni.navigateBack()
}
</script>
<template>
<view>
<wd-navbar :title="pageTitle" left-text="返回" placeholder left-arrow safe-area-inset-top fixed @click-left="handleClickLeft" />
<web-view :webview-styles="webviewStyles" :src="agreementUrl" />
</view>
</template>

View File

@ -1,72 +1,254 @@
<script setup>
import { onMounted, ref } from 'vue'
const userMessage = ref('')
const messages = ref([
{ sender: 'ai', text: '欢迎!请问有什么可以帮助您的吗?' },
])
function sendMessage() {
if (userMessage.value.trim() === '')
return
messages.value.push({ sender: 'user', text: userMessage.value })
// AI
setTimeout(() => {
messages.value.push({
sender: 'ai',
text: '感谢您的提问!我们会尽力为您提供帮助。',
})
}, 1000)
userMessage.value = ''
}
const safeAreaTop = ref(44)
onShow(() => {
uni.getSystemInfo({
success: (res) => {
if (res.safeArea && res.safeArea.top) {
safeAreaTop.value = res.safeArea.top //
}
},
})
})
</script>
<template>
<view
class="box-border min-h-screen from-blue-100 to-white bg-gradient-to-b" style="paddingTop:44px"
>
<view class="chat-page mx-4 flex flex-col rounded-xl shadow-lg">
<view class="chat-window flex-1 overflow-auto border p-4">
<view v-for="(message, index) in messages" :key="index" class="mb-2">
<view v-if="message.sender === 'ai'" class="inline-block max-w-max rounded-xl bg-white p-2 text-left text-green-600 font-medium shadow-md">
{{ message.text }}
</view>
<view v-else class="ml-auto inline-block max-w-max rounded-xl from-sky-300 via-sky-300 to-sky-300 bg-gradient-to-r p-2 text-right text-white font-medium shadow-md">
{{ message.text }}
<view class="safe-area-top flex flex-col box-border from-blue-100 to-white bg-gradient-to-b pt-4 flex-1 pb-4">
<!-- 角色切换部分 -->
<view class="flex border-blue-300 mx-4 p-1 bg-white rounded-xl">
<view class="flex items-center flex-1 p-2 box-border rounded-xl cursor-pointer"
:class="selectedRole === 'legal' ? 'bg-blue-300 text-white' : ''" @click="selectRole('legal')">
<image src="/static/image/ai_picture.webp" class="w-10 h-10 rounded-xl mr-2" alt="AI律师" />
法律咨询
</view>
<view class="flex items-center flex-1 p-2 box-border rounded-xl cursor-pointer"
:class="selectedRole === 'emotional' ? 'bg-blue-300 text-white' : ''" @click="selectRole('emotional')">
<image src="/static/image/ai_qinggan.png" class="w-10 h-10 rounded-xl mr-2" alt="AI心理咨询师" />
情感咨询
</view>
</view>
<!-- 聊天窗口 -->
<view class="mx-4 flex flex-col flex-1 rounded-xl shadow-lg">
<view class="flex flex-col flex-1 p-4">
<view class="flex-1 overflow-y-auto">
<view v-for="(message, index) in currentMessages" :key="index" class="mb-4">
<view v-if="message.sender === 'ai'" class="flex justify-start items-start">
<!-- 根据角色显示不同的AI形象 -->
<image :src="selectedRole === 'legal' ? '/static/image/ai_picture.webp' : '/static/image/ai_qinggan.png'"
class=" flex-shrink-0 w-10 h-10 rounded-xl mr-2" :alt="selectedRole === 'legal' ? 'AI律师' : 'AI心理咨询师'" />
<view class="inline-block max-w-max rounded-xl bg-white p-2 text-left"
:class="selectedRole === 'legal' ? 'text-green-600' : 'text-purple-600'">
<!-- 如果是AI消息显示加载中或文本 -->
<view v-if="message.loading" class="flex justify-center items-center">
<view class="loader"></view> <!-- 加载动画 -->
</view>
<view v-else>
{{ message.text }}
</view>
</view>
</view>
<view v-else class="flex justify-end">
<view class="ml-auto inline-block max-w-max rounded-xl from-sky-300 via-sky-300 to-sky-300
bg-gradient-to-r p-2 text-right text-white font-medium shadow-md">
{{ message.text }}
</view>
</view>
</view>
</view>
</view>
<view class="input-area mx-2 flex items-center gap-2 p-4">
<wd-input v-model="userMessage" placeholder="请输入您的问题..." class="flex-1" size="large" />
<wd-button custom-class="shadow" type="primary" @click="sendMessage">
发送
</wd-button>
<!-- 输入区域 -->
<view class="p-2 w-full input-area flex items-center gap-2">
<input v-model="userMessage" :placeholder="selectedRole === 'legal' ? '请输入您的法律问题...' : '请输入您的情感问题...'"
class="flex-1 p-2 border rounded-lg" type="text" @confirm="sendMessage" />
<button class="shadow p-2 bg-blue-500 text-white rounded-lg" @click="sendMessage">
发送
</button>
</view>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.chat-page {
height: calc(100vh - 108px);
<script setup>
import { ref, onBeforeUnmount, computed } from 'vue'
import chatEncrypt from "@/utils/chatEncrypt"
//
const selectedRole = ref('legal')
//
const userMessage = ref('')
//
const messages = ref({
legal: [
{ sender: 'ai', text: '欢迎!请问有什么法律问题需要帮助?' },
],
emotional: [
{ sender: 'ai', text: '欢迎!请问有什么情感问题需要帮助?' },
]
})
// sessionID
const sessionID = ref({
legal: "",
emotional: ""
})
let reader = {
legal: null,
emotional: null
}
//
const currentMessages = computed(() => messages.value[selectedRole.value])
//
function selectRole(role) {
if (selectedRole.value !== role) {
selectedRole.value = role
//
if (!messages.value[role]) {
messages.value[role] = [
{ sender: 'ai', text: role === 'legal' ? '欢迎!请问有什么法律问题需要帮助?' : '欢迎!请问有什么情感问题需要帮助?' },
]
sessionID.value[role] = ""
}
}
}
async function sendMessage() {
if (userMessage.value.trim() === '') return;
//
const role = selectedRole.value
//
messages.value[role].push({ sender: 'user', text: userMessage.value })
const t = Date.now()
const x = chatEncrypt(String(t))
// AI
const aiMessage = { sender: 'ai', text: '', loading: true }
messages.value[role].push(aiMessage)
console.log("import.meta.env.VITE_APP_BASE_URL", import.meta.env.VITE_APP_BASE_URL)
//
try {
const response = await uni.request({
url: import.meta.env.VITE_APP_BASE_URL + '/api/v1/chat/send',
method: 'POST',
header: {
'Content-Type': 'application/json',
'x': x,
't': t,
},
data: {
prompt: userMessage.value,
platform_id: 2,
// roleid: role === 'legal' ? 1 : 2, // roleid
role_id: 1, // roleid
openid: 'openid' + uni.getStorageSync("token"),
userid: 'userid' + uni.getStorageSync("token"),
sessionid: sessionID.value[role] // 使 sessionID
},
responseType: 'text',
enableChunked: true, //
enableStream: true, //
success: (streamRes) => {
if (streamRes.statusCode === 200) {
aiMessage.loading = false;
//
const chunks = streamRes.data.split('\n');
for (const chunk of chunks) {
if (chunk.trim()) {
let message = chunk;
if (message.startsWith('data:')) {
message = message.replace('data:', '').trim();
}
console.log("message", message);
try {
const parsedMessage = JSON.parse(message);
console.log("parsedMessage", parsedMessage);
if (parsedMessage?.output?.session_id) {
// session_id
sessionID.value[role] = parsedMessage?.output?.session_id;
}
// AI
const aiText = parsedMessage.output.text || '';
//
const addTextWithTypingEffect = (text) => {
if (!text) return;
//
aiMessage.text += text;
//
messages.value[role] = [...messages.value[role]];
};
//
addTextWithTypingEffect(aiText);
} catch (e) {
console.error('Failed to parse message:', e);
}
}
}
}
},
fail: (err) => {
console.error('Request failed:', err);
aiMessage.loading = false;
aiMessage.text = '抱歉,请求失败,请重试';
messages.value[role] = [...messages.value[role]];
}
});
} catch (error) {
console.error('Request error:', error);
}
userMessage.value = ''; //
}
onBeforeUnmount(() => {
// UniAppUniApp
})
</script>
<style scoped>
input {
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 0.5rem;
}
button {
padding: 0.5rem 1rem;
background-color: #007bff;
border: none;
border-radius: 0.5rem;
color: white;
}
button:hover {
background-color: #0056b3;
}
.loader {
border: 4px solid #f3f3f3;
/* Light gray */
border-top: 4px solid #3498db;
/* Blue */
border-radius: 50%;
width: 24px;
height: 24px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Tab Styles */
.flex.border-blue-300>view {
transition: all 0.3s;
}
</style>
<route lang="json">
{
"layout": "home"
}
</route>
<route lang="json">{
"layout": "home"
}</route>

View File

@ -1,54 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
const id = ref(null)
function handleMessage(event) {
const data = event.detail.data[0]
if (data.loaded) {
onWebViewLoaded()
}
else if (data.action === 'agreed') {
uni.redirectTo({ url: `/pages/pay?id=${id.value}` })
}
else if (data.action === 'cancelled') {
uni.showModal({
title: '注意',
content: '是否确认取消,退出当前页面',
success(res) {
if (res.confirm) {
uni.navigateBack()
}
},
})
}
}
function onWebViewLoaded() {
}
const src = ref('https://app.quannengcha.com/authorization')
onLoad((option) => {
if (option.id) {
src.value = `${src.value}?id=${encodeURIComponent(option.id)}&token=${encodeURIComponent(uni.getStorageSync('token'))}`
id.value = option.id
}
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" :src="src" @message="handleMessage" />
</view>
</template>
<route lang="json">
{
"layout": "page",
"title": "授权书"
}
</route>

View File

@ -1,22 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" src="https://app.quannengcha.com/complaint" />
</view>
</template>
<route lang="json">
{
"layout": "page",
"title": "投诉服务"
}
</route>

View File

@ -1,204 +0,0 @@
<script setup>
import CBad from '@/ui/CBad.vue'
import CBankLoanApplication from '@/ui/CBankLoanApplication.vue'
import CBankLoanBehavior from '@/ui/CBankLoanBehavior.vue'
import CLawsuit from '@/ui/CLawsuit.vue'
import CRelatedEnterprises from '@/ui/CRelatedEnterprises.vue'
import CSpecialList from '@/ui/CSpecialList.vue'
import CTabs from '@/ui/CTabs.vue'
import { queryExample } from '@/api/apis'
import CMarriage from '@/ui/CMarriage.vue'
const productMap = {
1: '背景调查',
2: '企业报告',
3: '家政服务',
4: '婚姻状态',
5: '贷前背景调查',
6: '租赁服务',
7: '个人风险评估',
}
// product_id
function getProductName(productId) {
return productMap[productId] || '未知类型'
}
const productId = ref(null)
const isDone = ref(false)
const entData = ref(null)
const lawsuitData = ref(null)
const badData = ref(null)
const specialData = ref(null)
const bankLoanApplicationData = ref(null)
const marriageData = ref(null)
const bankLoanBehavior = ref(null)
const tabs = ref([
{ label: '报告概述', value: 'overview' },
])
const reportItems = ref([
])
const sortedReportItems = computed(() => {
return reportItems.value.slice().sort((a, b) => a.sort - b.sort)
})
const sortedTabs = computed(() => {
return tabs.value.slice().sort((a, b) => a.sort - b.sort)
})
onLoad((option) => {
console.log('option', option)
const { feature } = option
if (feature) {
queryExample({ feature }).then((res) => {
console.log('res', res)
if (res.code === 200) {
productId.value = res.data.product_id
res.data.query_data.forEach((item) => {
if (item.success) {
switch (item.apiID) {
case 'G09SC02':
marriageData.value = item.data
tabs.value.push({ label: '婚姻状态', value: 'marriage', sort: 1 })
reportItems.value.push({ label: '婚姻状态', value: 'marriage', sort: 1 })
break
case 'G27BJ05':
bankLoanApplicationData.value = item.data
tabs.value.push({ label: '借贷申请记录', value: 'netloan', sort: 7 })
reportItems.value.push({ label: '借贷申请记录', value: 'netloan', sort: 7 })
break
case 'G28BJ05':
bankLoanBehavior.value = item.data
tabs.value.push({ label: '借贷记录', value: 'loan', sort: 6 })
reportItems.value.push({ label: '借贷记录', value: 'loan', sort: 6 })
break
case 'G26BJ05':
specialData.value = item.data
tabs.value.push({ label: '异常名单', value: 'special', sort: 5 })
reportItems.value.push({ label: '异常名单', value: 'special', sort: 5 })
break
case 'G05HZ01':
entData.value = item.data
tabs.value.push({ label: '关联企业', value: 'ent', sort: 4 })
reportItems.value.push({ label: '关联企业', value: 'ent', sort: 4 })
break
case 'G34BJ03':
badData.value = item.data
tabs.value.push({ label: '不良风险评估', value: 'bad', sort: 3 })
reportItems.value.push({ label: '不良风险评估', value: 'bad', sort: 3 })
break
case 'G35SC01':
lawsuitData.value = item.data
tabs.value.push({ label: '涉诉案件', value: 'lawsuit', sort: 2 })
reportItems.value.push({ label: '涉诉案件', value: 'lawsuit', sort: 2 })
break
default:
console.log(`未知的apiID: ${item.apiID}`)
}
}
})
}
}).finally(() => {
isDone.value = true
})
}
})
</script>
<template>
<div class="min-h-full from-blue-100 to-white bg-gradient-to-b">
<CTabs
:tabs="sortedTabs"
type="blue-green"
/>
<template v-if="isDone">
<div class="flex flex-col gap-y-4 p-4 pt-12">
<div id="overview" class="title">
报告概述
</div>
<div class="card">
<div class="flex flex-col gap-y-2">
<div class="flex justify-between">
<span class="text-gray-700 font-bold">报告时间</span>
<span class="text-gray-600">2024年11月18日 23:11:23</span>
</div>
<div class="flex justify-between">
<span class="text-gray-700 font-bold">报告项目</span>
<span class="text-gray-600">{{ getProductName(productId) }}</span>
</div>
</div>
<div>
<LTitle class="my-4" title="报告内容" type="blue-green" />
<div class="flex flex-col gap-y-2">
<div v-for="item in sortedReportItems" :key="item.value" class="flex justify-between">
<span class="text-gray-700 font-bold">{{ item.label }}</span>
<span class="text-green-500 font-bold">已解锁</span>
</div>
</div>
</div>
</div>
<template v-if="marriageData">
<div id="marriage" class="title">
婚姻状态
</div>
<CMarriage :data="marriageData" />
</template>
<template v-if="lawsuitData">
<div id="lawsuit" class="title">
涉诉案件
</div>
<CLawsuit :data="lawsuitData" />
</template>
<template v-if="badData">
<div id="bad" class="title">
不良风险评估
</div>
<CBad :data="badData" />
</template>
<template v-if="entData">
<div id="ent" class="title">
关联企业
</div>
<CRelatedEnterprises :data="entData" />
</template>
<template v-if="specialData">
<div id="special" class="title">
异常名单
</div>
<CSpecialList :data="specialData" />
</template>
<template v-if="bankLoanBehavior">
<div id="loan" class="title">
借贷记录
</div>
<CBankLoanBehavior :data="bankLoanBehavior" />
</template>
<template v-if="bankLoanApplicationData">
<div id="netloan" class="title">
贷款申请记录
</div>
<CBankLoanApplication :data="bankLoanApplicationData" />
</template>
<view class="card">
<view>
<view class="text-blue-500 font-bold">
报告说明
</view>
<view>本报告的数据由用户本人明确授权后我们才向相关合法存有用户个人数据的机构调取本报告相关内容本平台只做大数据的获取与分析仅向用户个人展示参考</view><p> &nbsp; &nbsp; 报告有效期<strong>30</strong>过期自动删除 </p><p> &nbsp; &nbsp; 若您的数据不全面可能是数据具有延迟性或者合作信息机构未获取到您的数据若数据有错误请联系客服</p>
</view>
</view>
</div>
</template>
</div>
</template>
<style lang="scss" scoped>
</style>
<route lang="json">
{
"layout": "page",
"title": "报告示例"
}
</route>

View File

@ -1,41 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
const feature = ref(null)
const token = ref(null)
const webviewSrc = ref('')
onLoad((option) => {
if (option.feature) {
feature.value = option.feature
}
token.value = uni.getStorageSync('token') || ''
const baseUrl = 'https://app.quannengcha.com/example'
webviewSrc.value = `${baseUrl}?feature=${encodeURIComponent(feature.value)}&token=${encodeURIComponent(token.value)}`
})
</script>
<template>
<view>
<!-- 使用动态构造的 WebView src -->
<web-view :webview-styles="webviewStyles" :src="webviewSrc" />
</view>
</template>
<style lang="scss" scoped>
</style>
<route lang="json">
{
"layout": "page",
"title": "示例报告"
}
</route>

View File

@ -1,30 +1,122 @@
<script setup>
import indexIcon1 from '/static/image/index_icon_1.png'
import indexIcon2 from '/static/image/index_icon_2.png'
import indexIcon3 from '/static/image/index_icon_3.png'
import indexIcon4 from '/static/image/index_icon_4.png'
import indexIcon5 from '/static/image/index_icon_5.png'
import indexIcon6 from '/static/image/index_icon_6.png'
import indexIcon7 from '/static/image/index_icon_7.png'
// WebView
// @ts-ignore
import WebViewPlugin from '@/utssdk/webview';
const webViewPlugin = new WebViewPlugin();
const services = ref(
[
{
title: '个人风险',
name: 'riskassessment',
subtitle: '一查全知',
bg: indexIcon2,
bgColor: 'bg-indigo-400',
position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg'
},
{
title: '婚恋风险',
name: 'marriage',
subtitle: '查婚姻状态让爱无忧',
bg: indexIcon1,
bgColor: ' bg-pink-400 ',
position: 'rounded-tr-[35px] rounded-br-[35px] rounded-tl-lg rounded-bl-lg'
},
{
title: '家政服务',
name: 'homeservice',
subtitle: '用人有保障',
bg: indexIcon3,
bgColor: ' bg-teal-500 ',
position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg'
},
{
title: '租赁风险',
name: 'rentalinfo',
subtitle: '一查明了',
bg: indexIcon4,
bgColor: ' bg-sky-500 ',
position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg'
},
{
title: '企业报告',
name: 'companyinfo',
subtitle: '合作更安心',
bg: indexIcon5,
bgColor: ' bg-blue-400 ',
position: 'rounded-tr-[35px] rounded-br-[35px] rounded-tl-lg rounded-bl-lg'
},
{
title: '人事背调',
name: 'backgroundcheck',
subtitle: '招聘有保障,选人更放心',
bg: indexIcon6,
bgColor: ' bg-orange-400 ',
position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg'
},
{
title: '贷前背调',
name: 'preloanbackgroundcheck',
subtitle: '招聘有保障,选人更放心',
bg: indexIcon7,
bgColor: ' bg-orange-400 ',
position: 'rounded-tr-[35px] rounded-br-[35px] rounded-tl-lg rounded-bl-lg'
},
]
)
function toInquire(name) {
uni.navigateTo({
url: `/pages/inquire?feature=${name}`,
})
// 使URL
console.log('使用服务:', name);
// App 使 UTS App 使
// #ifdef APP-PLUS
try {
// URL
const serviceUrl = `https://www.quannengcha.com/inquire/${name}`;
// 使 UTS
webViewPlugin.openUrl(serviceUrl);
} catch (error) {
console.error('打开URL失败:', error);
}
// #endif
}
const services = ref([
{ title: '个人风险', name: 'riskassessment', subtitle: '一查全知', bg: '/static/image/index_icon_2.png', bgColor: 'bg-indigo-400', position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg' },
{ title: '婚恋风险', name: 'marriage', subtitle: '查婚姻状态让爱无忧', bg: '/static/image/index_icon_1.png', bgColor: ' bg-pink-400 ', position: 'rounded-tr-[35px] rounded-br-[35px] rounded-tl-lg rounded-bl-lg' },
{ title: '家政服务', name: 'homeservice', subtitle: '用人有保障', bg: '/static/image/index_icon_3.png', bgColor: ' bg-teal-500 ', position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg' },
{ title: '租赁风险', name: 'rentalinfo', subtitle: '一查明了', bg: '/static/image/index_icon_4.png', bgColor: ' bg-sky-500 ', position: 'rounded-tl-[35px] rounded-bl-[35px] rounded-tr-lg rounded-br-lg' },
{ title: '企业报告', name: 'companyinfo', subtitle: '合作更安心', bg: '/static/image/index_icon_5.png', bgColor: ' bg-blue-400 ', position: 'rounded-tr-[35px] rounded-br-[35px] rounded-tl-lg rounded-bl-lg' },
{ title: '人事背调', name: 'backgroundcheck', subtitle: '招聘有保障,选人更放心', bg: '/static/image/index_icon_6.png', bgColor: ' bg-orange-400 ', position: 'rounded-[35px] col-span-2' },
])
const noticeText = ref([])
function toHistory() {
uni.navigateTo({
url: '/pages/queryHistory',
})
}
function toInvitation() {
uni.navigateTo({
url: '/pages/invitation',
})
}
function toPromote() {
uni.navigateTo({
url: '/pages/promote',
})
}
function toHelp() {
uni.navigateTo({
url: '/pages/help',
})
}
</script>
<template>
<view class="box-border min-h-screen from-blue-100 to-white bg-gradient-to-b">
<view class="box-border">
<view class="relative h-[190px]">
<image class="h-full w-full" src="/static/image/banner2.png" />
<image
@ -33,20 +125,43 @@ function toHistory() {
mode="aspectFit"
/>
</view>
<view class="relative p-4 pb-4 pt-2">
<view class="mb-1 flex items-center">
<view class="flex-shrink-0 pl-2 font-bold">
在线信息
<view class="mt-4">
<view class="flex items-center justify-around gap-2 px-4 pb-1">
<view class="" @click="toPromote">
<view
class="h-12 w-12 p-2 bg-gradient-to-b from-white to-blue-100/10 rounded-full shadow-lg flex items-center justify-center">
<image src="/static/image/icon_tg.svg" alt="直推报告" class="w-12 h-12" mode="aspectFit" />
</view>
<view class="text-center mt-1 font-bold">直推报告</view>
</view>
<view class="" @click="toInvitation">
<view
class="h-12 w-12 p-2 bg-gradient-to-b from-white to-blue-100/10 rounded-full shadow-lg flex items-center justify-center">
<image src="/static/image/icon_xj.svg" alt="邀请下级" class="w-12 h-12" mode="aspectFit" />
</view>
<view class="text-center mt-1 font-bold">邀请下级</view>
</view>
<view class="" @click="toHelp">
<view
class="h-12 w-12 p-2 bg-gradient-to-b from-white to-blue-100/10 rounded-full shadow-lg flex items-center justify-center">
<image src="/static/image/icon_bz.svg" alt="帮助中心" class="w-12 h-12" mode="aspectFit" />
</view>
<view class="text-center mt-1 font-bold">帮助中心</view>
</view>
<view class="" @click="toHistory">
<view
class="h-12 w-12 p-2 bg-gradient-to-b from-white to-blue-100/10 rounded-full shadow-lg flex items-center justify-center">
<image src="/static/image/icon_bg.svg" alt="我的报告" class="w-12 h-12" mode="aspectFit" />
</view>
<view class="text-center mt-1 font-bold">我的报告</view>
</view>
<wd-notice-bar
:text="noticeText" direction="vertical" :delay="5" color="#4c4c4c"
background-color="#00000000"
/>
</view>
</view>
<view class="relative p-4 pb-4 pt-2">
<view class="grid grid-cols-2 gap-3">
<template v-for="(service, index) in services" :key="index">
<view
class="relative flex flex-col px-4 py-2 shadow-lg" :class="[
class="relative flex flex-col px-4 py-2 shadow-lg " :class="[
service.position,
service.bgColor,
service.title === '婚恋风险' ? 'row-span-2' : '',
@ -57,9 +172,6 @@ function toHistory() {
<view class="mt-1 max-w-max text-left text-gray-600 font-bold">
{{ service.title }}
</view>
<view class="max-w-max text-left text-xs text-gray-600">
<rich-text :nodes="service.subtitle" />
</view>
<view class="mt-2 rounded-2xl px-2 text-xs text-white" :class="[service.bgColor]">
GO >
</view>
@ -106,6 +218,10 @@ function toHistory() {
<route type="home" lang="json">
{
"layout": "home"
"layout": "home",
"style": {
"navigationBarTextStyle": "white",
"transparentTitle": "always"
}
}
</route>

View File

@ -1,294 +0,0 @@
<script setup>
import { aesEncrypt } from '@/utils/crypto'
import { getCode, getProduct, queryMarriage, querybackgroundCheck, querycompanyInfo, queryhomeService, querypreLoanBackgroundCheck, queryrentalInfo, queryriskAssessment } from '@/api/apis'
const name = ref('')
const idCard = ref('')
const phoneNumber = ref('')
const verificationCode = ref('')
const agreeToTerms = ref(false)
const isCountingDown = ref(false)
const countdown = ref(60)
const feature = ref('')
const timer = null
const featureData = ref({})
const services = reactive([
{ title: '个人风险报告', name: 'riskassessment', subtitle: '一查全知', bg: '/static/image/index_icon_2.png', bgColor: 'bg-indigo-400', api: queryriskAssessment },
{ title: '婚恋报告', name: 'marriage', subtitle: '查婚姻状态让爱无忧', bg: '/static/image/index_icon_1.png', bgColor: ' bg-pink-400 ', api: queryMarriage },
{ title: '家政服务报告', name: 'homeservice', subtitle: '用人有保障', bg: '/static/image/index_icon_3.png', bgColor: ' bg-teal-500 ', api: queryhomeService },
{ title: '租赁服务报告', name: 'rentalinfo', subtitle: '一查明了', bg: '/static/image/index_icon_4.png', bgColor: ' bg-sky-500 ', api: queryrentalInfo },
{ title: '贷前调查报告', name: 'preloanbackgroundcheck', subtitle: '放心借贷', bg: '/static/image/index_icon_7.png', bgColor: ' bg-red-400 ', api: querypreLoanBackgroundCheck },
{ title: '人事背调报告', name: 'backgroundcheck', subtitle: '选人更放心', bg: '/static/image/index_icon_6.png', bgColor: ' bg-orange-400 ', api: querybackgroundCheck },
{ title: '企业报告', name: 'companyinfo', subtitle: '合作更安心', bg: '/static/image/index_icon_5.png', bgColor: ' bg-blue-400 ', api: querycompanyInfo },
])
const service = ref({})
onLoad((options) => {
console.log('options', options)
if (options.feature) {
feature.value = options.feature
}
else {
feature.value = 'marrige'
}
getService()
getProduct(feature.value).then((res) => {
if (res.code === 200) {
featureData.value = res.data
}
})
})
const isPhoneNumberValid = computed(() => {
return /^1[3-9]\d{9}$/.test(phoneNumber.value)
})
const isIdCardValid = computed(() => /^\d{17}[\dX]$/i.test(idCard.value))
function handleSubmit() {
if (!agreeToTerms.value) {
uni.showToast({ title: '请阅读并同意用户协议和隐私政策', icon: 'none' })
return
}
if (!name.value) {
uni.showToast({ title: '请输入姓名', icon: 'none' })
return
}
if (!isPhoneNumberValid.value) {
uni.showToast({ title: '请输入有效的手机号', icon: 'none' })
return
}
if (!isIdCardValid.value) {
uni.showToast({ title: '请输入有效的身份证号码', icon: 'none' })
return
}
if (!verificationCode.value) {
uni.showToast({ title: '请输入验证码', icon: 'none' })
return
}
submit()
}
function getService() {
for (const i of services) {
if (i.name === feature.value) {
service.value = i
}
}
}
function sendVerificationCode() {
if (isCountingDown.value || !isPhoneNumberValid.value)
return
if (!isPhoneNumberValid.value) {
uni.showToast({ title: '请输入有效的手机号', icon: 'none' })
return
}
getCode({
mobile: phoneNumber.value,
actionType: 'query',
}).then((res) => {
if (res.code === 200) {
uni.showToast({ title: '获取成功', icon: 'none' })
startCountdown()
}
})
}
function startCountdown() {
isCountingDown.value = true
countdown.value = 60
timer = setInterval(() => {
if (countdown.value > 0) {
countdown.value--
}
else {
clearInterval(timer)
isCountingDown.value = false
}
}, 1000)
}
function toExample() {
uni.navigateTo({
url: `/pages/example?feature=${feature.value}`,
})
}
function submit() {
const req = {
name: name.value,
id_card: idCard.value,
mobile: phoneNumber.value,
code: verificationCode.value,
}
const data = JSON.stringify(req)
const encodeData = aesEncrypt(data, 'ff83609b2b24fc73196aac3d3dfb874f')
service.value.api({ data: encodeData }).then((res) => {
if (res.code === 200) {
uni.navigateTo({
url: `/pages/authorization?id=${res.data.id}`,
})
}
})
}
function toUserAgreement() {
uni.navigateTo({
url: '/pages/userAgreement',
})
}
function toPrivacyPolicy() {
uni.navigateTo({
url: '/pages/privacyPolicy',
})
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
</script>
<template>
<view class="inquire-bg min-h-screen rounded-lg p-6 shadow-lg">
<view class="mb-6 text-center text-blue-800 font-extrabold">
<view class="text-blue-600">
<text class="text-2xl font-bold">
{{ service.title }}
</text>
</view>
</view>
<view class="card-p-0 px-4 py-6">
<view class="mb-4 text-xl text-gray-800 font-semibold">
基本信息
</view>
<wd-input
v-model="name" label="姓名" type="text" label-width="60px" placeholder="请输入正确的姓名"
class="mb-6 border-b border-gray-200 border-b-solid"
/>
<wd-input
v-model="idCard" label="身份证号" label-width="60px" placeholder="请输入准确的身份证号码"
class="mb-6 border-b border-gray-200 border-b-solid"
/>
<wd-input
v-model="phoneNumber" label="手机号" type="tel" label-width="60px" placeholder="输入手机号"
class="mb-6 border-b border-gray-200 border-b-solid"
/>
<view class="mb-6 flex items-center">
<wd-input
v-model="verificationCode" label="验证码" type="number" label-width="60px" placeholder="输入验证码"
class="flex-1 border-b border-gray-200 border-b-solid"
/>
<view
class="ml-2 flex-shrink-0 rounded-lg border-none px-2 py-2 text-sm font-bold outline-none ring-none transition duration-300"
:class="isCountingDown || !isPhoneNumberValid ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'bg-blue-500 text-white hover:bg-blue-600'"
@click="sendVerificationCode"
>
{{ isCountingDown ? `${countdown}s重新获取` : '获取验证码' }}
</view>
</view>
<view class="mb-6 flex items-center">
<wd-checkbox v-model="agreeToTerms" />
<view class="ml-1 text-xs text-gray-400">
我已阅读并同意<text class="text-blue-500 hover:underline" @click="toUserAgreement">
用户协议
</text><text class="text-blue-500 hover:underline" @click="toPrivacyPolicy">
隐私政策
</text>
</view>
</view>
<view class="flex">
<wd-button
custom-style="border-top-right-radius: 0;
border-bottom-right-radius: 0;" plain class="w-10 py-3 text-lg font-bold" @click="toExample"
>
示例报告
</wd-button>
<wd-button
custom-style="border-top-left-radius: 0;
border-bottom-left-radius: 0;" type="primary" class="flex-1 py-3 text-lg font-bold" @click="handleSubmit"
>
立即查询 {{ featureData.sell_price }}
</wd-button>
</view>
</view>
<wd-divider class="my-4" />
<view class="card">
<!-- 报告标题 -->
<view class="mb-6 text-xl text-gray-800 font-bold">
{{ featureData.product_name }}
</view>
<!-- 报告介绍 -->
<view class="mb-4 text-gray-600 leading-relaxed">
{{ featureData.description }}
</view>
<!-- 报价信息 -->
<view class="mb-6 flex items-center justify-between">
<view class="text-lg text-gray-500">
价格
</view>
<view class="text-lg text-blue-600 font-semibold">
¥{{ featureData.sell_price }}
</view>
</view>
<!-- 报告主要内容 -->
<view class="mb-4 text-lg text-gray-800 font-semibold">
报告主要内容
</view>
<view class="grid grid-cols-2 gap-4">
<view
v-for="(feature, index) in featureData.features"
:key="feature.id"
class="rounded-lg py-2 text-center text-sm text-gray-700 font-medium"
:class="[
(Math.floor(index / 2) + (index % 2)) % 2 === 0
? 'bg-gradient-to-r from-blue-200 via-blue-200 to-blue-100'
: 'bg-gradient-to-r from-sky-200 via-sky-200 to-sky-100',
]"
>
{{ feature.name }}
</view>
</view>
</view>
</view>
</template>
<style scoped>
.icon-company,
.icon-transaction,
.icon-judicial,
.icon-penalty {
font-size: 2rem;
}
.inquire-bg {
background: url("/static/image/bg_2.png") no-repeat;
position: relative;
}
.inquire-bg::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.4);
/* 使用白色的半透明覆盖层0.5 可调整为其他透明度值 */
z-index: 1;
}
.inquire-bg>* {
position: relative;
z-index: 2;
/* 确保子元素在覆盖层之上 */
}
</style>
<route lang="json">
{
"layout": "page",
"title": "报告查询"
}
</route>

51
src/pages/invitation.vue Normal file
View File

@ -0,0 +1,51 @@
<template>
<view>
<image src="/static/image/invitation.png" alt="邀请下级" mode="widthFix" class="w-full" />
<view @click="showQRcode = true"
class="bg-gradient-to-t from-orange-500 to-orange-300 fixed bottom-0 h-12 w-full shadow-xl text-white rounded-t-xl flex items-center justify-center font-bold">
立即邀请好友
</view>
<QRcode v-model:show="showQRcode" mode="invitation" :linkIdentifier="linkIdentifier" />
</view>
</template>
<script setup>
import { ref, onBeforeMount } from 'vue'
import { aesEncrypt } from "@/utils/crypto"
import QRcode from '@/components/QRcode.vue'
const showQRcode = ref(false)
const linkIdentifier = ref("")
const mobile = ref("")
const agentID = ref("")
onBeforeMount(() => {
// UniApp
const userInfo = uni.getStorageSync('userInfo') || {}
mobile.value = userInfo.mobile || ''
agentID.value = userInfo.agentID || ''
encryptIdentifire(agentID.value, mobile.value)
})
const encryptIdentifire = (agentID, mobile) => {
const linkIdentifierJSON = {
agentID,
mobile
}
const linkIdentifierStr = JSON.stringify(linkIdentifierJSON)
const encodeData = aesEncrypt(linkIdentifierStr, "8e3e7a2f60edb49221e953b9c029ed10")
linkIdentifier.value = encodeURIComponent(encodeData)
}
</script>
<style>
/* 自定义样式 */
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "邀请下级",
"auth": true,
"agent": true
}</route>

View File

@ -0,0 +1,199 @@
<template>
<view class="min-h-screen bg-[#D1D6FF]">
<image src="/static/image/invitation_agent_apply.png" alt="邀请代理申请" mode="widthFix" class="w-full" />
<!-- 统一状态处理容器 -->
<view class="flex flex-col items-center justify-center">
<!-- 审核中状态 -->
<view v-if="displayStatus === 0" class="text-center">
<text class="text-xs text-gray-500 block">您的申请正在审核中</text>
<view class="bg-gray-200 p-1 rounded-3xl shadow-xl mt-1">
<view class="text-xl font-bold px-8 py-2 bg-gray-400 text-white rounded-3xl shadow-lg cursor-not-allowed">
审核进行中
</view>
</view>
</view>
<!-- 审核通过状态 -->
<view v-if="displayStatus === 1" class="text-center">
<text class="text-xs text-gray-500 block">您已成为认证代理方</text>
<view class="bg-green-100 p-1 rounded-3xl shadow-xl mt-1" @click="goToHome">
<view
class="text-xl font-bold px-8 py-2 bg-gradient-to-t from-green-500 to-green-300 text-white rounded-3xl shadow-lg cursor-pointer">
进入应用首页
</view>
</view>
</view>
<!-- 审核未通过状态 -->
<view v-if="displayStatus === 2" class="text-center">
<text class="text-xs text-red-500 block">审核未通过请重新提交</text>
<view class="bg-red-100 p-1 rounded-3xl shadow-xl mt-1" @click="agentApply">
<view
class="text-xl font-bold px-8 py-2 bg-gradient-to-t from-red-500 to-red-300 text-white rounded-3xl shadow-lg cursor-pointer">
重新提交申请
</view>
</view>
</view>
<!-- 未申请状态包含邀请状态 -->
<view v-if="displayStatus === 3" class="text-center">
<text class="text-xs text-gray-500 block">{{ isSelf ? '立即申请成为代理人' : '邀您注册代理人' }}</text>
<view class="bg-gray-100 p-1 rounded-3xl shadow-xl mt-1" @click="agentApply">
<view
class="text-xl font-bold px-8 py-2 bg-gradient-to-t from-blue-500 to-blue-300 text-white rounded-3xl shadow-lg cursor-pointer">
立即成为代理方
</view>
</view>
</view>
</view>
<AgentApplicationForm v-model:show="showApplyPopup" @submit="submitApplication" @close="showApplyPopup = false"
:ancestor="ancestor" />
</view>
</template>
<script setup>
import { ref, computed, onBeforeMount } from 'vue'
import { getAgentInfo, applyAgent } from '@/apis/agent'
import AgentApplicationForm from '@/components/AgentApplicationForm.vue'
const showApplyPopup = ref(false)
const status = ref(3) //
const ancestor = ref("")
const isSelf = ref(true)
let intervalId = null // ID
// isSelffalse3
const displayStatus = computed(() => {
return !isSelf.value ? 3 : status.value
})
//
const agentApply = () => {
showApplyPopup.value = true
}
//
const goToHome = () => {
clearInterval(intervalId)
uni.switchTab({
url: '/pages/index'
})
}
const getAgentInformation = async () => {
const token = uni.getStorageSync("token")
if (!token) {
return
}
try {
const res = await getAgentInfo()
if (res.code === 200 && res.data) {
//
uni.setStorageSync("agentInfo", {
level: res.data.level,
isAgent: res.data.is_agent, //
status: res.data.status, // 0=1=2=3=
agentID: res.data.agent_id,
mobile: res.data.mobile
})
status.value = res.data.status
console.log('代理信息已获取并存入缓存')
}
} catch (error) {
console.error('获取代理信息失败', error)
}
}
//
const submitApplication = async (formData) => {
try {
const { region, mobile, wechat_id, code } = formData
let postData = {
region,
mobile,
wechat_id,
code,
}
if (!isSelf.value) {
postData.ancestor = ancestor.value
}
const res = await applyAgent(postData)
if (res.code === 200) {
showApplyPopup.value = false
uni.showToast({
title: "已提交申请",
icon: 'success'
})
if (res.data.accessToken) {
uni.setStorageSync('token', res.data.accessToken)
uni.setStorageSync('refreshAfter', res.data.refreshAfter)
uni.setStorageSync('accessExpire', res.data.accessExpire)
refreshAgentStatus()
}
} else {
uni.showToast({
title: res.msg || '申请失败',
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: '网络错误',
icon: 'none'
})
}
}
//
const refreshAgentStatus = () => {
if (status.value === 3) {
if (intervalId) clearInterval(intervalId)
intervalId = setInterval(() => {
if (status.value !== 3) {
clearInterval(intervalId)
intervalId = null
return
}
getAgentInformation()
}, 2000)
} else {
if (intervalId) {
clearInterval(intervalId)
intervalId = null
}
}
}
onLoad(() => {
const token = uni.getStorageSync('token')
if (token) {
//
const agentInfo = uni.getStorageSync('agentInfo')
if (agentInfo) {
status.value = agentInfo.status || 3
}
getAgentInformation()
}
})
//
onUnload(() => {
if (intervalId) {
clearInterval(intervalId)
intervalId = null
}
})
</script>
<route type="page" lang="json">{
"layout": "page",
"title": "代理申请",
"auth": true
}</route>

View File

@ -1,6 +1,6 @@
<script setup>
import { getCode, login } from '@/api/apis'
import { getCode, login, getUserInfo } from '@/api/apis'
import { getAgentInfo } from '@/apis/agent'
const phoneNumber = ref('')
const verificationCode = ref('')
const password = ref('')
@ -72,10 +72,13 @@ function handleLogin() {
return
}
login({ mobile: phoneNumber.value, code: verificationCode.value }).then((res) => {
console.log('res.data.AccessToken', res.data.accessToken)
if (res.code === 200) {
uni.setStorageSync('token', res.data.accessToken)
uni.setStorageSync('refreshAfter', res.data.refreshAfter)
uni.setStorageSync('accessExpire', res.data.accessExpire)
uni.showToast({ title: '登录成功', icon: 'none' })
getUser()
getAgentInformation()
uni.reLaunch({
url: '/pages/index',
})
@ -88,14 +91,50 @@ function handleLogin() {
function toUserAgreement() {
uni.navigateTo({
url: '/pages/userAgreement',
url: '/pages/agreement?type=user',
})
}
function toPrivacyPolicy() {
uni.navigateTo({
url: '/pages/privacyPolicy',
url: '/pages/agreement?type=privacy',
})
}
const getAgentInformation = async () => {
const token = uni.getStorageSync("token")
if (!token) {
return
}
try {
const res = await getAgentInfo()
if (res.code === 200 && res.data) {
//
uni.setStorageSync("agentInfo", {
level: res.data.level,
isAgent: res.data.is_agent, //
status: res.data.status, // 0=1=2=3=
agentID: res.data.agent_id,
mobile: res.data.mobile
})
console.log('代理信息已获取并存入缓存')
}
} catch (error) {
console.error('获取代理信息失败', error)
}
}
const getUser = async () => {
const token = uni.getStorageSync("token")
if (!token) {
return
}
const res = await getUserInfo()
if (res.code === 200) {
console.log(res.data)
uni.setStorageSync("userInfo", res.data.userInfo)
}
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
@ -107,47 +146,32 @@ onUnmounted(() => {
<view class="login px-8">
<view class="mb-8 pt-8 text-left">
<view class="flex flex-col items-center">
<image
class="h-18 w-18 rounded-full shadow"
src="/static/image/logo.png"
mode="scaleToFill"
/>
<image
class="mt-4 h-10"
src="/static/image/logo_title.png"
mode="aspectFit"
/>
<image class="h-18 w-18 rounded-full shadow" src="/static/image/logo.png" mode="scaleToFill" />
<image class="mt-4 h-10" src="/static/image/logo_title.png" mode="aspectFit" />
</view>
</view>
<view class="space-y-5">
<view class="input-container bg-blue-300/20" :class="[phoneFocused ? 'focused' : '']">
<input
v-model="phoneNumber" class="input-field" type="number" placeholder="请输入手机号" maxlength="11"
@focus="phoneFocused = true" @blur="phoneFocused = false"
>
<input v-model="phoneNumber" class="input-field" type="number" placeholder="请输入手机号" maxlength="11"
@focus="phoneFocused = true" @blur="phoneFocused = false">
</view>
<view v-if="!isPasswordLogin">
<view class="flex items-center justify-between">
<view class="input-container bg-blue-300/20" :class="[codeFocused ? 'focused' : '']">
<input
v-model="verificationCode" class="input-field" type="number" placeholder="请输入验证码" maxlength="6"
@focus="codeFocused = true" @blur="codeFocused = false"
>
<input v-model="verificationCode" class="input-field" type="number" placeholder="请输入验证码" maxlength="6"
@focus="codeFocused = true" @blur="codeFocused = false">
</view>
<view
class="ml-2 flex-shrink-0 rounded-lg px-4 py-2 text-sm font-bold transition duration-300 focus:outline-none"
:class="isCountingDown || !isPhoneNumberValid ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'bg-blue-500 text-white hover:bg-blue-600'"
@click="sendVerificationCode"
>
@click="sendVerificationCode">
{{ isCountingDown ? `${countdown}s重新获取` : '获取验证码' }}
</view>
</view>
</view>
<view v-if="isPasswordLogin" class="input-container" :class="[passwordFocused ? 'focused' : '']">
<input
v-model="password" class="input-field" type="password" placeholder="请输入密码"
@focus="passwordFocused = true" @blur="passwordFocused = false"
>
<input v-model="password" class="input-field" type="password" placeholder="请输入密码"
@focus="passwordFocused = true" @blur="passwordFocused = false">
</view>
<view class="flex items-start space-x-2">
<wd-checkbox v-model="isAgreed" class="mt-1" />
@ -165,17 +189,15 @@ onUnmounted(() => {
</view>
<button
class="mt-20 block w-full flex-shrink-0 rounded-full bg-blue-500 py-3 text-lg text-white font-bold transition duration-300"
@click="handleLogin"
>
@click="handleLogin">
登录
</button>
</view>
</template>
<style scoped>
.login{
.login {}
}
.input-container {
border: 2px solid rgba(125, 211, 252, 0.0);
border-radius: 1rem;
@ -195,9 +217,7 @@ onUnmounted(() => {
}
</style>
<route lang="json">
{
<route lang="json">{
"layout": "login",
"title": "登录"
}
</route>
}</route>

View File

@ -1,125 +1,246 @@
<script setup>
import { getUserInfo } from '@/api/apis'
const userName = ref('点击登录')
const userAvatar = ref('https://img0.baidu.com/it/u=1240274933,2284862568&fm=253&fmt=auto&app=138&f=PNG?w=180&h=180')
const isLoggedIn = ref(false)
const features = ref([
{ title: '我的报告', icon: 'list', action: () => toHistory() },
{ title: '联系客服', icon: 'service', action: () => toService() },
{ title: '用户协议', icon: 'file', action: () => toUserAgreement() },
{ title: '退出登录', icon: 'logout', action: () => handleLogout() },
])
function toHistory() {
uni.navigateTo({
url: '/pages/queryHistory',
})
}
function toUserAgreement() {
uni.navigateTo({
url: '/pages/userAgreement',
})
}
function redirectToLogin() {
uni.reLaunch({ url: '/pages/login' }) // 使 uni-app
}
function handleLogout() {
uni.removeStorageSync('token')
isLoggedIn.value = false
userName.value = '点击登录'
userAvatar.value = 'https://img0.baidu.com/it/u=1240274933,2284862568&fm=253&fmt=auto&app=138&f=PNG?w=180&h=180'
}
function toService() {
uni.navigateTo({
url: '/pages/service',
})
}
async function fetchUserInfo() {
try {
// API
getUserInfo().then((res) => {
if (res.code === 200) {
console.log('res', res)
const userinfo = res.data.userInfo
userName.value = userinfo.nickName || ''
userAvatar.value = userinfo.userAvatar || 'https://img0.baidu.com/it/u=1240274933,2284862568&fm=253&fmt=auto&app=138&f=PNG?w=180&h=180'
isLoggedIn.value = true
}
})
}
catch (error) {
console.error('获取用户信息失败', error)
}
}
const safeAreaTop = ref(0)
onMounted(() => {
const token = uni.getStorageSync('token')
if (token) {
isLoggedIn.value = true
fetchUserInfo()
}
else {
isLoggedIn.value = false
}
uni.getSystemInfo({
success: (res) => {
if (res.safeArea) {
safeAreaTop.value = res.safeArea.top
}
},
})
})
</script>
<template>
<view
class="box-border min-h-screen from-blue-100 to-white bg-gradient-to-b" style="paddingTop:44px"
>
<view class="flex flex-col p-4">
<view class="profile-section mb-4 flex items-center gap-4 rounded-md bg-white p-4 shadow-md" @click="!isLoggedIn ? redirectToLogin() : null">
<wd-img :src="userAvatar" round width="100" height="100" />
<view>
<h2 class="text-lg font-bold">
{{ isLoggedIn ? userName : '点击登录' }}
</h2>
<view class="safe-area-top box-border min-h-screen">
<view class="flex flex-col p-4 space-y-6">
<!-- 用户信息卡片 -->
<view
class="profile-section group relative flex items-center gap-4 rounded-xl bg-white p-6 shadow-lg transition-all hover:shadow-xl"
@click="!isLoggedIn ? redirectToLogin() : null">
<view class="relative">
<!-- 头像容器添加overflow-hidden解决边框问题 -->
<view class="flex items-center justify-center overflow-hidden rounded-full p-0.5"
:class="levelGradient.border">
<image :src="userAvatar || headShot" alt="User Avatar" class="h-24 w-24 rounded-full border-4 border-white">
</image>
</view>
<!-- 代理标识 -->
<view v-if="isAgent" class="absolute -bottom-2 -right-2">
<view class="flex items-center justify-center rounded-full px-3 py-1 text-xs font-bold text-white shadow-sm"
:class="levelGradient.badge">
{{ levelNames[level] }}
</view>
</view>
</view>
<view class="space-y-1">
<view class="text-2xl font-bold text-gray-800">
{{ isLoggedIn ? maskName(userName) : '点击登录' }}
</view>
<view v-if="isAgent" class="text-sm font-medium" :class="levelGradient.text">
🎖 {{ levelText[level] }}
</view>
</view>
</view>
<VipBanner v-if="isAgent && level === 'normal'" />
<!-- 功能菜单 -->
<view class="features-section space-y-3">
<template v-if="isAgent && ['VIP', 'SVIP'].includes(level)">
<button
class="feature-item bg-gradient-to-r from-purple-200/80 to-pink-200/80 hover:from-purple-300/80 hover:to-pink-300/80 text-purple-700"
@click="toVipConfig">
代理报告配置
</button>
</template>
<Wdviewider />
<view class="features-section flex flex-col gap-2">
<WdCell
v-for="(feature, index) in features"
:key="index"
:title="feature.title"
:icon="feature.icon"
class="feature-item rounded-md bg-white p-3 shadow-sm"
clickable
@click="feature.action"
/>
<button class="feature-item hover:bg-blue-50" @click="toHistory">
📃 我的报告
</button>
<button class="feature-item hover:bg-blue-50" @click="toUserAgreement">
📜 用户协议
</button>
<button class="feature-item hover:bg-blue-50" @click="toService">
💬 联系客服
</button>
<button class="feature-item hover:bg-red-50 text-red-600" @click="handleLogout">
退出登录
</button>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.profile-section {
@apply flex items-center gap-4 p-4 bg-white rounded-md shadow-md mb-4;
<script setup>
import { ref, computed, onBeforeMount } from 'vue'
import headShot from "@/static/image/head_shot.webp"
//
const userName = ref('')
const userAvatar = ref('')
const isLoggedIn = ref(false)
//
const isAgent = ref(false)
const level = ref('normal')
//
onBeforeMount(() => {
//
const token = uni.getStorageSync('token')
if (token) {
isLoggedIn.value = true
//
const userInfo = uni.getStorageSync('userInfo')
console.log("userInfo", userInfo)
if (userInfo) {
userName.value = userInfo.nickName || '用户'
userAvatar.value = userInfo.avatar || ''
}
//
const agentInfo = uni.getStorageSync('agentInfo')
if (agentInfo?.isAgent) {
isAgent.value = agentInfo.isAgent
level.value = agentInfo.level || 'normal'
}
}
})
const levelNames = {
normal: '普通代理',
VIP: 'VIP代理',
SVIP: 'SVIP代理'
}
.features-section {
@apply flex flex-col gap-2;
const levelText = {
normal: '基础代理特权',
VIP: '高级代理特权',
SVIP: '尊享代理特权'
}
const levelGradient = computed(() => ({
border: {
'normal': 'bg-green-300',
'VIP': 'bg-gradient-to-r from-yellow-400 to-amber-500',
'SVIP': 'bg-gradient-to-r from-purple-400 to-pink-400 shadow-[0_0_15px_rgba(163,51,200,0.2)]'
}[level.value],
badge: {
'normal': 'bg-green-500',
'VIP': 'bg-gradient-to-r from-yellow-500 to-amber-600',
'SVIP': 'bg-gradient-to-r from-purple-500 to-pink-500'
}[level.value],
text: {
'normal': 'text-green-600',
'VIP': 'text-amber-600',
'SVIP': 'text-purple-600'
}[level.value]
}))
function maskName(name) {
if (!name || name.length < 11) return name
return name.substring(0, 3) + "****" + name.substring(7)
}
function toHistory() {
uni.navigateTo({
url: '/pages/queryHistory'
})
}
function toUserAgreement() {
uni.navigateTo({
url: '/pages/agreement?type=user'
})
}
function redirectToLogin() {
uni.navigateTo({
url: '/pages/login'
})
}
function handleLogout() {
uni.removeStorageSync('token')
uni.removeStorageSync('refreshAfter')
uni.removeStorageSync('accessExpire')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('agentInfo')
//
isLoggedIn.value = false
userName.value = ''
userAvatar.value = ''
isAgent.value = false
level.value = 'normal'
uni.reLaunch({
url: '/pages/index'
})
}
function toService() {
// #ifdef APP-PLUS
plus.runtime.openURL('https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9')
// #endif
// #ifdef H5
window.location.href = 'https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9'
// #endif
// #ifdef MP
uni.setClipboardData({
data: 'https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9',
success: function () {
uni.showToast({
title: '客服链接已复制,请在浏览器中打开',
icon: 'none'
})
}
})
// #endif
}
function toVipConfig() {
uni.navigateTo({
url: '/pages/agentVipConfig'
})
}
</script>
<style scoped>
.profile-section {
background: linear-gradient(135deg, #ffffff 50%, rgba(236, 253, 245, 0.3));
border: 1px solid rgba(209, 213, 219, 0.2);
}
.profile-section .relative>view:first-child {
transition: all 0.3s ease;
}
.feature-item {
@apply bg-white p-3 rounded-md shadow-sm;
transition:
transform 0.2s ease,
background 0.3s ease,
box-shadow 0.3s ease;
display: flex;
width: 100%;
align-items: center;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-right: 0.75rem;
border-radius: 0.75rem;
background-color: #ffffff;
padding: 1rem 1.5rem;
text-align: left;
color: #4b5563;
transition-property: all;
transition-duration: 300ms;
}
.feature-item:active {
transform: scale(1.02);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.border-gradient-to-r {
border-image: linear-gradient(to right, var(--tw-gradient-from), var(--tw-gradient-to)) 1;
}
.shadow-glow {
box-shadow: 0 0 8px rgba(163, 51, 200, 0.2);
}
</style>
<route lang="json">
{
"layout": "home"
}
</route>
<route lang="json">{
"layout": "home"
}</route>

View File

@ -1,98 +0,0 @@
<script setup>
import { payment, queryProvisionalOrder } from '@/api/apis'
const selectedPaymentMethod = ref('alipay')
const id = ref(null)
const order = ref({
productName: '',
price: null,
})
function handlePayment() {
if (selectedPaymentMethod.value === 'alipay') {
payment({ id: id.value, pay_method: selectedPaymentMethod.value }).then((res) => {
if (res.code === 200) {
uni.requestPayment({
provider: 'alipay', //
orderInfo: res.data.prepay_id, // orderInfo
success: () => {
handlePaySuccess(res.data.order_id)
},
fail: (err) => {
console.log('支付失败:', err)
},
})
}
})
}
}
function handlePaySuccess(orderID) {
uni.redirectTo({
url: `/pages/result?id=${orderID}`,
})
}
onLoad((option) => {
if (option.id) {
id.value = option.id
queryProvisionalOrder(option.id).then((res) => {
console.log('res', res)
if (res.code === 200) {
order.value.productName = res.data.product.product_name
order.value.price = res.data.product.sell_price
}
})
}
})
</script>
<template>
<view class="min-h-screen from-blue-200 via-sky-200 to-sky-100 bg-gradient-to-b p-6">
<view class="card">
<h1 class="mb-4 text-xl font-bold">
订单支付
</h1>
<view class="my-10 text-center">
<view class="text-2xl font-bold">
¥{{ order.price }}
</view>
<view class="text-gray-600">
{{ order.productName }}
</view>
</view>
<view class="mb-4">
<label class="mb-2 block text-sm text-gray-600">支付方式</label>
<wd-radio-group v-model="selectedPaymentMethod" shape="dot" size="large">
<view class="border-3 border-blue-500 rounded-lg border-solid px-4 py-2">
<wd-radio value="alipay">
<view class="flex" items-center>
<image
src="/static/image/alipay_icon.svg"
mode="aspectFit"
class="mr-1 h-5 w-5"
/>
</view>
</wd-radio>
</view>
</wd-radio-group>
</view>
<button
class="w-full rounded-xl from-blue-500 via-blue-500 to-blue-400 bg-gradient-to-b px-4 py-2 text-white"
@click="handlePayment"
>
立即支付
</button>
</view>
</view>
</template>
<style scoped>
:deep(.wd-radio){
margin-top: 0;
}
</style>
<route lang="json">
{
"layout": "page",
"title": "全能查收款"
}
</route>

View File

@ -1,164 +0,0 @@
<script setup>
import { iapPaymentCallback, payment, queryProvisionalOrder } from '@/api/apis'
const selectedPaymentMethod = ref('appleiap')
const id = ref(null)
const order = ref({
productName: '',
price: null,
})
async function handlePayment() {
try {
if (selectedPaymentMethod.value === 'appleiap') {
const paymentResponse = await payment({ id: id.value, pay_method: selectedPaymentMethod.value })
if (paymentResponse.code === 200) {
uni.showLoading({ title: '加载中' })
const productID = paymentResponse.data.prepay_id
const orderID = paymentResponse.data.order_id
const iapChannel = await getIapChannel()
const products = await requestProduct(iapChannel, [productID])
if (products.length > 0) {
const product = products[0]
uni.requestPayment({
provider: 'appleiap',
orderInfo: { productid: product.productid },
success: async (iapRes) => {
const callbackResponse = await iapPaymentCallback({
order_id: orderID,
transaction_receipt: iapRes.transactionReceipt,
})
if (callbackResponse.code === 200) {
handlePaySuccess(orderID)
}
else {
console.error('支付回调处理失败:', callbackResponse)
}
},
fail: (err) => {
console.error('支付失败:', err)
},
})
}
else {
console.error('未找到对应的产品信息')
}
}
else {
console.error('支付请求失败:', paymentResponse)
}
}
else {
console.error('未选择 Apple IAP 支付方式')
}
}
catch (error) {
console.error('支付流程中发生错误:', error)
}
finally {
uni.hideLoading()
}
}
async function getIapChannel() {
return new Promise((resolve, reject) => {
uni.showLoading({ title: '加载中' })
plus.payment.getChannels((channels) => {
const iapChannel = channels.find(channel => channel.id === 'appleiap')
if (iapChannel) {
resolve(iapChannel)
}
else {
reject(new Error('未找到 Apple IAP 支付通道'))
}
}, (error) => {
reject(new Error(`获取支付通道失败:${error.message}`))
})
})
}
async function requestProduct(iapChannel, productIds) {
return new Promise((resolve, reject) => {
uni.showLoading({ title: '加载中' })
console.log('请求的产品 ID 列表:', productIds)
iapChannel.requestOrder(productIds, (products) => {
resolve(products)
}, (error) => {
reject(new Error(`请求产品信息失败:${error.message}`))
})
})
}
function handlePaySuccess(orderID) {
uni.redirectTo({
url: `/pages/result?id=${orderID}`,
})
}
onLoad((option) => {
if (option.id) {
id.value = option.id
queryProvisionalOrder(option.id).then((res) => {
console.log('res', res)
if (res.code === 200) {
order.value.productName = res.data.product.product_name
order.value.price = res.data.product.sell_price
}
})
}
})
</script>
<template>
<view class="min-h-screen from-blue-200 via-sky-200 to-sky-100 bg-gradient-to-b p-6">
<view class="card">
<h1 class="mb-4 text-xl font-bold">
订单支付
</h1>
<view class="my-10 text-center">
<view class="text-2xl font-bold">
¥{{ order.price }}
</view>
<view class="text-gray-600">
{{ order.productName }}
</view>
</view>
<view class="mb-4">
<label class="mb-2 block text-sm text-gray-600">支付方式</label>
<wd-radio-group v-model="selectedPaymentMethod" shape="dot" size="large">
<view class="border-3 border-blue-500 rounded-lg border-solid px-4 py-2">
<wd-radio value="appleiap">
<view class="flex items-center">
<image
src="/static/image/apple.svg"
mode="aspectFit"
class="mr-1 h-5 w-5"
/> Apple Pay
</view>
</wd-radio>
</view>
</wd-radio-group>
</view>
<button
class="w-full rounded-xl from-blue-500 via-blue-500 to-blue-400 bg-gradient-to-b px-4 py-2 text-white"
@click="handlePayment"
>
立即支付
</button>
</view>
</view>
</template>
<style scoped>
:deep(.wd-radio) {
margin-top: 0;
}
</style>
<route lang="json">
{
"layout": "page",
"title": "全能查收款"
}
</route>

View File

@ -1,22 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" src="https://app.quannengcha.com/privacyPolicy" @message="handleMessage" />
</view>
</template>
<route lang="json">
{
"layout": "page",
"title": "隐私政策"
}
</route>

245
src/pages/promote.vue Normal file
View File

@ -0,0 +1,245 @@
<template>
<view class="min-h-screen p-4 promote">
<view class="mb-4 card !bg-gradient-to-b from-orange-200 to-orange-200/80">
<view>
<text class="text-lg font-bold text-orange-500 block">直推用户查询</text>
<text class="font-bold text-orange-400 mt-1 block">自定义价格赚取差价</text>
</view>
<view class="mt-6">
<view class="mt-2 text-gray-600 bg-orange-100 rounded-xl px-4 py-2">
在下方 "自定义价格" 处选择报告类型设置客户查询价即可立即推广
</view>
</view>
</view>
<VipBanner />
<!-- 推广内容 -->
<view>
<view class="card mb-4">
<view>
<text class="text-xl font-semibold mb-2 block">生成推广码</text>
<wd-form :model="formData" ref="promotionForm">
<wd-cell-group border>
<!-- 报告类型 -->
<wd-picker label="报告类型" label-width="100px" v-model="formData.productType" :columns="[reportTypes]"
title="选择报告类型" prop="productType" placeholder="请选择报告类型" @confirm="onConfirmType"
:rules="[{ required: true, message: '请选择报告类型' }]" />
<!-- 定价 -->
<wd-input label="客户查询价" label-width="100px" v-model="formData.clientPrice" placeholder="请输入价格" readonly
clickable @click="showPricePicker = true" prop="clientPrice" suffix-icon="arrow-right"
:rules="[{ required: true, message: '请输入客户查询价' }]" />
</wd-cell-group>
<view class="flex items-center justify-between my-2">
<text class="text-sm text-gray-500">推广收益为 <text class="text-orange-500">{{ promotionRevenue }}</text>
</text>
<text class="text-sm text-gray-500">我的成本为 <text class="text-orange-500">{{ costPrice }}</text> </text>
</view>
</wd-form>
</view>
<view class="mt-6">
<button type="primary" block @click="generatePromotionCode">点击立即推广</button>
</view>
</view>
</view>
<PriceInputPopup v-model:show="showPricePicker" :default-price="formData.clientPrice"
:product-config="pickerProductConfig" @change="onPriceChange" />
<QRcode v-model:show="showQRcode" :linkIdentifier="linkIdentifier" />
</view>
</template>
<script setup>
import { getProductConfig, generatePromotionLink } from '@/apis/agent'
import PriceInputPopup from '@/components/PriceInputPopup.vue'
import VipBanner from '@/components/VipBanner.vue'
import QRcode from '@/components/QRcode.vue'
//
const reportTypes = [
{ label: '人事背调', value: 'backgroundcheck', id: 1 },
{ label: '老板企业报告', value: 'companyinfo', id: 2 },
{ label: '家政风险', value: 'homeservice', id: 3 },
{ label: '婚恋风险', value: 'marriage', id: 4 },
{ label: '贷前背调', value: 'preloanbackgroundcheck', id: 5 },
{ label: '租赁风险', value: 'rentalrisk', id: 6 },
{ label: '个人风险', value: 'riskassessment', id: 7 }
]
//
const promotionForm = ref(null)
const showPricePicker = ref(false)
const pickerProductConfig = ref(null)
const productConfig = ref(null)
const linkIdentifier = ref("")
const showQRcode = ref(false)
//
const formData = ref({
productType: '',
clientPrice: null
})
//
const costPrice = computed(() => {
if (!pickerProductConfig.value) return '0.00'
//
let platformPricing = 0
platformPricing += pickerProductConfig.value.cost_price
if (formData.value.clientPrice > pickerProductConfig.value.p_pricing_standard) {
platformPricing += (formData.value.clientPrice - pickerProductConfig.value.p_pricing_standard) * pickerProductConfig.value.p_overpricing_ratio
}
if (pickerProductConfig.value.a_pricing_standard > platformPricing &&
pickerProductConfig.value.a_pricing_end > platformPricing &&
pickerProductConfig.value.a_overpricing_ratio > 0) {
if (formData.value.clientPrice > pickerProductConfig.value.a_pricing_standard) {
if (formData.value.clientPrice > pickerProductConfig.value.a_pricing_end) {
platformPricing += (pickerProductConfig.value.a_pricing_end - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
} else {
platformPricing += (formData.value.clientPrice - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
}
}
}
return safeTruncate(platformPricing)
})
// 广
const promotionRevenue = computed(() => {
return safeTruncate(formData.value.clientPrice - costPrice.value)
})
// 2
function safeTruncate(num, decimals = 2) {
if (isNaN(num) || !isFinite(num)) return "0.00"
const factor = 10 ** decimals
const scaled = Math.trunc(num * factor)
const truncated = scaled / factor
return truncated.toFixed(decimals)
}
// 广
const generatePromotionCode = async () => {
//
try {
await promotionForm.value.validate()
} catch (e) {
return
}
try {
//
const reportType = reportTypes.find(item => item.value === formData.value.productType)
if (!reportType) {
uni.showToast({
title: '请选择有效的报告类型',
icon: 'none'
})
return
}
const res = await generatePromotionLink({
product: formData.value.productType,
price: formData.value.clientPrice
})
if (res.code === 200) {
linkIdentifier.value = res.data.link_identifier
showQRcode.value = true
} else {
uni.showToast({
title: res.msg || '生成推广码失败',
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: '网络错误',
icon: 'none'
})
}
}
//
const selectProductType = (reportTypeValue) => {
const reportType = reportTypes.find(item => item.id === reportTypeValue || item.value === reportTypeValue)
if (!reportType) return
formData.value.productType = reportType.value
if (productConfig.value) {
for (let i of productConfig.value) {
if (i.product_id === reportType.id) {
pickerProductConfig.value = i
formData.value.clientPrice = i.p_pricing_standard.toString()
}
}
}
}
//
const getPromoteConfig = async () => {
try {
const res = await getProductConfig()
if (res.code === 200) {
productConfig.value = res.data.AgentProductConfig
//
selectProductType(1) // 使ID 1
} else {
uni.showToast({
title: res.msg || '获取配置失败',
icon: 'none'
})
}
} catch (error) {
console.log(error)
uni.showToast({
title: '网络错误',
icon: 'none'
})
}
}
//
const onPriceChange = (price) => {
formData.value.clientPrice = price
}
//
const onConfirmType = (e) => {
// picker
if (e && e.value && e.value.length > 0) {
const selectedValue = e.value[0]
selectProductType(selectedValue)
}
}
//
onMounted(() => {
getPromoteConfig()
})
</script>
<style>
.card {
border-radius: 12px;
background-color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
padding: 16px;
margin-bottom: 16px;
}
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "推广",
"agent": true,
"auth": true
}</route>

View File

@ -0,0 +1,144 @@
<template>
<view class="min-h-screen bg-gray-50">
<!-- 收益列表 -->
<uni-list :loading="loading" :loadmore="loadMoreStatus" @loadmore="onLoadMore">
<!-- 空状态提示 -->
<view v-if="!loading && list.length === 0" class="flex flex-col items-center justify-center py-16">
<image src="/static/image/empty.svg" mode="aspectFit" class="w-48 h-48 mb-4" />
<text class="text-gray-400 text-base">暂无直推报告</text>
</view>
<view v-for="(item, index) in list" :key="index" class="mx-4 my-2 bg-white rounded-lg p-4 shadow-sm">
<view class="flex justify-between items-center mb-2">
<text class="text-gray-500 text-sm">{{ item.create_time || '-' }}</text>
<text class="text-green-500 font-bold">+{{ item.amount.toFixed(2) }}</text>
</view>
<view class="flex items-center">
<text class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium"
:class="getReportTypeStyle(item.product_name)">
<text class="w-2 h-2 rounded-full mr-1 inline-block" :class="getDotColor(item.product_name)"></text>
{{ item.product_name }}
</text>
</view>
</view>
<!-- 加载更多/加载完成提示 -->
<uni-load-more :status="loadMoreStatus" />
</uni-list>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { getAgentCommission } from '@/apis/agent'
//
const typeColors = {
'老板企业报告': { bg: 'bg-blue-100', text: 'text-blue-800', dot: 'bg-blue-500' },
'人事背调': { bg: 'bg-green-100', text: 'text-green-800', dot: 'bg-green-500' },
'家政风险': { bg: 'bg-purple-100', text: 'text-purple-800', dot: 'bg-purple-500' },
'婚恋风险': { bg: 'bg-pink-100', text: 'text-pink-800', dot: 'bg-pink-500' },
'贷前背调': { bg: 'bg-orange-100', text: 'text-orange-800', dot: 'bg-orange-500' },
'租赁风险': { bg: 'bg-indigo-100', text: 'text-indigo-800', dot: 'bg-indigo-500' },
'个人风险': { bg: 'bg-red-100', text: 'text-red-800', dot: 'bg-red-500' },
//
'default': { bg: 'bg-gray-100', text: 'text-gray-800', dot: 'bg-gray-500' }
}
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const list = ref([])
const loading = ref(false)
const loadMoreStatus = ref('more') // 'more'|'loading'|'noMore'
//
const getReportTypeStyle = (name) => {
const color = typeColors[name] || typeColors.default
return `${color.bg} ${color.text}`
}
//
const getDotColor = (name) => {
return (typeColors[name] || typeColors.default).dot
}
//
const onLoadMore = async () => {
if (loadMoreStatus.value === 'noMore') return
page.value++
await getData()
}
//
const getData = async () => {
try {
loading.value = true
loadMoreStatus.value = 'loading'
const res = await getAgentCommission({
page: page.value,
page_size: pageSize.value
})
if (res.code === 200) {
//
if (page.value === 1) {
list.value = res.data.list
total.value = res.data.total
} else {
//
list.value.push(...res.data.list)
}
//
if (list.value.length >= res.data.total || res.data.list.length < pageSize.value) {
loadMoreStatus.value = 'noMore'
} else {
loadMoreStatus.value = 'more'
}
} else {
uni.showToast({
title: res.msg || '加载失败',
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: '网络错误',
icon: 'none'
})
} finally {
loading.value = false
}
}
//
onMounted(() => {
getData()
})
//
const onPullDownRefresh = () => {
page.value = 1
loadMoreStatus.value = 'more'
getData().then(() => {
uni.stopPullDownRefresh()
})
}
//
defineExpose({
onPullDownRefresh
})
</script>
<route type="page" lang="json">
{
"layout": "page",
"title": "直推报告",
"agent": true,
"auth": true
}
</route>

View File

@ -98,10 +98,8 @@ function statusClass(state) {
</script>
<template>
<wd-notice-bar
text="为保证用户的隐私以及数据安全您的报告生成30天之后将自动清除请及时保存您的报告。" prefix="warn-bold" color="#007aff"
background-color="#f8f8f8"
/>
<!-- <wd-notice-bar text="为保证用户的隐私以及数据安全您的报告生成30天之后将自动清除请及时保存您的报告。" prefix="warn-bold" color="#007aff"
background-color="#f8f8f8" /> -->
<view class="flex flex-col gap-4 p-4">
<view v-for="item in reportList" :key="item.id" class="card flex flex-col gap-2" @click="toDetail(item)">
<view class="flex items-center justify-between">
@ -117,7 +115,7 @@ function statusClass(state) {
报告类型
</view>
<view>
{{ getProductName(item.product_id) }}
{{ item.product_name }}
</view>
</view>
<view class="flex items-center justify-between">
@ -148,9 +146,8 @@ function statusClass(state) {
}
</style>
<route lang="json">
{
"layout": "page",
"title": "历史报告"
}
</route>
<route lang="json">{
"layout": "page",
"title": "历史报告",
"auth": true
}</route>

View File

@ -1,204 +0,0 @@
<script setup>
import CBad from '@/ui/CBad.vue'
import CBankLoanApplication from '@/ui/CBankLoanApplication.vue'
import CBankLoanBehavior from '@/ui/CBankLoanBehavior.vue'
import CLawsuit from '@/ui/CLawsuit.vue'
import CRelatedEnterprises from '@/ui/CRelatedEnterprises.vue'
import CSpecialList from '@/ui/CSpecialList.vue'
import CTabs from '@/ui/CTabs.vue'
import { queryResultByOrder } from '@/api/apis'
import CMarriage from '@/ui/CMarriage.vue'
const productMap = {
1: '背景调查',
2: '企业报告',
3: '家政服务',
4: '婚姻状态',
5: '贷前背景调查',
6: '租赁服务',
7: '个人风险评估',
}
// product_id
function getProductName(productId) {
return productMap[productId] || '未知类型'
}
const productId = ref(null)
const isDone = ref(false)
const entData = ref(null)
const lawsuitData = ref(null)
const badData = ref(null)
const specialData = ref(null)
const bankLoanApplicationData = ref(null)
const marriageData = ref(null)
const bankLoanBehavior = ref(null)
const tabs = ref([
{ label: '报告概述', value: 'overview' },
])
const reportItems = ref([
])
const sortedReportItems = computed(() => {
return reportItems.value.slice().sort((a, b) => a.sort - b.sort)
})
const sortedTabs = computed(() => {
return tabs.value.slice().sort((a, b) => a.sort - b.sort)
})
onLoad((option) => {
console.log('option', option)
const { id } = option
if (id) {
queryResultByOrder(id).then((res) => {
console.log('res', res)
if (res.code === 200) {
productId.value = res.data.product_id
res.data.query_data.forEach((item) => {
if (item.success) {
switch (item.apiID) {
case 'G09SC02':
marriageData.value = item.data
tabs.value.push({ label: '婚姻状态', value: 'marriage', sort: 1 })
reportItems.value.push({ label: '婚姻状态', value: 'marriage', sort: 1 })
break
case 'G27BJ05':
bankLoanApplicationData.value = item.data
tabs.value.push({ label: '借贷申请记录', value: 'netloan', sort: 7 })
reportItems.value.push({ label: '借贷申请记录', value: 'netloan', sort: 7 })
break
case 'G28BJ05':
bankLoanBehavior.value = item.data
tabs.value.push({ label: '借贷记录', value: 'loan', sort: 6 })
reportItems.value.push({ label: '借贷记录', value: 'loan', sort: 6 })
break
case 'G26BJ05':
specialData.value = item.data
tabs.value.push({ label: '异常名单', value: 'special', sort: 5 })
reportItems.value.push({ label: '异常名单', value: 'special', sort: 5 })
break
case 'G05HZ01':
entData.value = item.data
tabs.value.push({ label: '关联企业', value: 'ent', sort: 4 })
reportItems.value.push({ label: '关联企业', value: 'ent', sort: 4 })
break
case 'G34BJ03':
badData.value = item.data
tabs.value.push({ label: '不良风险评估', value: 'bad', sort: 3 })
reportItems.value.push({ label: '不良风险评估', value: 'bad', sort: 3 })
break
case 'G35SC01':
lawsuitData.value = item.data
tabs.value.push({ label: '涉诉案件', value: 'lawsuit', sort: 2 })
reportItems.value.push({ label: '涉诉案件', value: 'lawsuit', sort: 2 })
break
default:
console.log(`未知的apiID: ${item.apiID}`)
}
}
})
}
}).finally(() => {
isDone.value = true
})
}
})
</script>
<template>
<div class="min-h-full from-blue-100 to-white bg-gradient-to-b">
<CTabs
:tabs="sortedTabs"
type="blue-green"
/>
<template v-if="isDone">
<div class="flex flex-col gap-y-4 p-4 pt-12">
<div id="overview" class="title">
报告概述
</div>
<div class="card">
<div class="flex flex-col gap-y-2">
<div class="flex justify-between">
<span class="text-gray-700 font-bold">报告时间</span>
<span class="text-gray-600">2024年11月18日 23:11:23</span>
</div>
<div class="flex justify-between">
<span class="text-gray-700 font-bold">报告项目</span>
<span class="text-gray-600">{{ getProductName(productId) }}</span>
</div>
</div>
<div>
<LTitle class="my-4" title="报告内容" type="blue-green" />
<div class="flex flex-col gap-y-2">
<div v-for="item in sortedReportItems" :key="item.value" class="flex justify-between">
<span class="text-gray-700 font-bold">{{ item.label }}</span>
<span class="text-green-500 font-bold">已解锁</span>
</div>
</div>
</div>
</div>
<template v-if="marriageData">
<div id="marriage" class="title">
婚姻状态
</div>
<CMarriage :data="marriageData" />
</template>
<template v-if="lawsuitData">
<div id="lawsuit" class="title">
涉诉案件
</div>
<CLawsuit :data="lawsuitData" />
</template>
<template v-if="badData">
<div id="bad" class="title">
不良风险评估
</div>
<CBad :data="badData" />
</template>
<template v-if="entData">
<div id="ent" class="title">
关联企业
</div>
<CRelatedEnterprises :data="entData" />
</template>
<template v-if="specialData">
<div id="special" class="title">
异常名单
</div>
<CSpecialList :data="specialData" />
</template>
<template v-if="bankLoanBehavior">
<div id="loan" class="title">
借贷记录
</div>
<CBankLoanBehavior :data="bankLoanBehavior" />
</template>
<template v-if="bankLoanApplicationData">
<div id="netloan" class="title">
贷款申请记录
</div>
<CBankLoanApplication :data="bankLoanApplicationData" />
</template>
<view class="card">
<view>
<view>
报告说明
</view>
<view>本报告的数据由用户本人明确授权后我们才向相关合法存有用户个人数据的机构调取本报告相关内容本平台只做大数据的获取与分析仅向用户个人展示参考</view><p> &nbsp; &nbsp; 报告有效期<strong>30</strong>过期自动删除 </p><p> &nbsp; &nbsp; 若您的数据不全面可能是数据具有延迟性或者合作信息机构未获取到您的数据若数据有错误请联系客服</p>
</view>
</view>
</div>
</template>
</div>
</template>
<style lang="scss" scoped>
</style>
<route lang="json">
{
"layout": "page",
"title": "报告结果"
}
</route>

View File

@ -1,40 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
const orderId = ref(null)
const token = ref(null)
const webviewSrc = ref('')
onLoad((option) => {
if (option.id) {
orderId.value = option.id
}
token.value = uni.getStorageSync('token') || ''
const baseUrl = 'https://app.quannengcha.com/report'
webviewSrc.value = `${baseUrl}?order_id=${encodeURIComponent(orderId.value)}&token=${encodeURIComponent(token.value)}`
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" :src="webviewSrc" />
</view>
</template>
<style lang="scss" scoped>
</style>
<route lang="json">
{
"layout": "page",
"title": "报告结果"
}
</route>

View File

@ -0,0 +1,165 @@
<template>
<view class="min-h-screen bg-gray-50">
<!-- 收益列表 -->
<uni-list :loading="loading" :loadmore="loadMoreStatus" @loadmore="onLoadMore">
<!-- 空状态提示 -->
<view v-if="!loading && list.length === 0" class="flex flex-col items-center justify-center py-16">
<image src="/static/image/empty.svg" mode="aspectFit" class="w-48 h-48 mb-4" />
<text class="text-gray-400 text-base">暂无收益记录</text>
</view>
<view v-for="(item, index) in list" :key="index" class="mx-4 my-2 bg-white rounded-lg p-4 shadow-sm">
<view class="flex justify-between items-center mb-2">
<text class="text-gray-500 text-sm">{{ item.create_time || '-' }}</text>
<text class="text-green-500 font-bold">+{{ item.amount.toFixed(2) }}</text>
</view>
<view class="flex items-center">
<text class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium"
:class="getReportTypeStyle(item.type)">
<text class="w-2 h-2 rounded-full mr-1 inline-block" :class="getDotColor(item.type)"></text>
{{ typeToChinese(item.type) }}
</text>
</view>
</view>
<!-- 加载更多/加载完成提示 -->
<uni-load-more :status="loadMoreStatus" />
</uni-list>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { getAgentRewards } from '@/apis/agent'
//
const typeConfig = {
descendant_promotion: {
chinese: '下级推广奖励',
color: { bg: 'bg-blue-100', text: 'text-blue-800', dot: 'bg-blue-500' }
},
descendant_upgrade_vip: {
chinese: '下级升级VIP奖励',
color: { bg: 'bg-green-100', text: 'text-green-800', dot: 'bg-green-500' }
},
descendant_upgrade_svip: {
chinese: '下级升级SVIP奖励',
color: { bg: 'bg-purple-100', text: 'text-purple-800', dot: 'bg-purple-500' }
},
descendant_stay_activedescendant: {
chinese: '下级活跃奖励',
color: { bg: 'bg-pink-100', text: 'text-pink-800', dot: 'bg-pink-500' }
},
new_active: {
chinese: '新增活跃奖励',
color: { bg: 'bg-orange-100', text: 'text-orange-800', dot: 'bg-orange-500' }
},
descendant_withdraw: {
chinese: '下级提现奖励',
color: { bg: 'bg-indigo-100', text: 'text-indigo-800', dot: 'bg-indigo-500' }
},
default: {
chinese: '其他奖励',
color: { bg: 'bg-gray-100', text: 'text-gray-800', dot: 'bg-gray-500' }
}
}
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const list = ref([])
const loading = ref(false)
const loadMoreStatus = ref('more') // 'more'|'loading'|'noMore'
//
const typeToChinese = (type) => {
return typeConfig[type]?.chinese || typeConfig.default.chinese
}
//
const getReportTypeStyle = (type) => {
const config = typeConfig[type] || typeConfig.default
return `${config.color.bg} ${config.color.text}`
}
//
const getDotColor = (type) => {
return typeConfig[type]?.color.dot || typeConfig.default.color.dot
}
//
const onLoadMore = async () => {
if (loadMoreStatus.value === 'noMore') return
page.value++
await getData()
}
//
const getData = async () => {
try {
loading.value = true
loadMoreStatus.value = 'loading'
const res = await getAgentRewards({
page: page.value,
page_size: pageSize.value
})
if (res.code === 200) {
if (page.value === 1) {
list.value = res.data.list
total.value = res.data.total
} else {
list.value.push(...res.data.list)
}
if (list.value.length >= res.data.total || res.data.list.length < pageSize.value) {
loadMoreStatus.value = 'noMore'
} else {
loadMoreStatus.value = 'more'
}
} else {
uni.showToast({
title: res.msg || '加载失败',
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: '网络错误',
icon: 'none'
})
} finally {
loading.value = false
}
}
//
onMounted(() => {
getData()
})
//
const onPullDownRefresh = () => {
page.value = 1
loadMoreStatus.value = 'more'
getData().then(() => {
uni.stopPullDownRefresh()
})
}
//
defineExpose({
onPullDownRefresh
})
</script>
<route type="page" lang="json">
{
"layout": "page",
"title": "收益明细",
"agent": true,
"auth": true
}
</route>

View File

@ -1,22 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" src="https://app.quannengcha.com/service" />
</view>
</template>
<route lang="json">
{
"layout": "page",
"title": "客户服务"
}
</route>

View File

@ -1,22 +0,0 @@
<script setup>
const webviewStyles = ref({
top: `${uni.getSystemInfoSync().statusBarHeight + 44}px`, //
height: `${uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().statusBarHeight - 44}px`, //
position: 'absolute', //
dock: 'bottom', //
bounce: 'vertical', //
})
</script>
<template>
<view>
<web-view :webview-styles="webviewStyles" src="https://app.quannengcha.com/userAgreement" />
</view>
</template>
<route lang="json">
{
"layout": "page",
"title": "用户协议"
}
</route>

26
src/pages/vip.vue Normal file
View File

@ -0,0 +1,26 @@
<template>
<view class="relative">
<image class="w-full" src="/static/images/vip_bg.png" mode="widthFix" />
<view @click="toService"
class="absolute left-[50%] translate-x-[-50%] bottom-80 bg-gradient-to-r from-gray-900 via-black to-gray-900 py-2 px-4 rounded-lg text-white text-[24px] font-bold shadow-[0_0_15px_rgba(255,255,255,0.3)]"
hover-class="scale-105">
点击马上报名
</view>
</view>
</template>
<script setup>
function toService() {
//
uni.navigateTo({
url: 'https://work.weixin.qq.com/kfid/kfc5c19b2b93a5e73b9'
})
}
</script>
<style>
.scale-105 {
transform: scale(1.05);
transition: transform 0.3s;
}
</style>

427
src/pages/withdraw.vue Normal file
View File

@ -0,0 +1,427 @@
<template>
<view class="min-h-screen bg-blue-50/30">
<view class="p-4">
<!-- 提现卡片 -->
<view class="bg-white rounded-lg p-5 mb-4">
<view class="flex items-center mb-6">
<view class="w-6 h-6 bg-orange-100 rounded-full flex items-center justify-center mr-2">
<text class="text-orange-400 text-sm"></text>
</view>
<text class="text-lg font-bold">支付宝提现</text>
</view>
<wd-form :model="form" :rules="rules" label-position="top" class="withdraw-form">
<!-- 支付宝账号 -->
<view class="mb-4">
<view class="mb-2">
<text class="text-red-500 mr-1">*</text>
<text class="text-base">支付宝账号</text>
</view>
<wd-input v-model="form.alipayAccount" prop="alipayAccount" placeholder="请输入支付宝账号"
custom-class="custom-input" />
<text class="text-gray-400 text-xs mt-1 block">可填写支付宝账户绑定的手机号</text>
</view>
<!-- 支付宝实名姓名 -->
<view class="mb-4">
<view class="mb-2">
<text class="text-red-500 mr-1">*</text>
<text class="text-base">实名姓名</text>
</view>
<wd-input v-model="form.realName" prop="realName" placeholder="请输入支付宝认证姓名" custom-class="custom-input" />
<text class="text-gray-400 text-xs mt-1 block">请填写支付宝账户认证的真实姓名</text>
</view>
<!-- 提现金额 -->
<view class="mb-4">
<view class="mb-2">
<text class="text-red-500 mr-1">*</text>
<text class="text-base">提现金额</text>
</view>
<view class="relative">
<wd-input v-model="form.amount" prop="amount" type="digit" placeholder="请输入提现金额"
custom-class="custom-input" @input="handleAmountInput" />
<view class="absolute right-2 top-1/2 transform -translate-y-1/2">
<view class="bg-blue-100 text-blue-600 rounded-full px-3 py-1 text-sm" @click="fillMaxAmount">
全部提现
</view>
</view>
</view>
</view>
</wd-form>
<!-- 金额提示 -->
<view class="text-sm text-gray-500 my-4">
可提现金额<text class="text-blue-600 font-semibold">¥{{ safeTruncate(availableAmount) }}</text>
</view>
<!-- 提现规则 -->
<view class="bg-gray-50 p-4 rounded-lg">
<view class="flex items-center">
<text class="text-orange-500 mr-1"></text>
<text class="text-blue-600 text-sm">提现须知</text>
</view>
<view class="text-xs text-gray-600 mt-2 space-y-1">
<text class="block">· 每日限提现1次最低50元</text>
<text class="block">· 超过800元需人工审核1-3个工作日</text>
<text class="block">· 到账时间24小时内</text>
</view>
</view>
</view>
<!-- 提交按钮 -->
<wd-button type="primary" block :loading="isSubmitting" @click="handleSubmit" custom-class="submit-button">
立即提现
</wd-button>
</view>
<!-- 状态弹窗 -->
<wd-popup v-model="popupVisible" custom-class="w-[85%] rounded-xl" closable close-on-click-modal>
<view class="p-8 bg-gradient-to-b from-white to-blue-50/30 relative">
<!-- 状态内容 -->
<view class="text-center space-y-5">
<!-- 状态图标 -->
<view class="relative inline-block">
<view class="w-14 h-14 rounded-full flex items-center justify-center" :class="statusIconClass[status]">
<text class="text-4xl">{{ statusIcon[status] }}</text>
</view>
</view>
<!-- 状态文案 -->
<view>
<text class="text-xl font-semibold mb-1 block" :class="statusTextColors[status]">
{{ statusMessages[status] }}
</text>
<template v-if="status === 2">
<text class="text-sm text-gray-500 block">
已向 <text class="text-blue-500">{{ form.alipayAccount }}</text> 转账
</text>
<text class="text-2xl font-bold text-green-600 mt-2 block">¥{{ form.amount }}</text>
</template>
<template v-if="status === 3">
<text class="text-red-500 text-sm px-4 block">{{ failMsg }}</text>
</template>
</view>
<!-- 进度条处理中状态 -->
<view v-if="status === 1" class="my-2">
<wd-progress :percentage="60" hide-text color="#4080ff" />
</view>
<!-- 辅助文案 -->
<view class="text-xs text-gray-400 space-y-1.5">
<template v-if="status === 2">
<text class="block">预计24小时内到账</text>
<text class="block">到账后可在支付宝账单中查看详情</text>
</template>
<template v-if="status === 1">
<text class="block">您的申请已进入处理队列</text>
<text class="block">5分钟后结果在提现记录中查看</text>
</template>
</view>
<!-- 操作按钮 -->
<wd-button type="primary" block class="mt-4" :style="{ backgroundColor: statusButtonColor[status] }"
@click="handlePopupAction">
{{ status === 1 ? '知道了' : status === 2 ? '完成' : '重新提现' }}
</wd-button>
</view>
</view>
</wd-popup>
<wd-toast />
</view>
</template>
<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { useToast } from 'wot-design-uni'
import { getAgentRevenue, agentWithdrawal } from '@/apis/agent'
//
function safeTruncate(num, decimals = 2) {
if (isNaN(num) || !isFinite(num)) return "0.00";
const factor = 10 ** decimals;
const scaled = Math.trunc(num * factor);
const truncated = scaled / factor;
return truncated.toFixed(decimals);
}
//
const form = ref({
alipayAccount: '',
realName: '',
amount: ''
})
const availableAmount = ref(0)
const isSubmitting = ref(false)
// 使wot-design-uitoast
const toast = useToast()
//
const popupVisible = ref(false)
//
const status = ref(null)
const failMsg = ref('')
//
const rules = {
alipayAccount: [
{ required: true, message: '请输入支付宝账号' }
],
realName: [
{ required: true, message: '请输入姓名' },
{
required: true,
pattern: /^[\u4e00-\u9fa5]{2,4}$/,
message: '请输入2-4位中文姓名'
}
],
amount: [
{ required: true, message: '请输入提现金额' },
{
validator: (val) => {
const amountNum = Number(val)
if (isNaN(amountNum)) {
return '请输入有效金额'
}
// if (amountNum < 50) {
// return '50'
// }
if (amountNum > availableAmount.value) {
return '超过可提现金额'
}
return true
}
}
]
}
//
const statusIcon = {
1: '⏳',
2: '✅',
3: '❌'
}
const statusIconClass = {
1: 'bg-blue-100 text-blue-500 border-4 border-blue-200',
2: 'bg-green-100 text-green-500 border-4 border-green-200',
3: 'bg-red-100 text-red-500 border-4 border-red-200'
}
const statusTextColors = {
1: 'text-blue-600',
2: 'text-green-600',
3: 'text-red-600'
}
const statusButtonColor = {
1: '#3b82f6',
2: '#4ade80',
3: '#f87171'
}
const statusMessages = {
1: '提现申请处理中,请稍后再查询结果',
2: '提现成功',
3: '提现失败'
}
//
const handleBack = () => {
uni.navigateBack()
}
//
const getData = async () => {
try {
const res = await getAgentRevenue()
if (res.code === 200) {
availableAmount.value = res.data.balance
} else {
toast.error(res.msg || '获取余额失败')
}
} catch (error) {
toast.error('网络错误')
}
}
//
const fillMaxAmount = () => {
// 使safeTruncate2
form.value.amount = safeTruncate(availableAmount.value)
}
//
const handleAmountInput = (event) => {
let value = event.value
// 便
let numValue = parseFloat(value)
//
if (!isNaN(numValue) && numValue > availableAmount.value) {
value = availableAmount.value
// 使toast
toast.info(`金额已自动调整为最大可提现金额: ¥${value}`)
}
// value2
if (value.toString().includes('.') && value.toString().split('.')[1].length > 2) {
value = safeTruncate(value)
}
form.value.amount = value
console.log(value)
console.log(form.value.amount)
}
//
const handleSubmit = async () => {
try {
//
const amountNum = Number(form.value.amount)
//
if (!form.value.alipayAccount.trim()) {
toast.info('请输入支付宝账号')
return
}
if (!form.value.realName.trim()) {
toast.info('请输入账户实名姓名')
return
}
if (!/^[\u4e00-\u9fa5]{2,4}$/.test(form.value.realName)) {
toast.info('请输入2-4位中文姓名')
return
}
if (!form.value.amount || isNaN(amountNum)) {
toast.info('请输入有效金额')
return
}
// if (amountNum < 50) {
// toast.info('50')
// return
// }
if (amountNum > availableAmount.value) {
toast.info('超过可提现金额')
return
}
isSubmitting.value = true
const res = await agentWithdrawal({
payee_account: form.value.alipayAccount,
amount: amountNum,
payee_name: form.value.realName
})
if (res.code === 200) {
status.value = res.data.status
if (status.value === 3) {
failMsg.value = res.data.fail_msg
}
popupVisible.value = true
} else {
toast.error(res.msg || '提交失败')
}
} catch (error) {
toast.error('网络错误')
} finally {
isSubmitting.value = false
}
}
//
const handlePopupAction = () => {
popupVisible.value = false
if (status.value === 2) {
resetForm()
getData()
}
}
//
const resetForm = () => {
status.value = null
form.value = {
alipayAccount: '',
realName: '',
amount: ''
}
}
//
onMounted(() => {
getData()
})
</script>
<style>
@keyframes progress {
0% {
width: 0;
}
100% {
width: 60%;
}
}
.animate-progress {
animation: progress 1.5s ease-in-out infinite;
animation-direction: alternate;
}
/* 自定义样式 */
.withdraw-form :deep(.wd-form-item) {
margin-bottom: 0;
}
.withdraw-form :deep(.wd-input__label) {
display: none;
}
.withdraw-form :deep(.custom-input .wd-input__inner) {
padding: 10px 15px;
font-size: 14px;
height: 45px;
border: none;
background-color: rgba(64, 128, 255, 0.05);
border-radius: 12px;
transition: all 0.3s ease;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.withdraw-form :deep(.custom-input:focus-within .wd-input__inner) {
border: 2px solid #4080ff;
background-color: rgba(64, 128, 255, 0.08);
box-shadow: 0 0 0 2px rgba(64, 128, 255, 0.1);
}
.withdraw-form :deep(.wd-input__prefix) {
display: none;
}
.submit-button {
height: 45px;
border-radius: 6px;
background-color: #4080ff !important;
font-size: 16px;
}
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "提现",
"auth": true,
"agent": true
}</route>

View File

@ -0,0 +1,181 @@
<template>
<view class="min-h-screen bg-gray-50">
<!-- 提现记录列表 -->
<uni-list :loading="loading" :loadmore="loadMoreStatus" @loadmore="onLoadMore">
<!-- 空状态提示 -->
<view v-if="!loading && list.length === 0" class="flex flex-col items-center justify-center py-16">
<image src="/static/image/empty.svg" mode="aspectFit" class="w-48 h-48 mb-4" />
<text class="text-gray-400 text-base">暂无提现记录</text>
</view>
<view v-for="(item, index) in list" :key="index" class="mx-4 my-2 bg-white rounded-lg p-4 shadow-sm">
<view class="flex justify-between items-center mb-2">
<text class="text-gray-500 text-sm">{{ item.create_time || '-' }}</text>
<text class="font-bold" :class="getAmountColor(item.status)">{{ item.amount.toFixed(2) }}</text>
</view>
<view class="flex items-center mb-2">
<text class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium"
:class="getStatusStyle(item.status)">
<text class="w-2 h-2 rounded-full mr-1 inline-block" :class="getDotColor(item.status)"></text>
{{ statusToChinese(item.status) }}
</text>
</view>
<view class="text-xs text-gray-500">
<text v-if="item.payee_account" class="block">收款账户{{ maskName(item.payee_account) }}</text>
<text v-if="item.remark" class="block">备注{{ item.remark }}</text>
</view>
</view>
<!-- 加载更多/加载完成提示 -->
<uni-load-more :status="loadMoreStatus" />
</uni-list>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { getWithdrawalRecords } from '@/apis/agent'
//
const statusConfig = {
1: {
chinese: '处理中',
color: {
bg: 'bg-yellow-100',
text: 'text-yellow-800',
dot: 'bg-yellow-500',
amount: 'text-yellow-500'
}
},
2: {
chinese: '提现成功',
color: {
bg: 'bg-green-100',
text: 'text-green-800',
dot: 'bg-green-500',
amount: 'text-green-500'
}
},
3: {
chinese: '提现失败',
color: {
bg: 'bg-red-100',
text: 'text-red-800',
dot: 'bg-red-500',
amount: 'text-red-500'
}
}
}
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const list = ref([])
const loading = ref(false)
const loadMoreStatus = ref('more') // 'more'|'loading'|'noMore'
//
const maskName = (name) => {
if (!name || typeof name !== 'string') return ''
if (name.length <= 7) return name
return name.substring(0, 3) + '****' + name.substring(7)
}
//
const statusToChinese = (status) => {
return statusConfig[status]?.chinese || '未知状态'
}
//
const getStatusStyle = (status) => {
const config = statusConfig[status] || {}
return `${config.color?.bg || 'bg-gray-100'} ${config.color?.text || 'text-gray-800'}`
}
//
const getDotColor = (status) => {
return statusConfig[status]?.color.dot || 'bg-gray-500'
}
//
const getAmountColor = (status) => {
return statusConfig[status]?.color.amount || 'text-gray-500'
}
//
const onLoadMore = async () => {
if (loadMoreStatus.value === 'noMore') return
page.value++
await getData()
}
//
const getData = async () => {
try {
loading.value = true
loadMoreStatus.value = 'loading'
const res = await getWithdrawalRecords({
page: page.value,
page_size: pageSize.value
})
if (res.code === 200) {
if (page.value === 1) {
list.value = res.data.list
total.value = res.data.total
} else {
list.value.push(...res.data.list)
}
if (list.value.length >= res.data.total || res.data.list.length < pageSize.value) {
loadMoreStatus.value = 'noMore'
} else {
loadMoreStatus.value = 'more'
}
} else {
uni.showToast({
title: res.msg || '加载失败',
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: '网络错误',
icon: 'none'
})
} finally {
loading.value = false
}
}
//
onMounted(() => {
getData()
})
//
const onPullDownRefresh = () => {
page.value = 1
loadMoreStatus.value = 'more'
getData().then(() => {
uni.stopPullDownRefresh()
})
}
//
defineExpose({
onPullDownRefresh
})
</script>
<style>
/* 自定义样式 */
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "提现记录",
"auth": true,
"agent": true
}</route>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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