Browse Source

Merge branch 'dongqian/feature-20251022181325-deepmate简版' into milestone-20251031-简版功能开发

maziyang/feature-20251025172218-智能客服中台
dongqian 4 weeks ago
parent
commit
f2981e95f1
  1. 3
      .hbuilderx/launch.json
  2. 21
      App.vue
  3. 18
      api/deepExploration/deepExploration.js
  4. 2
      api/tcpConnection.js
  5. 146
      pages/deepExploration/deepExploration.vue
  6. 326
      pages/deepExploration/stockSelectDetail.vue
  7. 3
      utils/http.js

3
.hbuilderx/launch.json

@ -2,7 +2,8 @@
"version" : "1.0",
"configurations" : [
{
"customPlaygroundType" : "local",
"customPlaygroundType" : "device",
"packageName" : "io.dcloud.HBuilder",
"playground" : "custom",
"type" : "uni-app:app-android"
}

21
App.vue

@ -1,8 +1,25 @@
<script>
export default {
import { useDeviceStore } from './stores/modules/deviceInfo'
export default {
onLaunch: function() {
console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
console.log('App Launch')
//
// const deviceStore = useDeviceStore()
// try {
// const sys = uni.getSystemInfoSync()
// let deviceId = ''
// // #ifdef APP-PLUS
// try { deviceId = plus?.device?.uuid || '' } catch(e) {}
// // #endif
// if (!deviceId) deviceId = uni.getStorageSync('device_id')
// if (!deviceId) {
// deviceId = `web_${Date.now()}_${Math.random().toString(36).slice(2,10)}`
// uni.setStorageSync('device_id', deviceId)
// }
// deviceStore.setDeviceInfo({ deviceId, platform: sys.platform, model: sys.model })
// console.log('Device init:', deviceStore.deviceInfo)
// } catch(e) { console.warn('Init device info failed:', e) }
},
onShow: function() {
console.log('App Show')
@ -10,7 +27,7 @@
onHide: function() {
console.log('App Hide')
}
}
}
</script>
<style lang="scss">

18
api/deepExploration/deepExploration.js

@ -101,8 +101,22 @@ export const RecordListApi = (data) => {
data:data
})
}
// 选股策略
export const stocSelectApi = (data) => {
return http({
method: 'POST',
url: '/api/deep/getStrategy',
data:data
})
}
//根据名字选股策略
export const stocSelectByNameApi = (data) => {
return http({
method: 'POST',
url: '/api/deep/getStrategyByName',
data:data
})
}
//历史记录详情

2
api/tcpConnection.js

@ -6,7 +6,7 @@
*/
// 引用TCP插件
const TCPSocket = uni.requireNativePlugin('Aimer-TCPPlugin');
// const TCPSocket = uni.requireNativePlugin('Aimer-TCPPlugin');
// const TCPSocket = uni.requireNativePlugin("Aimer-TCPPlugin");
// TCP连接配置

146
pages/deepExploration/deepExploration.vue

@ -96,9 +96,9 @@
</view>
<view class="contentItem">
<view class="row" v-for="(item, index) in stockData" :key="index">
<view class="nameItem">{{ item.name }}</view>
<view class="nameItem">{{ item.tscode }}</view>
<view class="closeItem">{{ item.close }}</view>
<view class="priceItem">{{ item.select }}</view>
<view class="priceItem">{{ item.preClose }}</view>
</view>
</view>
</view>
@ -113,7 +113,7 @@
src="/static/deepExploration-images/plus.png"
mode="aspectFill"
></image>
<text>抄底卖顶</text>
<text>波段行情</text>
</view>
<view class="right">
<image
@ -130,10 +130,10 @@
<view class="contentTitle_price">选股价格</view>
</view>
<view class="contentItem">
<view class="row" v-for="(item, index) in stockData" :key="index">
<view class="nameItem">{{ item.name }}</view>
<view class="row" v-for="(item, index) in stockDataByName" :key="index">
<view class="nameItem">{{ item.tscode }}</view>
<view class="closeItem">{{ item.close }}</view>
<view class="priceItem">{{ item.select }}</view>
<view class="priceItem">{{ item.preClose }}</view>
</view>
</view>
</view>
@ -145,9 +145,13 @@
</template>
<script setup>
import { ref, onMounted } from "vue";
import footerBar from "@/components/footerBar.vue";
import deepExploration_header from "@/components/deepExploration_header.vue";
import {
ref,
onMounted
} from 'vue'
import footerBar from '@/components/footerBar.vue'
import deepExploration_header from '@/components/deepExploration_header.vue'
import { stocSelectApi, stocSelectByNameApi } from '@/api/deepExploration/deepExploration.js'
const type = ref("deepExploration");
const iSMT = ref(0);
@ -182,43 +186,109 @@ const searchStock = () => {
});
};
//
const viewAll = () => {
//
const viewAll = () => {
uni.navigateTo({
url: "/pages/deepExploration/stockSelectDetail",
});
};
//
const stockData = [
{
name: "(MKTW)MarketWise Inc",
close: "$14.190",
select: "$13.180",
},
{
name: "(MTCH)Match Group Inc",
close: "$32.120",
select: "$28.120",
},
{
name: "(MKTW)MarketWise Inc",
close: "$14.190",
select: "$13.180",
},
];
onMounted(() => {
url: '/pages/deepExploration/stockSelectDetail'
})
}
//
const stockData = ref([]);
const stockDataByName = ref([]); //
//
const loadStockSelection = async () => {
try {
const res = await stocSelectApi({ language: 'cn', size: 3 })
// console.log(':', typeof res === 'object' ? JSON.stringify(res) : res)
const raw = res?.data
const listCandidates = [
raw?.list,
raw?.data?.list,
raw?.data?.rows,
raw?.rows,
Array.isArray(raw) ? raw : null
].filter(Array.isArray)
let list = listCandidates.length ? listCandidates[0] : []
//
if ((!Array.isArray(list) || !list.length) && raw && typeof raw === 'object' && !Array.isArray(raw)) {
const arrays = Object.values(raw).filter(Array.isArray)
if (arrays.length) {
list = arrays.flat()
}
}
if (Array.isArray(list) && list.length) {
const mapped = list.map(item => ({
tscode: item.tsCode ?? item.tscode ?? item.code ?? '',
close: item.close ?? item.lastClose ?? '',
preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
}))
stockData.value = mapped.slice(0, 3)
console.log('选股策略列表长度:', stockData.value.length, '首项:', stockData.value[0])
} else {
console.warn('选股策略接口返回空列表或结构不匹配', raw)
}
} catch (e) {
console.error('选股策略接口调用失败', e)
uni.showToast({ title: '选股策略加载失败', icon: 'none' })
}
}
//
const loadStockSelectionByName = async () => {
try {
const res = await stocSelectByNameApi({ name: '安徽' })
const raw = res?.data
const dataObj = raw?.data || raw
let list = []
if (Array.isArray(dataObj)) {
list = dataObj
} else if (dataObj && typeof dataObj === 'object') {
const target = dataObj['安徽']
if (Array.isArray(target)) {
list = target
} else {
const firstArr = Object.values(dataObj).find(v => Array.isArray(v))
if (Array.isArray(firstArr)) list = firstArr
}
}
if (Array.isArray(list) && list.length) {
const mapped = list.map(item => ({
tscode: item.tsCode ?? item.tscode ?? item.code ?? '',
close: item.close ?? item.lastClose ?? '',
preClose: item.preClose ?? item.preclose ?? item.prevClose ?? ''
}))
stockDataByName.value = mapped.slice(0, 3)
console.log('安徽板块列表长度:', stockDataByName.value.length, '首项:', stockDataByName.value[0])
} else {
console.warn('按名称(安徽)接口返回空列表或结构不匹配', raw)
}
} catch (e) {
console.error('按名称(安徽)接口调用失败', e)
uni.showToast({ title: '安徽板块加载失败', icon: 'none' })
}
}
onMounted(() => {
//
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
});
//
loadStockSelection()
loadStockSelectionByName() //
})
</script>
<style scoped lang="scss">
.main {
width: 100%;
height: 100vh;
min-height: 100vh; //
height: auto; //
overflow-y: auto; //
background-color: #fff;
padding-bottom: 120rpx; //
.search {
position: relative;
@ -451,6 +521,8 @@ onMounted(() => {
.static-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
}

326
pages/deepExploration/stockSelectDetail.vue

@ -3,7 +3,7 @@
<view class="table">
<view class="tableHeader">
<scroll-view class="tabs" scroll-x="true">
<view v-for="(item,index) in tabsData" :key="index" class="tabItem" @click="handleTab(item)">
<view v-for="(item,index) in tabsData" :key="index" :class="['tabItem', { 'tabItem-active': item === activeTab }]" @click="handleTab(item)">
{{item}}
</view>
</scroll-view>
@ -23,7 +23,7 @@
</view>
</view>
<view class="box_content">
<view class="row" v-for="(item,index) in fakeData" :key="index" :class="{ 'increase-positive': item.increase.startsWith('+'),
<view class="row" v-for="(item,index) in strategyData" :key="index" :class="{ 'increase-positive': item.increase.startsWith('+'),
'increase-negative': item.increase.startsWith('-')}">
<view class="name_colum">
<text class="stockName">{{item.name}}</text>
@ -48,153 +48,182 @@
</template>
<script setup>
import {
ref
} from 'vue'
const tabsData = ref(['全部', '抄底卖顶', '波段行情', '价值投资', '资金及仓位管理', '价值投资', '价值投资', '价值投资', ])
const handleTab = (item) => {
uni.showToast({
title: `查看 ${item} 详情`,
icon: 'none',
duration: 2000
})
import { ref, onMounted } from 'vue'
import { stocSelectApi, stocSelectByNameApi } from '@/api/deepExploration/deepExploration.js'
import { useUserStore } from '@/stores/modules/userInfo.js'
import { useDeviceStore } from '@/stores/modules/deviceInfo.js'
import { LoginApi } from '@/api/start/login.js'
const tabsData = ref(['全部', '抄底卖顶', '波段行情', '价值投资', '资金及仓位管理', ])
const activeTab = ref('全部')
//
const handleTab = async (item) => {
activeTab.value = item
const nameMap = {
'抄底卖顶': '北京',
'波段行情': '安徽',
'价值投资': '重庆',
'资金及仓位管理': '黑龙江'
}
if (item === '全部') {
await loadStrategy()
uni.showToast({ title: `查看 ${item} 详情`, icon: 'none', duration: 1500 })
return
}
const apiName = nameMap[item]
if (apiName) {
await loadByName(apiName)
uni.showToast({ title: `${item}数据已更新`, icon: 'none', duration: 1500 })
} else {
uni.showToast({ title: `暂不支持:${item}`, icon: 'none' })
}
}
//
const ifASC = ref(true)
//
const tableContentHeaderData = ref(['最新', '涨幅', '跌幅', '昨收', '成交量', '成交额', '开盘价', '最高价', '最低价'])
const fakeData = [{
name: "TechCore",
stockCode: "600001",
latest: 1315.00,
increase: "+5.2%",
decrease: "+5.2%",
previousClose: 1250.00,
volume: 12000,
turnover: "15780K",
openingPrice: 1237.50,
highestPrice: 1320.00,
lowestPrice: 1230.00
},
{
name: "MediaLink",
stockCode: "600002",
latest: 1138.70,
increase: "-3.5%",
decrease: "-3.5%",
previousClose: 1180.00,
volume: 8500,
turnover: "967.9K",
openingPrice: 1191.80,
highestPrice: 1195.00,
lowestPrice: 1130.00
},
{
name: "FinServ",
stockCode: "600003",
latest: 1413.72,
increase: "+7.1%",
decrease: "+7.1%",
previousClose: 1320.00,
volume: 15000,
turnover: "2120.6K",
openingPrice: 1293.60,
highestPrice: 1420.00,
lowestPrice: 1290.00
},
{
name: "AutoDrive",
stockCode: "600004",
latest: 1080.40,
increase: "+2.8%",
decrease: "+2.8%",
previousClose: 1050.00,
volume: 9000,
turnover: "972.4K",
openingPrice: 1055.25,
highestPrice: 1085.00,
lowestPrice: 1050.00
},
{
name: "EduSmart",
stockCode: "600005",
latest: 968.24,
increase: "-1.2%",
decrease: "-1.2%",
previousClose: 980.00,
volume: 7000,
turnover: "677.8K",
openingPrice: 975.10,
highestPrice: 978.00,
lowestPrice: 965.00
},
{
name: "HealthPlusqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
stockCode: "600006",
latest: 1463.00,
increase: "+4.5%",
decrease: "+4.5%",
previousClose: 1400.00,
volume: 13000,
turnover: "1901.9K",
openingPrice: 1393.00,
highestPrice: 1470.00,
lowestPrice: 1385.00
},
{
name: "AgriTech",
stockCode: "600007",
latest: 1038.36,
increase: "+1.8%",
decrease: "+1.8%",
previousClose: 1020.00,
volume: 6500,
turnover: "674.9K",
openingPrice: 1028.16,
highestPrice: 1040.00,
lowestPrice: 1025.00
},
{
name: "LogiFlow",
stockCode: "600008",
latest: 1094.24,
increase: "-2.3%",
decrease: "-2.3%",
previousClose: 1120.00,
volume: 8000,
turnover: "875.4K",
openingPrice: 1122.24,
highestPrice: 1125.00,
lowestPrice: 1090.00
},
{
name: "EnergySol",
stockCode: "600009",
latest: 1435.05,
increase: "+6.3%",
decrease: "+6.3%",
previousClose: 1350.00,
volume: 14000,
turnover: "2009.1K",
openingPrice: 1339.75,
highestPrice: 1440.00,
lowestPrice: 1335.00
},
{
name: "RealEstate",
stockCode: "600010",
latest: 995.00,
increase: "-0.5%",
decrease: "-0.5%",
previousClose: 1000.00,
volume: 7500,
turnover: "746.3K",
openingPrice: 1003.00,
highestPrice: 1005.00,
lowestPrice: 990.00
}
];
const tableContentHeaderData = ref(['最新', '涨幅', '涨跌', '昨收', '成交量', '成交额', '开盘价', '最高价', '最低价'])
//
const strategyData = ref([])
// token
const ensureAuth = async () => {
const userStore = useUserStore()
if (userStore.userInfo?.token) return
try {
const deviceStore = useDeviceStore()
let deviceId = deviceStore.deviceInfo?.deviceId
if (!deviceId) {
const cached = uni.getStorageSync('deviceId')
deviceId = cached || `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`
uni.setStorageSync('deviceId', deviceId)
deviceStore.setDeviceInfo({ ...(deviceStore.deviceInfo || {}), deviceId })
}
const res = await LoginApi({
loginType: 'VISITOR',
account: deviceId,
useCode: false
})
if (res?.code === 200 && res?.data?.token) {
userStore.setUserInfo(res.data)
console.log('游客登录成功,token=', res.data.token)
} else {
console.warn('游客登录失败', res)
}
} catch (err) {
console.warn('游客登录异常', err)
}
}
const formatPctChg = (val) => {
if (val === null || val === undefined || val === '') return ''
const num = Number(val)
if (!isFinite(num)) return String(val)
const sign = num > 0 ? '+' : ''
return `${sign}${num.toFixed(2)}%`
}
// ( pctChg )
const sortByPctDesc = (arr) => arr.sort((a, b) => (Number(b.pctChg) || -Infinity) - (Number(a.pctChg) || -Infinity))
// ///
const loadByName = async (apiName) => {
try {
const userStore = useUserStore()
if (!userStore.userInfo?.token) {
await ensureAuth()
}
const token = useUserStore().userInfo?.token
const res = await stocSelectByNameApi({ name: apiName, token })
const raw = res?.data
const dataObj = raw?.data || raw
let list = []
if (dataObj && typeof dataObj === 'object' && !Array.isArray(dataObj)) {
const target = dataObj[apiName]
if (Array.isArray(target)) list = target
else {
const firstArr = Object.values(dataObj).find(v => Array.isArray(v))
if (Array.isArray(firstArr)) list = firstArr
}
}
if ((!Array.isArray(list) || !list.length) && Array.isArray(raw)) {
list = raw
}
//
if (Array.isArray(list)) list = sortByPctDesc(list)
if (Array.isArray(list) && list.length) {
strategyData.value = list.map(item => ({
name: item.tsCode ?? item.tscode ?? '',
stockCode: item.tsCode ?? item.tscode ?? '',
latest: item.close ?? '',
increase: formatPctChg(item.pctChg),
decrease: item.change ?? '',
previousClose: item.preClose ?? item.preclose ?? '',
volume: item.vol ?? '',
turnover: item.amount ?? '',
openingPrice: item.open ?? '',
highestPrice: item.high ?? '',
lowestPrice: item.low ?? ''
}))
console.log(`按名称(${apiName})加载成功,条数:`, strategyData.value.length, '首项:', strategyData.value[0])
} else {
console.warn('getStrategyByName 返回空列表或结构不匹配', raw)
}
} catch (e) {
console.error('getStrategyByName 接口调用失败', e)
uni.showToast({ title: '按名称加载失败', icon: 'none' })
}
}
const loadStrategy = async () => {
try {
const userStore = useUserStore()
if (!userStore.userInfo?.token) {
await ensureAuth()
}
const token = useUserStore().userInfo?.token
const res = await stocSelectApi({ language: 'cn', token })
const raw = res?.data
const listCandidates = [
raw?.list,
raw?.data?.list,
raw?.data?.rows,
raw?.rows,
Array.isArray(raw) ? raw : null
].filter(Array.isArray)
let list = listCandidates.length ? listCandidates[0] : []
if ((!Array.isArray(list) || !list.length) && raw && typeof raw === 'object' && !Array.isArray(raw)) {
const arrays = Object.values(raw).filter(Array.isArray)
if (arrays.length) list = arrays.flat()
}
//
if (Array.isArray(list)) list = sortByPctDesc(list)
if (Array.isArray(list) && list.length) {
strategyData.value = list.map(item => ({
name: item.tsCode ?? item.tscode ?? '',
stockCode: item.tsCode ?? item.tscode ?? '',
latest: item.close ?? '',
increase: formatPctChg(item.pctChg),
decrease: item.change ?? '',
previousClose: item.preClose ?? item.preclose ?? '',
volume: item.vol ?? '',
turnover: item.amount ?? '',
openingPrice: item.open ?? '',
highestPrice: item.high ?? '',
lowestPrice: item.low ?? ''
}))
console.log('stockSelectDetail 加载成功(已按涨幅降序),条数:', strategyData.value.length, '首项:', strategyData.value[0])
} else {
console.warn('stockSelectDetail 接口返回空列表或结构不匹配', raw)
}
} catch (e) {
console.error('stockSelectDetail 接口调用失败', e)
uni.showToast({ title: '选股策略详情加载失败', icon: 'none' })
}
}
onMounted(() => {
loadStrategy()
})
</script>
<style scoped lang="scss">
@ -229,12 +258,17 @@
background-color: rgb(243, 243, 243);
}
.tabItem-active {
background-color: #DB1F1D; //
color: #fff;
}
}
}
.tableContent {
width: 100%;
background-color: #fff;
position: relative;
.showAll {

3
utils/http.js

@ -44,8 +44,7 @@ const httpInterceptor = {
//4 添加token,优先用store,没有则回退到body中的token,保持与Apifox一致
const memberStore = useUserStore()
const token = memberStore.userInfo?.token || options.data?.token
// const token = '2d0b5654409646713cdd40ec0d0bb56c'
// const token = '1b3a58424c5324e40d4bf4d085e18047'
// const token = 'a72cf584af42525f214670cb47443820'
if (token) {
options.header.token = token
}

Loading…
Cancel
Save