Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
W
WSCF
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
潘栩锋
WSCF
Commits
1e226390
Commit
1e226390
authored
Oct 20, 2024
by
潘栩锋
🚴
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加 vue版WSCF客户端
parent
963cb741
Show whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
5530 additions
and
83 deletions
+5530
-83
MainWindow.xaml.cs
WSCF.Test.Server/MainWindow.xaml.cs
+2
-0
Foo.cs
WSCF.Test/Server/Foo.cs
+5
-1
WSCF.csproj
WSCF/WSCF.csproj
+0
-1
WebSocketClient.cs
WSCF/WebSocketClient.cs
+1
-1
WsServiceClient.cs
WSCF/WsServiceClient.cs
+0
-80
.gitignore
wscf-test-client-vue/.gitignore
+30
-0
extensions.json
wscf-test-client-vue/.vscode/extensions.json
+3
-0
README.md
wscf-test-client-vue/README.md
+29
-0
index.html
wscf-test-client-vue/index.html
+13
-0
jsconfig.json
wscf-test-client-vue/jsconfig.json
+8
-0
package-lock.json
wscf-test-client-vue/package-lock.json
+3945
-0
package.json
wscf-test-client-vue/package.json
+20
-0
favicon.ico
wscf-test-client-vue/public/favicon.ico
+0
-0
App.vue
wscf-test-client-vue/src/App.vue
+24
-0
base.css
wscf-test-client-vue/src/assets/base.css
+86
-0
logo.svg
wscf-test-client-vue/src/assets/logo.svg
+1
-0
main.css
wscf-test-client-vue/src/assets/main.css
+35
-0
HelloWorld.vue
wscf-test-client-vue/src/components/HelloWorld.vue
+148
-0
TestFoo.vue
wscf-test-client-vue/src/components/TestFoo.vue
+67
-0
TestTiger.vue
wscf-test-client-vue/src/components/TestTiger.vue
+25
-0
TheWelcome.vue
wscf-test-client-vue/src/components/TheWelcome.vue
+88
-0
WelcomeItem.vue
wscf-test-client-vue/src/components/WelcomeItem.vue
+87
-0
IconCommunity.vue
wscf-test-client-vue/src/components/icons/IconCommunity.vue
+7
-0
IconDocumentation.vue
...est-client-vue/src/components/icons/IconDocumentation.vue
+7
-0
IconEcosystem.vue
wscf-test-client-vue/src/components/icons/IconEcosystem.vue
+7
-0
IconSupport.vue
wscf-test-client-vue/src/components/icons/IconSupport.vue
+7
-0
IconTooling.vue
wscf-test-client-vue/src/components/icons/IconTooling.vue
+19
-0
main.js
wscf-test-client-vue/src/main.js
+6
-0
Foo2ServiceClient.js
wscf-test-client-vue/src/serviceClients/Foo2ServiceClient.js
+50
-0
FooServiceClient.js
wscf-test-client-vue/src/serviceClients/FooServiceClient.js
+53
-0
TigerServiceClient.js
...-test-client-vue/src/serviceClients/TigerServiceClient.js
+19
-0
COMMON.js
wscf-test-client-vue/src/wscf-client/COMMON.js
+24
-0
ReflectSeviceClientAssistant.js
...lient-vue/src/wscf-client/ReflectSeviceClientAssistant.js
+254
-0
Reflect_SeviceClient.js
wscf-test-client-vue/src/wscf-client/Reflect_SeviceClient.js
+134
-0
SubPropertyNode.js
wscf-test-client-vue/src/wscf-client/SubPropertyNode.js
+71
-0
WebSocketClient.js
wscf-test-client-vue/src/wscf-client/WebSocketClient.js
+239
-0
vite.config.js
wscf-test-client-vue/vite.config.js
+16
-0
No files found.
WSCF.Test.Server/MainWindow.xaml.cs
View file @
1e226390
...
...
@@ -72,11 +72,13 @@ namespace WSCF.Test.Server
private
void
btnStartClick
(
object
sender
,
RoutedEventArgs
e
)
{
tiger
.
Start
();
foo
.
Start
();
}
private
void
btnStopClick
(
object
sender
,
RoutedEventArgs
e
)
{
tiger
.
Stop
();
foo
.
Stop
();
}
}
}
WSCF.Test/Server/Foo.cs
View file @
1e226390
...
...
@@ -33,7 +33,8 @@ namespace WSCF.Test.Server
timer
=
new
DispatcherTimer
();
timer
.
Interval
=
TimeSpan
.
FromSeconds
(
1
);
timer
.
Tick
+=
Timer_Tick
;
timer
.
Start
();
Start
();
}
int
timecnt
=
0
;
...
...
@@ -73,5 +74,8 @@ namespace WSCF.Test.Server
Param
.
PName
=
param
.
PName
;
Param
.
Target
=
param
.
Target
;
}
public
void
Start
()
{
timer
.
Start
();}
public
void
Stop
()
{
timer
.
Stop
();
}
}
}
WSCF/WSCF.csproj
View file @
1e226390
...
...
@@ -46,7 +46,6 @@
<ItemGroup>
<Compile
Include=
"AsyncCBHandler.cs"
/>
<Compile
Include=
"ReflectSeviceClientAssistant.cs"
/>
<Compile
Include=
"WsServiceClient.cs"
/>
<Compile
Include=
"WsServiceProxy.cs"
/>
<Compile
Include=
"CallAttribute.cs"
/>
<Compile
Include=
"COMMON.cs"
/>
...
...
WSCF/WebSocketClient.cs
View file @
1e226390
...
...
@@ -40,7 +40,7 @@ namespace WSCF
//长时间没有通讯 测试连接状态 定时器
ping_timer
=
new
System
.
Timers
.
Timer
();
retry
_timer
.
AutoReset
=
true
;
ping
_timer
.
AutoReset
=
true
;
ping_timer
.
Interval
=
10000
;
ping_timer
.
Elapsed
+=
Ping_timer_Elapsed
;
...
...
WSCF/WsServiceClient.cs
deleted
100644 → 0
View file @
963cb741
using
Newtonsoft.Json
;
using
Newtonsoft.Json.Linq
;
using
System
;
using
System.Collections.Generic
;
using
System.ComponentModel
;
using
System.Linq
;
using
System.Net
;
using
System.Reflection
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
WSCF.RevCtrl
{
public
abstract
class
WsServiceClient
:
IReflectSeviceClientCore
{
public
event
PropertyChangedEventHandler
PropertyChanged
;
/// <summary>
/// 连接成功
/// </summary>
public
bool
IsConnected
{
get
;
set
;
}
/// <summary>
/// 代理对象 接口类型
/// </summary>
protected
virtual
Type
InterfaceType
{
get
;
}
/// <summary>
/// 已经同步完成;
/// 已经收到了 CALL_GetAllProperties, 全部属性都与服务器一致
/// </summary>
public
bool
IsSynced
{
get
;
set
;
}
/// <summary>
/// 当前 INotifyPropertyChanged 对象 引发了 PropertyChanged, 是由于 接收到数据导致的
/// </summary>
public
bool
IsInPushValue
{
get
;
set
;
}
ReflectSeviceClientAssistant
assistant
;
public
WsServiceClient
()
{
assistant
=
new
ReflectSeviceClientAssistant
();
assistant
.
Init
(
InterfaceType
,
this
);
}
public
void
SetSendEx
(
Action
<
string
>
sendEx
)
{
assistant
.
SetSendEx
(
sendEx
);
}
public
void
OnOpen
()
{
assistant
.
OnOpen
();
}
public
void
OnMessage
(
Reflect_OBJ_INTERFACE
.
PkgData
pkgData
)
{
assistant
.
OnMessage
(
pkgData
);
}
public
void
OnClose
()
{
assistant
.
OnClose
();
}
protected
void
Call
(
string
methodName
,
object
parameters
,
AsyncCBHandler
asyncDelegate
,
object
asyncContext
)
{
assistant
.
Call
(
methodName
,
parameters
,
asyncDelegate
,
asyncContext
);
}
protected
void
Call
(
string
methodName
,
object
parameters
)
{
Call
(
methodName
,
parameters
,
null
,
null
);
}
protected
void
Call
(
string
methodName
)
{
Call
(
methodName
,
null
,
null
,
null
);
}
}
}
wscf-test-client-vue/.gitignore
0 → 100644
View file @
1e226390
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
wscf-test-client-vue/.vscode/extensions.json
0 → 100644
View file @
1e226390
{
"recommendations"
:
[
"Vue.volar"
]
}
wscf-test-client-vue/README.md
0 → 100644
View file @
1e226390
# wscf-test-client-vue
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[
VSCode
](
https://code.visualstudio.com/
)
+
[
Volar
](
https://marketplace.visualstudio.com/items?itemName=Vue.volar
)
(
and
disable Vetur).
## Customize configuration
See
[
Vite Configuration Reference
](
https://vite.dev/config/
)
.
## Project Setup
```
sh
npm
install
```
### Compile and Hot-Reload for Development
```
sh
npm run dev
```
### Compile and Minify for Production
```
sh
npm run build
```
wscf-test-client-vue/index.html
0 → 100644
View file @
1e226390
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<link
rel=
"icon"
href=
"/favicon.ico"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<title>
Vite App
</title>
</head>
<body>
<div
id=
"app"
></div>
<script
type=
"module"
src=
"/src/main.js"
></script>
</body>
</html>
wscf-test-client-vue/jsconfig.json
0 → 100644
View file @
1e226390
{
"compilerOptions"
:
{
"paths"
:
{
"@/*"
:
[
"./src/*"
]
}
},
"exclude"
:
[
"node_modules"
,
"dist"
]
}
wscf-test-client-vue/package-lock.json
0 → 100644
View file @
1e226390
This source diff could not be displayed because it is too large. You can
view the blob
instead.
wscf-test-client-vue/package.json
0 → 100644
View file @
1e226390
{
"name"
:
"wscf-test-client-vue"
,
"version"
:
"0.0.0"
,
"private"
:
true
,
"type"
:
"module"
,
"scripts"
:
{
"dev"
:
"vite"
,
"build"
:
"vite build"
,
"preview"
:
"vite preview"
},
"dependencies"
:
{
"EventEmitter"
:
"^1.0.0"
,
"uuid"
:
"^10.0.0"
,
"vue"
:
"^3.5.12"
},
"devDependencies"
:
{
"@vitejs/plugin-vue"
:
"^5.1.4"
,
"vite"
:
"^5.4.8"
}
}
wscf-test-client-vue/public/favicon.ico
0 → 100644
View file @
1e226390
4.19 KB
wscf-test-client-vue/src/App.vue
0 → 100644
View file @
1e226390
<
script
setup
>
import
HelloWorld
from
'./components/HelloWorld.vue'
import
TestTiger
from
'./components/TestTiger.vue'
;
import
TestFoo
from
'./components/TestFoo.vue'
;
</
script
>
<
template
>
<header>
<img
alt=
"Vue logo"
class=
"logo"
src=
"./assets/logo.svg"
width=
"125"
height=
"125"
/>
<TestFoo
/>
<!--
<TestTiger
/>
-->
<!--
<HelloWorld
/>
-->
</header>
</
template
>
<
style
scoped
>
.logo
{
display
:
block
;
margin
:
0
auto
2rem
;
}
</
style
>
wscf-test-client-vue/src/assets/base.css
0 → 100644
View file @
1e226390
/* color palette from <https://github.com/vuejs/theme> */
:root
{
--vt-c-white
:
#ffffff
;
--vt-c-white-soft
:
#f8f8f8
;
--vt-c-white-mute
:
#f2f2f2
;
--vt-c-black
:
#181818
;
--vt-c-black-soft
:
#222222
;
--vt-c-black-mute
:
#282828
;
--vt-c-indigo
:
#2c3e50
;
--vt-c-divider-light-1
:
rgba
(
60
,
60
,
60
,
0.29
);
--vt-c-divider-light-2
:
rgba
(
60
,
60
,
60
,
0.12
);
--vt-c-divider-dark-1
:
rgba
(
84
,
84
,
84
,
0.65
);
--vt-c-divider-dark-2
:
rgba
(
84
,
84
,
84
,
0.48
);
--vt-c-text-light-1
:
var
(
--vt-c-indigo
);
--vt-c-text-light-2
:
rgba
(
60
,
60
,
60
,
0.66
);
--vt-c-text-dark-1
:
var
(
--vt-c-white
);
--vt-c-text-dark-2
:
rgba
(
235
,
235
,
235
,
0.64
);
}
/* semantic color variables for this project */
:root
{
--color-background
:
var
(
--vt-c-white
);
--color-background-soft
:
var
(
--vt-c-white-soft
);
--color-background-mute
:
var
(
--vt-c-white-mute
);
--color-border
:
var
(
--vt-c-divider-light-2
);
--color-border-hover
:
var
(
--vt-c-divider-light-1
);
--color-heading
:
var
(
--vt-c-text-light-1
);
--color-text
:
var
(
--vt-c-text-light-1
);
--section-gap
:
160px
;
}
@media
(
prefers-color-scheme
:
dark
)
{
:root
{
--color-background
:
var
(
--vt-c-black
);
--color-background-soft
:
var
(
--vt-c-black-soft
);
--color-background-mute
:
var
(
--vt-c-black-mute
);
--color-border
:
var
(
--vt-c-divider-dark-2
);
--color-border-hover
:
var
(
--vt-c-divider-dark-1
);
--color-heading
:
var
(
--vt-c-text-dark-1
);
--color-text
:
var
(
--vt-c-text-dark-2
);
}
}
*,
*
::before
,
*
::after
{
box-sizing
:
border-box
;
margin
:
0
;
font-weight
:
normal
;
}
body
{
min-height
:
100vh
;
color
:
var
(
--color-text
);
background
:
var
(
--color-background
);
transition
:
color
0.5s
,
background-color
0.5s
;
line-height
:
1.6
;
font-family
:
Inter
,
-apple-system
,
BlinkMacSystemFont
,
'Segoe UI'
,
Roboto
,
Oxygen
,
Ubuntu
,
Cantarell
,
'Fira Sans'
,
'Droid Sans'
,
'Helvetica Neue'
,
sans-serif
;
font-size
:
15px
;
text-rendering
:
optimizeLegibility
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
}
wscf-test-client-vue/src/assets/logo.svg
0 → 100644
View file @
1e226390
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 261.76 226.69"
><path
d=
"M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z"
fill=
"#41b883"
/><path
d=
"M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z"
fill=
"#34495e"
/></svg>
wscf-test-client-vue/src/assets/main.css
0 → 100644
View file @
1e226390
@import
'./base.css'
;
#app
{
max-width
:
1280px
;
margin
:
0
auto
;
padding
:
2rem
;
font-weight
:
normal
;
}
a
,
.green
{
text-decoration
:
none
;
color
:
hsla
(
160
,
100%
,
37%
,
1
);
transition
:
0.4s
;
padding
:
3px
;
}
@media
(
hover
:
hover
)
{
a
:
hover
{
background-color
:
hsla
(
160
,
100%
,
37%
,
0.2
);
}
}
@media
(
min-width
:
1024px
)
{
body
{
display
:
flex
;
place-items
:
center
;
}
#app
{
display
:
grid
;
grid-template-columns
:
1
fr
1
fr
;
padding
:
0
2rem
;
}
}
wscf-test-client-vue/src/components/HelloWorld.vue
0 → 100644
View file @
1e226390
<
script
setup
>
import
{
ref
}
from
"vue"
;
import
WebSocketClient
from
"@/wscf-client/WebSocketClient"
;
import
FooServiceClient
from
"@/serviceClients/FooServiceClient"
;
defineProps
({
msg
:
{
type
:
String
,
required
:
true
}
})
const
elapseSec
=
ref
(
0
);
const
timer
=
ref
(
0
);
const
a
=
ref
(
0
);
const
b
=
ref
(
0
);
const
ret
=
ref
(
0
);
const
ws
=
new
WebSocketClient
();
const
foo
=
new
FooServiceClient
.
FooServiceClient
();
foo
.
eventEmitter
.
on
(
FooServiceClient
.
EVENT_MsgChanged
,
(
eventArgs
)
=>
{
console
.
log
(
`foo.eventEmitter.on(FooServiceClient.EVENT_MsgChanged,
${
eventArgs
}
)`
);
});
function
WebSocketTest
(){
if
(
"WebSocket"
in
window
)
{
console
.
log
(
"您的浏览器支持 WebSocket!"
);
// 打开一个 web socket
var
ws
=
new
WebSocket
(
"ws://localhost:5540/Tiger"
);
console
.
log
(
"01"
);
ws
.
onopen
=
function
()
{
// Web Socket 已连接上,使用 send() 方法发送数据
//ws.send("发送数据");
//alert("数据发送中...");
console
.
log
(
"onopen"
);
};
ws
.
onmessage
=
function
(
evt
)
{
var
received_msg
=
evt
.
data
;
console
.
log
(
`onmessage
${
received_msg
}
`
);
};
ws
.
onclose
=
function
()
{
ws
.
readyState
// 关闭 websocket
console
.
log
(
"onclose"
);
};
console
.
log
(
"02"
);
}
else
{
// 浏览器不支持 WebSocket
console
.
log
(
"您的浏览器不支持 WebSocket!"
);
}
}
function
startTimer
(){
timer
.
value
=
setInterval
(
_timer_Elapsed
,
1000
);
}
function
stopTimer
(){
clearInterval
(
timer
.
value
);
elapseSec
.
value
=
0
;
}
const
_timer_Elapsed
=
()
=>
{
elapseSec
.
value
++
;
}
function
testWebSocketClient
(){
ws
.
Init
(
"Tiger"
,
"localhost:5540"
);
}
async
function
add
(){
ret
.
value
=
await
foo
.
Add
(
a
.
value
,
b
.
value
);
}
</
script
>
<
template
>
<div
class=
"greetings"
>
<h1
class=
"green"
>
{{
msg
}}
</h1>
<h3>
You’ve successfully created a project with
<a
href=
"https://vite.dev/"
target=
"_blank"
rel=
"noopener"
>
Vite
</a>
+
<a
href=
"https://vuejs.org/"
target=
"_blank"
rel=
"noopener"
>
Vue 3
</a>
.
</h3>
<div
style=
"display: flex; flex-direction: row;"
>
<button
@
click=
"testWebSocketClient"
style=
"padding: 5px 20px; margin: 5px;"
>
Test WebSocketClient
</button>
<div
style=
"display: flex; flex-direction: column;"
>
<p
style=
"margin: 3px;"
>
IsConnected =
{{
ws
.
IsConnected
}}
</p>
<p
style=
"margin: 3px;"
>
RetrySurplusSec =
{{
ws
.
RetrySurplusSec
}}
</p>
</div>
</div>
<div
style=
"display: flex; flex-direction: row;"
>
<button
@
click=
"startTimer"
style=
"padding: 5px 20px; margin: 5px;"
>
Start Timer
</button>
<button
@
click=
"stopTimer"
style=
"padding: 5px 20px; margin: 5px;"
>
Stop Timer
</button>
<div
style=
"display: flex; flex-direction: column;"
>
<p
style=
"margin: 3px;"
>
timer =
{{
timer
}}
</p>
<p
style=
"margin: 3px;"
>
elapseSec =
{{
elapseSec
}}
</p>
</div>
</div>
<h3>
---Foo----
</h3>
<div
style=
"display: flex; flex-direction: row;"
>
<button
@
click=
"foo.start()"
style=
"padding: 5px 20px; margin: 5px;"
>
Foo.Start
</button>
<button
@
click=
"foo.stop()"
style=
"padding: 5px 20px; margin: 5px;"
>
Foo.Stop
</button>
<div
style=
"display: flex; flex-direction: column;"
>
<p
style=
"margin: 3px;"
>
Foo.Number =
{{
foo
.
Number
}}
</p>
<p
style=
"margin: 3px;"
>
Foo.Msg =
{{
foo
.
Msg
}}
</p>
</div>
</div>
<div
style=
"display: flex; flex-direction: row;"
>
<input
style=
"width:min-content;"
type=
"text"
v-model=
"a"
>
<span>
+
</span>
<input
style=
"width: 100px;"
type=
"text"
v-model=
"b"
>
<button
@
click=
"add"
>
=
</button>
<span>
{{
ret
}}
</span>
</div>
</div>
</
template
>
<
style
scoped
>
h1
{
font-weight
:
500
;
font-size
:
2.6rem
;
position
:
relative
;
top
:
-10px
;
}
h3
{
font-size
:
1.2rem
;
}
.greetings
h1
,
.greetings
h3
{
text-align
:
center
;
}
@media
(
min-width
:
1024px
)
{
.greetings
h1
,
.greetings
h3
{
text-align
:
left
;
}
}
</
style
>
wscf-test-client-vue/src/components/TestFoo.vue
0 → 100644
View file @
1e226390
<
script
setup
>
import
{
ref
,
watch
}
from
"vue"
;
import
FooServiceClient
from
"@/serviceClients/Foo2ServiceClient"
;
const
a
=
ref
(
0
);
const
b
=
ref
(
0
);
const
ret
=
ref
(
0
);
const
dataChanged_time
=
ref
(
''
);
const
dataChanged_msg
=
ref
(
''
);
const
PName
=
ref
(
''
);
const
foo
=
new
FooServiceClient
();
foo
.
Init
(
"Foo"
,
"localhost:5540"
);
foo
.
EventEmitter
.
on
(
"DataChanged"
,(
eventArgs
)
=>
{
dataChanged_time
.
value
=
eventArgs
.
Time
;
dataChanged_msg
.
value
=
eventArgs
.
Msg
;
});
watch
(
()
=>
foo
.
Data
.
value
.
Param
.
PName
,
(
newValue
)
=>
{
PName
.
value
=
newValue
;
},
{
immediate
:
true
});
async
function
add
(){
var
{
result
}
=
await
foo
.
Add
(
a
.
value
,
b
.
value
);
ret
.
value
=
result
;
}
async
function
apply
()
{
await
foo
.
SyncSetValue
({
PName
:
PName
.
value
},
"Param"
);
}
</
script
>
<
template
>
<div
>
<h1>
Test FooServiceClient
</h1>
<p
style=
"margin: 3px;"
>
FooServiceClient.Data =
{{
foo
.
Data
}}
</p>
<div
style=
"display: flex; flex-direction: row;"
>
<input
style=
"width:min-content;"
type=
"text"
v-model=
"a"
>
<span>
+
</span>
<input
style=
"width: 100px;"
type=
"text"
v-model=
"b"
>
<button
@
click=
"add"
>
=
</button>
<span>
{{
ret
}}
</span>
</div>
<div
style=
"display: flex; flex-direction: row;"
>
<button
style=
"padding: 5px 20px; margin: 5px;"
@
click=
"foo.start()"
>
Foo.Start
</button>
<button
style=
"padding: 5px 20px; margin: 5px;"
@
click=
"foo.stop()"
>
Foo.Stop
</button>
</div>
<p
style=
"margin: 3px;"
>
DataChanged Time=
{{
dataChanged_time
}}
Msg=
{{
dataChanged_msg
}}
</p>
<p
style=
"margin: 3px;"
>
foo.Number =
{{
foo
.
Data
.
value
.
Number
}}
</p>
<div
style=
"display: flex; flex-direction: row;"
>
<label>
PName:
</label>
<input
type=
"text"
v-model=
"PName"
>
<button
style=
"padding: 5px 20px; margin: 5px;"
@
click=
"apply"
>
submit
</button>
</div>
</div>
</
template
>
<
style
scoped
>
</
style
>
wscf-test-client-vue/src/components/TestTiger.vue
0 → 100644
View file @
1e226390
<
script
setup
>
import
{
ref
}
from
"vue"
;
import
TigeServiceClient
from
"@/serviceClients/TigerServiceClient"
;
const
tiger
=
new
TigeServiceClient
();
tiger
.
Init
(
"Tiger"
,
"localhost:5540"
);
</
script
>
<
template
>
<div
>
<h1>
Test TigerServiceClient
</h1>
<div
style=
"display: flex; flex-direction: row;"
>
<button
@
click=
"foo.start()"
style=
"padding: 5px 20px; margin: 5px;"
>
Foo.Start
</button>
<button
@
click=
"foo.stop()"
style=
"padding: 5px 20px; margin: 5px;"
>
Foo.Stop
</button>
<div
style=
"display: flex; flex-direction: column;"
>
<p
style=
"margin: 3px;"
>
Tiger.Data =
{{
tiger
.
Data
}}
</p>
</div>
</div>
</div>
</
template
>
<
style
scoped
>
</
style
>
wscf-test-client-vue/src/components/TheWelcome.vue
0 → 100644
View file @
1e226390
<
script
setup
>
import
WelcomeItem
from
'./WelcomeItem.vue'
import
DocumentationIcon
from
'./icons/IconDocumentation.vue'
import
ToolingIcon
from
'./icons/IconTooling.vue'
import
EcosystemIcon
from
'./icons/IconEcosystem.vue'
import
CommunityIcon
from
'./icons/IconCommunity.vue'
import
SupportIcon
from
'./icons/IconSupport.vue'
</
script
>
<
template
>
<WelcomeItem>
<template
#
icon
>
<DocumentationIcon
/>
</
template
>
<
template
#
heading
>
Documentation
</
template
>
Vue’s
<a
href=
"https://vuejs.org/"
target=
"_blank"
rel=
"noopener"
>
official documentation
</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<
template
#
icon
>
<ToolingIcon
/>
</
template
>
<
template
#
heading
>
Tooling
</
template
>
This project is served and bundled with
<a
href=
"https://vite.dev/guide/features.html"
target=
"_blank"
rel=
"noopener"
>
Vite
</a>
. The
recommended IDE setup is
<a
href=
"https://code.visualstudio.com/"
target=
"_blank"
rel=
"noopener"
>
VSCode
</a>
+
<a
href=
"https://github.com/johnsoncodehk/volar"
target=
"_blank"
rel=
"noopener"
>
Volar
</a>
. If
you need to test your components and web pages, check out
<a
href=
"https://www.cypress.io/"
target=
"_blank"
rel=
"noopener"
>
Cypress
</a>
and
<a
href=
"https://on.cypress.io/component"
target=
"_blank"
rel=
"noopener"
>
Cypress Component Testing
</a
>
.
<br
/>
More instructions are available in
<code>
README.md
</code>
.
</WelcomeItem>
<WelcomeItem>
<
template
#
icon
>
<EcosystemIcon
/>
</
template
>
<
template
#
heading
>
Ecosystem
</
template
>
Get official tools and libraries for your project:
<a
href=
"https://pinia.vuejs.org/"
target=
"_blank"
rel=
"noopener"
>
Pinia
</a>
,
<a
href=
"https://router.vuejs.org/"
target=
"_blank"
rel=
"noopener"
>
Vue Router
</a>
,
<a
href=
"https://test-utils.vuejs.org/"
target=
"_blank"
rel=
"noopener"
>
Vue Test Utils
</a>
, and
<a
href=
"https://github.com/vuejs/devtools"
target=
"_blank"
rel=
"noopener"
>
Vue Dev Tools
</a>
. If
you need more resources, we suggest paying
<a
href=
"https://github.com/vuejs/awesome-vue"
target=
"_blank"
rel=
"noopener"
>
Awesome Vue
</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<
template
#
icon
>
<CommunityIcon
/>
</
template
>
<
template
#
heading
>
Community
</
template
>
Got stuck? Ask your question on
<a
href=
"https://chat.vuejs.org"
target=
"_blank"
rel=
"noopener"
>
Vue Land
</a>
, our official
Discord server, or
<a
href=
"https://stackoverflow.com/questions/tagged/vue.js"
target=
"_blank"
rel=
"noopener"
>
StackOverflow
</a
>
. You should also subscribe to
<a
href=
"https://news.vuejs.org"
target=
"_blank"
rel=
"noopener"
>
our mailing list
</a>
and follow
the official
<a
href=
"https://twitter.com/vuejs"
target=
"_blank"
rel=
"noopener"
>
@vuejs
</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<
template
#
icon
>
<SupportIcon
/>
</
template
>
<
template
#
heading
>
Support Vue
</
template
>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a
href=
"https://vuejs.org/sponsor/"
target=
"_blank"
rel=
"noopener"
>
becoming a sponsor
</a>
.
</WelcomeItem>
</template>
wscf-test-client-vue/src/components/WelcomeItem.vue
0 → 100644
View file @
1e226390
<
template
>
<div
class=
"item"
>
<i>
<slot
name=
"icon"
></slot>
</i>
<div
class=
"details"
>
<h3>
<slot
name=
"heading"
></slot>
</h3>
<slot></slot>
</div>
</div>
</
template
>
<
style
scoped
>
.item
{
margin-top
:
2rem
;
display
:
flex
;
position
:
relative
;
}
.details
{
flex
:
1
;
margin-left
:
1rem
;
}
i
{
display
:
flex
;
place-items
:
center
;
place-content
:
center
;
width
:
32px
;
height
:
32px
;
color
:
var
(
--color-text
);
}
h3
{
font-size
:
1.2rem
;
font-weight
:
500
;
margin-bottom
:
0.4rem
;
color
:
var
(
--color-heading
);
}
@media
(
min-width
:
1024px
)
{
.item
{
margin-top
:
0
;
padding
:
0.4rem
0
1rem
calc
(
var
(
--section-gap
)
/
2
);
}
i
{
top
:
calc
(
50%
-
25px
);
left
:
-26px
;
position
:
absolute
;
border
:
1px
solid
var
(
--color-border
);
background
:
var
(
--color-background
);
border-radius
:
8px
;
width
:
50px
;
height
:
50px
;
}
.item
:before
{
content
:
' '
;
border-left
:
1px
solid
var
(
--color-border
);
position
:
absolute
;
left
:
0
;
bottom
:
calc
(
50%
+
25px
);
height
:
calc
(
50%
-
25px
);
}
.item
:after
{
content
:
' '
;
border-left
:
1px
solid
var
(
--color-border
);
position
:
absolute
;
left
:
0
;
top
:
calc
(
50%
+
25px
);
height
:
calc
(
50%
-
25px
);
}
.item
:first-of-type:before
{
display
:
none
;
}
.item
:last-of-type:after
{
display
:
none
;
}
}
</
style
>
wscf-test-client-vue/src/components/icons/IconCommunity.vue
0 → 100644
View file @
1e226390
<
template
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"20"
height=
"20"
fill=
"currentColor"
>
<path
d=
"M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</
template
>
wscf-test-client-vue/src/components/icons/IconDocumentation.vue
0 → 100644
View file @
1e226390
<
template
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"20"
height=
"17"
fill=
"currentColor"
>
<path
d=
"M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</
template
>
wscf-test-client-vue/src/components/icons/IconEcosystem.vue
0 → 100644
View file @
1e226390
<
template
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"18"
height=
"20"
fill=
"currentColor"
>
<path
d=
"M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</
template
>
wscf-test-client-vue/src/components/icons/IconSupport.vue
0 → 100644
View file @
1e226390
<
template
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"20"
height=
"20"
fill=
"currentColor"
>
<path
d=
"M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</
template
>
wscf-test-client-vue/src/components/icons/IconTooling.vue
0 → 100644
View file @
1e226390
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<
template
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
aria-hidden=
"true"
role=
"img"
class=
"iconify iconify--mdi"
width=
"24"
height=
"24"
preserveAspectRatio=
"xMidYMid meet"
viewBox=
"0 0 24 24"
>
<path
d=
"M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill=
"currentColor"
></path>
</svg>
</
template
>
wscf-test-client-vue/src/main.js
0 → 100644
View file @
1e226390
import
'./assets/main.css'
import
{
createApp
}
from
'vue'
import
App
from
'./App.vue'
createApp
(
App
).
mount
(
'#app'
)
wscf-test-client-vue/src/serviceClients/Foo2ServiceClient.js
0 → 100644
View file @
1e226390
import
{
ref
}
from
"vue"
;
import
Reflect_SeviceClient
from
"@/wscf-client/Reflect_SeviceClient"
;
/**
* eventName: DataChanged
*
* eventArgs: { Time:string, Msg:string }
*/
class
FooServiceClient
extends
Reflect_SeviceClient
{
constructor
(){
super
();
this
.
Data
=
ref
({
Msg
:
''
,
Number
:
0
,
AddFuncTime
:
''
,
Abc
:[],
Param
:{
PName
:
'pname'
,
Target
:
100
,
Bar
:{
Number
:
0
}
},
Bars
:[]
});
}
/**
* @description 加法
* @param {number} a
* @param {number} b
* @returns {{result:number}}
*/
async
Add
(
a
,
b
){
return
await
this
.
SyncCall
(
'Add'
,
{
a
,
b
});
}
/**
*
* @param {*} param
*/
async
Apply
(
param
){
return
await
this
.
SyncCall
(
'Apply'
,
{
param
});
}
}
export
default
FooServiceClient
;
\ No newline at end of file
wscf-test-client-vue/src/serviceClients/FooServiceClient.js
0 → 100644
View file @
1e226390
import
{
ref
}
from
"vue"
;
import
EventEmitter
from
"EventEmitter"
;
const
EVENT_MsgChanged
=
"MsgChanged"
;
class
FooServiceClient
{
constructor
(){
this
.
Number
=
ref
(
0
);
this
.
Msg
=
ref
(
''
);
this
.
eventEmitter
=
new
EventEmitter
();
}
async
Add
(
a
,
b
){
var
ret
=
a
+
b
;
var
t
=
await
this
.
_delay
(
1000
);
console
.
log
(
`delay(1000)=
${
t
}
`
);
return
ret
;
}
_delay
(
time
)
{
return
new
Promise
((
resolve
)
=>
{
setTimeout
(()
=>
{
resolve
(
Math
.
floor
(
time
-
Math
.
random
()
*
10
,
0
));
},
time
);
});
}
start
(){
this
.
timer
=
setInterval
(()
=>
{
this
.
_timerTick
();
},
1000
);
}
stop
(){
clearInterval
(
this
.
timer
);
}
_timerTick
(){
this
.
Number
.
value
++
;
if
(
this
.
Number
.
value
%
10
==
0
){
this
.
Msg
=
`
${
Math
.
floor
(
this
.
Number
.
value
/
10
,
0
)}
个10`
this
.
eventEmitter
.
emit
(
EVENT_MsgChanged
,
this
.
Msg
);
};
}
}
export
default
{
FooServiceClient
,
EVENT_MsgChanged
}
\ No newline at end of file
wscf-test-client-vue/src/serviceClients/TigerServiceClient.js
0 → 100644
View file @
1e226390
import
{
ref
}
from
"vue"
;
import
Reflect_SeviceClient
from
"@/wscf-client/Reflect_SeviceClient"
;
export
default
class
TigeServiceClient
extends
Reflect_SeviceClient
{
constructor
(){
super
();
this
.
Data
=
ref
({
Text
:
'?text'
,
Name
:
'?name'
});
}
//#region protected override
//#endregion
}
wscf-test-client-vue/src/wscf-client/COMMON.js
0 → 100644
View file @
1e226390
/**
*
* @param {string} nodePath
*/
function
FindNode
(
nodePath
){
var
regex
=
/
\[(\d
+
)\]
/
;
var
eval_str
=
""
;
var
paths
=
nodePath
.
split
(
'.'
);
for
(
let
i
=
0
;
i
<
paths
.
length
;
i
++
){
var
path
=
paths
[
i
];
var
matchs
=
path
.
match
(
regex
);
if
(
matchs
){
//能匹配上,是数组 matchs[1] 是数组序号
eval_str
+=
matchs
[
0
];
}
else
{
//是对象
eval_str
+=
`.
${
path
}
`
;
}
}
return
eval_str
;
}
export
{
FindNode
};
\ No newline at end of file
wscf-test-client-vue/src/wscf-client/ReflectSeviceClientAssistant.js
0 → 100644
View file @
1e226390
import
{
v4
as
uuid
}
from
"uuid"
;
import
{
FindNode
}
from
"./COMMON"
;
export
default
class
ReflectSeviceClientAssistant
{
constructor
(){
//#region public
//#endregion
//#region private
/**
* @description 发送数据
* @type (data:string)=>void
*/
this
.
_send
=
null
;
/**
* @description 代理对象
* @type Reflect_SeviceClient
*/
this
.
_obj
=
null
;
/**
* @description 缓存 发出 CALL_GetAllProperties指令,到收到回复 之间时段的 全部推送
* @type Array<{name:string,data:object}>
*/
this
.
_pushInfoList
=
[];
/**
* @description method 的回调函数
* @type Array<{
* guid:string,
* asyncDelegate:(context:object,retData:object)=>void,
* asyncContext:object}>();
*/
this
.
_anyMethodInvokes
=
[];
//#endregion
}
//#region public
/**
*
* @param {*} obj
*/
Init
(
obj
,
send
)
{
this
.
_obj
=
obj
;
this
.
_send
=
send
;
}
/**
* @description 第1次连接成功
*/
OnOpen
(){
console
.
log
(
`OnOpen`
);
//获取全部属性
this
.
GetValue
(
null
,(
context
,
retData
)
=>
{
console
.
log
(
`获取全部属性
${
retData
}
`
);
//同步完成
this
.
_obj
.
IsSynced
=
true
;
//处理全部event
this
.
_dealPushInfoList
();
},
null
);
}
OnClose
(){
console
.
log
(
`OnClose`
);
this
.
_obj
.
IsSynced
=
false
;
}
OnMessage
(
data
){
var
pkgData
=
JSON
.
parse
(
data
);
console
.
log
(
`OnMessage
${
pkgData
}
`
);
//可能是 Event, 也可能是 Method
if
(
!
pkgData
.
guid
){
//EVENT
if
(
!
this
.
_obj
.
IsSynced
){
//还没同步完成,先缓存
this
.
_pushInfoList
.
push
({
name
:
pkgData
.
name
,
data
:
pkgData
.
data
});
return
;
}
else
{
this
.
_receive_EVENT
(
pkgData
.
name
,
pkgData
.
data
);
}
}
else
{
//METHOD
var
idx
=
this
.
_anyMethodInvokes
.
findIndex
(
ami
=>
ami
.
guid
==
pkgData
.
guid
);
if
(
idx
==-
1
){
//没有这个GUID
//异常!!!应该有对应的回调
throw
new
Error
(
`
${
pkgData
.
name
}
异常!!!应该有回调`
);
}
var
anyMethodInvoke
=
this
.
_anyMethodInvokes
[
idx
];
this
.
_receive_CALL_MethodInvoke
(
pkgData
.
name
,
pkgData
.
data
,
anyMethodInvoke
.
asyncDelegate
,
anyMethodInvoke
.
asyncContext
);
//删除
this
.
_anyMethodInvokes
.
splice
(
idx
,
1
);
}
}
GetValue
(
nodePath
,
asyncDelegate
,
asyncContext
){
var
parameters
=
nodePath
;
this
.
_send_CALL_MethodInvoke
(
"GetValue"
,
parameters
,
(
context
,
retData
)
=>
{
this
.
_receive_EVENT_PropertyChanged
(
retData
);
if
(
context
.
asyncDelegate
!=
null
){
context
.
asyncDelegate
(
context
.
asyncContext
,
retData
);
}
},
{
asyncDelegate
,
asyncContext
});
}
SetValue
(
value
,
nodePath
,
asyncDelegate
,
asyncContext
){
var
parameters
=
{
data
:
value
};
if
(
nodePath
!=
null
){
parameters
.
name
=
nodePath
;
}
console
.
log
(
JSON
.
stringify
(
parameters
));
this
.
_send_CALL_MethodInvoke
(
"SetValue"
,
parameters
,
asyncDelegate
,
asyncContext
);
}
Call
(
methodName
,
parameters
,
asyncDelegate
,
asyncContext
){
this
.
_send_CALL_MethodInvoke
(
methodName
,
parameters
,
asyncDelegate
,
asyncContext
);
}
//#endregion
//#region private
/**
* @description 处理全部 缓存的推送数据
*/
_dealPushInfoList
(){
for
(
let
i
=
0
;
i
<
this
.
_pushInfoList
.
length
;
i
++
){
var
pushInfoData
=
this
.
_pushInfoList
[
i
];
this
.
_receive_EVENT
(
pushInfoData
.
name
,
pushInfoData
.
data
);
}
this
.
_pushInfoList
=
[];
}
/**
* @description 处理 从服务器 回复的 PUSH_PropertyChanged
* @param {{name:string,data:object}} data
*/
_receive_EVENT_PropertyChanged
(
data
){
console
.
log
(
`属性改变
${
data
}
`
);
this
.
_obj
.
IsInPushValue
=
true
;
//需要更新的 属性对象节点
var
nodePath
=
data
.
name
;
//数据
var
obj
=
data
.
data
;
if
(
nodePath
==
null
||
nodePath
==
'.'
){
//根
for
(
let
key
in
obj
){
var
value
=
obj
[
key
];
//this._obj.Data 是VUE 的 ref()
this
.
_obj
.
Data
.
value
[
key
]
=
value
;
}
}
else
{
var
path_str
=
FindNode
(
nodePath
);
for
(
let
key
in
obj
){
var
value
=
obj
[
key
];
var
eval_str2
=
`this._obj.Data.value
${
path_str
}
.
${
key
}
=value`
;
console
.
log
(
eval_str2
);
eval
(
eval_str2
);
}
}
this
.
_obj
.
IsInPushValue
=
false
;
}
/**
* @description 处理 从服务器 回复的 EVENT
* @param {string} eventName
* @param {object} retData
*/
_receive_EVENT
(
eventName
,
retData
){
console
.
log
(
`事件触发
${
eventName
}
${
retData
}
`
);
if
(
eventName
==
"PropertyChanged"
){
this
.
_receive_EVENT_PropertyChanged
(
retData
);
}
else
{
this
.
_obj
.
EventEmitter
.
emit
(
eventName
,
retData
);
}
}
/**
* @description 处理 从服务器 回复的 CALL_MethodInvoke
* @param {string} methodName
* @param {object} retData
* @param {(context:object,retData:object)=>void} asyncDelegate
* @param {object} asyncContext
*/
_receive_CALL_MethodInvoke
(
methodName
,
retData
,
asyncDelegate
,
asyncContext
){
console
.
log
(
`函数触发
${
methodName
}
${
retData
}
`
);
if
(
asyncDelegate
!=
null
)
asyncDelegate
(
asyncContext
,
retData
);
}
/**
* @description 发送 CALL_MethodInvoke 请求到服务
* @param {string} methodName
* @param {object} methodParams
* @param {(context:object,retData:object)=>void} asyncDelegate
* @param {object} asyncContext
*/
_send_CALL_MethodInvoke
(
methodName
,
methodParams
,
asyncDelegate
,
asyncContext
){
var
pkgData
=
{
guid
:
uuid
(),
name
:
methodName
};
if
(
methodParams
!=
null
)
pkgData
.
data
=
methodParams
;
this
.
_anyMethodInvokes
.
push
(
{
guid
:
pkgData
.
guid
,
asyncDelegate
:
asyncDelegate
,
asyncContext
:
asyncContext
});
var
json
=
JSON
.
stringify
(
pkgData
);
this
.
_send
(
json
);
}
//#endregion
}
\ No newline at end of file
wscf-test-client-vue/src/wscf-client/Reflect_SeviceClient.js
0 → 100644
View file @
1e226390
import
{
ref
}
from
"vue"
;
import
WebSocketClient
from
"./WebSocketClient"
;
import
ReflectSeviceClientAssistant
from
"./ReflectSeviceClientAssistant"
;
import
EventEmitter
from
"EventEmitter"
;
/** abstract */
export
default
class
Reflect_SeviceClient
extends
WebSocketClient
{
constructor
(){
super
();
//-----------------------------------------------------------------
// public
/**
* @description 已经同步完成;已经收到了 CALL_GetAllProperties, 全部属性都与服务器一致;
* @type bool
*/
this
.
IsSynced
=
false
;
/**
* @description 当前 INotifyPropertyChanged 对象 引发了 PropertyChanged, 是由于 接收到数据导致的
* @type bool
*/
this
.
IsInPushValue
=
false
;
this
.
Data
=
ref
({});
this
.
EventEmitter
=
new
EventEmitter
();
//-----------------------------------------------------------------
// private
/**
* @description
* @type ReflectSeviceClientAssistant
*/
this
.
_assistant
=
new
ReflectSeviceClientAssistant
();
}
//#region public
Init
(
serverName
,
addr
){
super
.
Init
(
serverName
,
addr
);
this
.
_assistant
.
Init
(
this
,
(
data
)
=>
this
.
send
(
data
));
}
/**
* @description 获取属性
* @param {string} nodePath 节点
* @param {(asyncContext:object,retData:object)=>void} asyncDelegate 回调
* @param {object} asyncContext 上下文
*/
GetValue
(
nodePath
=
null
,
asyncDelegate
=
null
,
asyncContext
=
null
){
this
.
_assistant
.
GetValue
(
nodePath
,
asyncDelegate
,
asyncContext
);
}
/**
* @description 获取属性 同步版
* @param {string} nodePath 节点
*/
async
SyncGetValue
(
nodePath
=
null
){
return
await
new
Promise
((
resolve
)
=>
{
this
.
GetValue
(
nodePath
,
(
context
,
retData
)
=>
{
context
(
retData
);
},
resolve
);
});
}
/**
* @description 设置属性
* @param {object} value 属性值
* @param {string} nodePath 节点
* @param {(asyncContext:object,retData:object)=>void} asyncDelegate 回调
* @param {object} asyncContext 上下文
*/
SetValue
(
value
,
nodePath
=
null
,
asyncDelegate
=
null
,
asyncContext
=
null
){
this
.
_assistant
.
SetValue
(
value
,
nodePath
,
asyncDelegate
,
asyncContext
);
}
/**
* @description 设置属性 同步版
* @param {object} value 属性值
* @param {string} nodePath 节点
*/
async
SyncSetValue
(
value
,
nodePath
=
null
){
return
await
new
Promise
((
resolve
)
=>
{
this
.
SetValue
(
value
,
nodePath
,
(
context
,
retData
)
=>
{
context
(
retData
);
},
resolve
);
});
}
/**
* @description 远程方法调用
* @param {string} methodName 方法名
* @param {object} parameters 参数
* @param {(asyncContext:object,retData:object)=>void} asyncDelegate 回调
* @param {object} asyncContext 上下文
*/
Call
(
methodName
,
parameters
=
null
,
asyncDelegate
=
null
,
asyncContext
=
null
)
{
this
.
_assistant
.
Call
(
methodName
,
parameters
,
asyncDelegate
,
asyncContext
);
}
/**
* @description 远程方法调用 同步版
* @param {string} methodName 方法名
* @param {object} parameters 参数
*/
async
SyncCall
(
methodName
,
parameters
=
null
){
return
await
new
Promise
((
resolve
)
=>
{
this
.
Call
(
methodName
,
parameters
,
(
context
,
retData
)
=>
{
context
(
retData
);
},
resolve
);
});
}
//#endregion
//#region protected override
onOpen
(){
this
.
_assistant
.
OnOpen
();
}
onMessage
(
data
){
this
.
_assistant
.
OnMessage
(
data
);
}
onClose
(){
this
.
_assistant
.
OnClose
();
}
//#endregion
//#region protected
//#endregion
}
\ No newline at end of file
wscf-test-client-vue/src/wscf-client/SubPropertyNode.js
0 → 100644
View file @
1e226390
/**
* 子属性节点,用于注册 INotifyPropertyChanged
*/
export
default
class
SubPropertyNode
{
constructor
(){
//#region public
/**
* @description 下级节点
* @type Array<SubPropertyNode>
*/
this
.
Children
=
[];
/**
* @description 下级节点
* @type SubPropertyNode
*/
this
.
Parent
=
null
;
/**
* @description 节点名称
* 正常情况,就是属性的Name;
* 但,当为数组时, 它的下级就是数组的元素。 元素不是数组的属性。 元素的name为 $"[{序号}]"
* @type string
*/
this
.
Name
=
""
;
/**
* @description 节点对象
* @type object
*/
this
.
Obj
=
null
;
/**
* @description 对象的模板接口。默认就是 Obj.GetType()
* @type prototype
*/
this
.
InterfaceType
=
null
;
/**
* @description 是数组
* @type bool
*/
this
.
IsArray
=
false
;
/**
* @description
* @type PropertyChangedEventHandler
*/
this
.
PropertyChanged
=
_PropertyChanged
;
/**
* @description
* @type SubPropertyChangedEventHandler
*/
this
.
SubPropertyChanged
=
null
;
//#endregion
}
_PropertyChanged
(
sender
,
e
)
{
//处理[PropertyPush]重新注册问题
COMMON
.
PropertyChanged_reInitPropertyPush
(
this
,
e
);
SubPropertyChanged
?.
Invoke
(
this
,
e
);
}
}
\ No newline at end of file
wscf-test-client-vue/src/wscf-client/WebSocketClient.js
0 → 100644
View file @
1e226390
import
{
ref
}
from
"vue"
;
/** abstract */
export
default
class
WebSocketClient
{
constructor
()
{
//-----------------------------------------------------------------
// public
/**
* @description 连接中
* @type Ref<bool>
*/
this
.
IsConnected
=
ref
(
false
);
/**
* @description 重连剩余秒数
* @type Ref<number>
*/
this
.
RetrySurplusSec
=
ref
(
0
);
/**
* @description 服务名称 ws://{Addr}/{ServiceName}
* @type Ref<string>
*/
this
.
ServiceName
=
ref
(
""
);
/**
* @description 服务地址 ws://{Addr}/{ServiceName}
* @type Ref<string>
*/
this
.
Addr
=
ref
(
"localhost:5540"
);
/**
* @description URL ws://{Addr}/{ServiceName}
* @type Ref<string>
*/
this
.
URL
=
()
=>
`ws://
${
this
.
Addr
.
value
}
/
${
this
.
ServiceName
.
value
}
`
//-----------------------------------------------------------------
// protected
/**
* @description WebSocket实例
* @type WebSocket
*/
this
.
ws
=
null
;
//-----------------------------------------------------------------
// private
/** 连接重试计时 */
this
.
_retryStopwatch
=
new
Date
();
/** 重连定时器 */
this
.
_retryTimer
=
0
;
}
//-----------------------------------------------------------------
// public
/**
* @description 初始化 然后直接连接
* @param {string} serviceName 服务名称
* @param {string} addr 服务地址
*/
Init
(
serviceName
,
addr
){
this
.
ServiceName
.
value
=
serviceName
;
this
.
Addr
.
value
=
addr
;
this
.
_connect
();
}
/**
* @description 重连
* @param {string} addr
*/
ReConnect
(
addr
)
{
this
.
Addr
.
value
=
addr
;
if
(
this
.
_retryTimer
){
this
.
_stopRetry
();
}
if
(
this
.
ws
)
this
.
_close
();
this
.
_connect
();
}
/**
* @description 释放资源
*/
Dispose
()
{
if
(
this
.
_retryTimer
){
this
.
_stopRetry
();
}
if
(
this
.
ws
)
this
.
_close
();
}
//-----------------------------------------------------------------
// protected
/**
* @description 发送数据
* @param {string} data
*/
send
(
data
)
{
if
(
this
.
ws
.
readyState
!=
WebSocket
.
OPEN
)
{
console
.
error
(
`this.ws.readyState (
${
this
.
ws
.
readyState
}
) != WebSocket.OPEN`
);
return
;
}
this
.
ws
.
send
(
data
);
}
//-----------------------------------------------------------------
// protected abstract
/**
* @description 消息事件,需要重载
* @protected abstract
* @param {string} msg
*/
onMessage
(
msg
){
//throw new Error('you should override "onMessage"');
console
.
error
(
'you should override "onMessage"'
);
}
/**
* @description 连接成功事件,需要重载
* @protected abstract
*/
onOpen
(){
//throw new Error('you should override "onOpen"');
console
.
error
(
'you should override "onOpen"'
);
}
/**
* @description 连接断开事件,需要重载
* @protected abstract
*/
onClose
(){
//throw new Error('you should override "onClose"');
console
.
error
(
'you should override "onClose"'
);
}
//-----------------------------------------------------------------
// private
_connect
()
{
//WebSocket 在 new 时已经异步connect, 失败会调用onclose事件,需要重新new
console
.
log
(
`this.ws = new WebSocket(
${
this
.
URL
()}
)`
);
this
.
ws
=
new
WebSocket
(
this
.
URL
());
this
.
ws
.
onmessage
=
(
ev
)
=>
{
console
.
log
(
`onmessage(
${
ev
}
)`
);
console
.
log
(
`ev.data=
${
ev
.
data
}
`
);
this
.
onMessage
(
ev
.
data
);
};
this
.
ws
.
onclose
=
(
ev
)
=>
{
console
.
log
(
`onclose(
${
ev
}
)`
);
//连接断开,重连
this
.
_retry
();
if
(
this
.
IsConnected
.
value
){
this
.
IsConnected
.
value
=
false
;
this
.
onClose
();
}
}
this
.
ws
.
onerror
=
(
ev
)
=>
{
console
.
log
(
`onerror(
${
ev
}
)`
);
//连接断开,重连
// this._retry();
// if(this.IsConnected.value){
// this.IsConnected.value = false;
// this.onClose();
// }
}
this
.
ws
.
onopen
=
(
ev
)
=>
{
console
.
log
(
`onopen(
${
ev
}
)`
);
this
.
IsConnected
.
value
=
true
;
this
.
onOpen
();
}
}
_close
()
{
this
.
ws
.
close
();
this
.
ws
.
onmessage
=
null
;
this
.
ws
.
onclose
=
null
;
this
.
ws
.
onerror
=
null
;
this
.
ws
.
onopen
=
null
;
this
.
ws
=
null
;
}
_retry
(){
this
.
_retry_stopwatch
=
new
Date
();
this
.
_updateRetryStatus
();
if
(
this
.
_retryTimer
)
this
.
_stopRetry
();
this
.
_startRetry
();
}
_stopRetry
(){
clearInterval
(
this
.
_retryTimer
);
this
.
_retryTimer
=
0
;
}
_startRetry
(){
if
(
this
.
_retryTimer
)
return
;
this
.
_retryTimer
=
setInterval
(()
=>
{
if
(
this
.
_updateRetryStatus
())
{
console
.
log
(
`重连`
);
this
.
_stopRetry
();
this
.
_connect
();
}
},
2000
);
}
/**
* 更新 RetrySurplusSec 值
* @returns 需要触发connect = true
*/
_updateRetryStatus
(){
var
now
=
new
Date
();
var
elapsed_ms
=
now
.
getTime
()
-
this
.
_retry_stopwatch
.
getTime
();
elapsed_ms
=
5000
-
elapsed_ms
;
this
.
RetrySurplusSec
.
value
=
Math
.
floor
(((
elapsed_ms
>
0
)
?
elapsed_ms
:
0
)
/
1000
);
return
(
this
.
RetrySurplusSec
.
value
<=
0
);
}
}
\ No newline at end of file
wscf-test-client-vue/vite.config.js
0 → 100644
View file @
1e226390
import
{
fileURLToPath
,
URL
}
from
'node:url'
import
{
defineConfig
}
from
'vite'
import
vue
from
'@vitejs/plugin-vue'
// https://vite.dev/config/
export
default
defineConfig
({
plugins
:
[
vue
(),
],
resolve
:
{
alias
:
{
'@'
:
fileURLToPath
(
new
URL
(
'./src'
,
import
.
meta
.
url
))
}
}
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment