登录功能

This commit is contained in:
lanzhihui 2026-02-06 10:12:08 +08:00
parent 118aab4f3b
commit 4286fa07f0
22 changed files with 356 additions and 10121 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,49 +1,43 @@
{
"hash": "cb5d0200",
"configHash": "ed1743b1",
"lockfileHash": "dc2ce3eb",
"browserHash": "7eb5a1d0",
"hash": "21acb680",
"configHash": "f8279dd9",
"lockfileHash": "3f41a995",
"browserHash": "9ba88dfd",
"optimized": {
"@vue/devtools-api": {
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "@vue_devtools-api.js",
"fileHash": "78218010",
"fileHash": "51d28fb6",
"needsInterop": false
},
"@vuepress/shared": {
"src": "../../../../node_modules/@vuepress/shared/dist/index.js",
"file": "@vuepress_shared.js",
"fileHash": "97474d81",
"fileHash": "1c5d8c58",
"needsInterop": false
},
"vue": {
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "bf4f1bd0",
"fileHash": "aff3e00e",
"needsInterop": false
},
"vue-router": {
"src": "../../../../node_modules/vue-router/dist/vue-router.esm-bundler.js",
"file": "vue-router.js",
"fileHash": "1ed8f5d8",
"fileHash": "d25827a8",
"needsInterop": false
},
"pinia": {
"src": "../../../../node_modules/pinia/dist/pinia.mjs",
"file": "pinia.js",
"fileHash": "cec75367",
"fileHash": "b5e4c171",
"needsInterop": false
},
"axios": {
"src": "../../../../node_modules/axios/index.js",
"file": "axios.js",
"fileHash": "5ad3ff1a",
"needsInterop": false
},
"@vueuse/core": {
"src": "../../../../node_modules/@vueuse/core/index.mjs",
"file": "@vueuse_core.js",
"fileHash": "ece7d2ca",
"fileHash": "a24178aa",
"needsInterop": false
}
},

View File

@ -46,8 +46,8 @@ var isPlainObject = (val) => {
if (kindOf(val) !== "object") {
return false;
}
const prototype3 = getPrototypeOf(val);
return (prototype3 === null || prototype3 === Object.prototype || Object.getPrototypeOf(prototype3) === null) && !(toStringTag in val) && !(iterator in val);
const prototype2 = getPrototypeOf(val);
return (prototype2 === null || prototype2 === Object.prototype || Object.getPrototypeOf(prototype2) === null) && !(toStringTag in val) && !(iterator in val);
};
var isEmptyObject = (val) => {
if (!isObject(val) || isBuffer(val)) {
@ -130,10 +130,8 @@ function merge() {
result[targetKey] = merge({}, val);
} else if (isArray(val)) {
result[targetKey] = val.slice();
} else {
if (!skipUndefined || !isUndefined(val)) {
result[targetKey] = val;
}
} else if (!skipUndefined || !isUndefined(val)) {
result[targetKey] = val;
}
};
for (let i = 0, l = arguments.length; i < l; i++) {
@ -144,9 +142,19 @@ function merge() {
var extend = (a, b, thisArg, { allOwnKeys } = {}) => {
forEach(b, (val, key) => {
if (thisArg && isFunction(val)) {
a[key] = bind(val, thisArg);
Object.defineProperty(a, key, {
value: bind(val, thisArg),
writable: true,
enumerable: true,
configurable: true
});
} else {
a[key] = val;
Object.defineProperty(a, key, {
value: val,
writable: true,
enumerable: true,
configurable: true
});
}
}, { allOwnKeys });
return a;
@ -157,9 +165,14 @@ var stripBOM = (content) => {
}
return content;
};
var inherits = (constructor, superConstructor, props, descriptors2) => {
constructor.prototype = Object.create(superConstructor.prototype, descriptors2);
constructor.prototype.constructor = constructor;
var inherits = (constructor, superConstructor, props, descriptors) => {
constructor.prototype = Object.create(superConstructor.prototype, descriptors);
Object.defineProperty(constructor.prototype, "constructor", {
value: constructor,
writable: true,
enumerable: false,
configurable: true
});
Object.defineProperty(constructor, "super", {
value: superConstructor.prototype
});
@ -240,9 +253,9 @@ var toCamelCase = (str) => {
var hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype);
var isRegExp = kindOfTest("RegExp");
var reduceDescriptors = (obj, reducer) => {
const descriptors2 = Object.getOwnPropertyDescriptors(obj);
const descriptors = Object.getOwnPropertyDescriptors(obj);
const reducedDescriptors = {};
forEach(descriptors2, (descriptor, name) => {
forEach(descriptors, (descriptor, name) => {
let ret;
if ((ret = reducer(descriptor, name, obj)) !== false) {
reducedDescriptors[name] = ret || descriptor;
@ -397,25 +410,38 @@ var utils_default = {
};
// node_modules/axios/lib/core/AxiosError.js
function AxiosError(message, code, config, request, response) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = new Error().stack;
var AxiosError = class _AxiosError extends Error {
static from(error, code, config, request, response, customProps) {
const axiosError = new _AxiosError(error.message, code || error.code, config, request, response);
axiosError.cause = error;
axiosError.name = error.name;
customProps && Object.assign(axiosError, customProps);
return axiosError;
}
this.message = message;
this.name = "AxiosError";
code && (this.code = code);
config && (this.config = config);
request && (this.request = request);
if (response) {
this.response = response;
this.status = response.status ? response.status : null;
/**
* Create an Error with the specified message, config, error code, request and response.
*
* @param {string} message The error message.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [config] The config.
* @param {Object} [request] The request.
* @param {Object} [response] The response.
*
* @returns {Error} The created error.
*/
constructor(message, code, config, request, response) {
super(message);
this.name = "AxiosError";
this.isAxiosError = true;
code && (this.code = code);
config && (this.config = config);
request && (this.request = request);
if (response) {
this.response = response;
this.status = response.status;
}
}
}
utils_default.inherits(AxiosError, Error, {
toJSON: function toJSON() {
toJSON() {
return {
// Standard
message: this.message,
@ -434,45 +460,19 @@ utils_default.inherits(AxiosError, Error, {
status: this.status
};
}
});
var prototype = AxiosError.prototype;
var descriptors = {};
[
"ERR_BAD_OPTION_VALUE",
"ERR_BAD_OPTION",
"ECONNABORTED",
"ETIMEDOUT",
"ERR_NETWORK",
"ERR_FR_TOO_MANY_REDIRECTS",
"ERR_DEPRECATED",
"ERR_BAD_RESPONSE",
"ERR_BAD_REQUEST",
"ERR_CANCELED",
"ERR_NOT_SUPPORT",
"ERR_INVALID_URL"
// eslint-disable-next-line func-names
].forEach((code) => {
descriptors[code] = { value: code };
});
Object.defineProperties(AxiosError, descriptors);
Object.defineProperty(prototype, "isAxiosError", { value: true });
AxiosError.from = (error, code, config, request, response, customProps) => {
const axiosError = Object.create(prototype);
utils_default.toFlatObject(error, axiosError, function filter2(obj) {
return obj !== Error.prototype;
}, (prop) => {
return prop !== "isAxiosError";
});
const msg = error && error.message ? error.message : "Error";
const errCode = code == null && error ? error.code : code;
AxiosError.call(axiosError, msg, errCode, config, request, response);
if (error && axiosError.cause == null) {
Object.defineProperty(axiosError, "cause", { value: error, configurable: true });
}
axiosError.name = error && error.name || "Error";
customProps && Object.assign(axiosError, customProps);
return axiosError;
};
AxiosError.ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";
AxiosError.ERR_BAD_OPTION = "ERR_BAD_OPTION";
AxiosError.ECONNABORTED = "ECONNABORTED";
AxiosError.ETIMEDOUT = "ETIMEDOUT";
AxiosError.ERR_NETWORK = "ERR_NETWORK";
AxiosError.ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";
AxiosError.ERR_DEPRECATED = "ERR_DEPRECATED";
AxiosError.ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";
AxiosError.ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
AxiosError.ERR_CANCELED = "ERR_CANCELED";
AxiosError.ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT";
AxiosError.ERR_INVALID_URL = "ERR_INVALID_URL";
var AxiosError_default = AxiosError;
// node_modules/axios/lib/helpers/null.js
@ -612,11 +612,11 @@ function AxiosURLSearchParams(params, options) {
this._pairs = [];
params && toFormData_default(params, this, options);
}
var prototype2 = AxiosURLSearchParams.prototype;
prototype2.append = function append(name, value) {
var prototype = AxiosURLSearchParams.prototype;
prototype.append = function append(name, value) {
this._pairs.push([name, value]);
};
prototype2.toString = function toString2(encoder) {
prototype.toString = function toString2(encoder) {
const _encode = encoder ? function(value) {
return encoder.call(this, value, encode);
} : encode;
@ -635,17 +635,15 @@ function buildURL(url, params, options) {
return url;
}
const _encode = options && options.encode || encode2;
if (utils_default.isFunction(options)) {
options = {
serialize: options
};
}
const serializeFn = options && options.serialize;
const _options = utils_default.isFunction(options) ? {
serialize: options
} : options;
const serializeFn = _options && _options.serialize;
let serializedParams;
if (serializeFn) {
serializedParams = serializeFn(params, options);
serializedParams = serializeFn(params, _options);
} else {
serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, options).toString(_encode);
serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, _options).toString(_encode);
}
if (serializedParams) {
const hashmarkIndex = url.indexOf("#");
@ -667,6 +665,7 @@ var InterceptorManager = class {
*
* @param {Function} fulfilled The function to handle `then` for a `Promise`
* @param {Function} rejected The function to handle `reject` for a `Promise`
* @param {Object} options The options for the interceptor, synchronous and runWhen
*
* @return {Number} An ID used to remove interceptor later
*/
@ -684,7 +683,7 @@ var InterceptorManager = class {
*
* @param {Number} id The ID that was returned by `use`
*
* @returns {Boolean} `true` if the interceptor was removed, `false` otherwise
* @returns {void}
*/
eject(id) {
if (this.handlers[id]) {
@ -1197,11 +1196,11 @@ var AxiosHeaders = class {
accessors: {}
};
const accessors = internals.accessors;
const prototype3 = this.prototype;
const prototype2 = this.prototype;
function defineAccessor(_header) {
const lHeader = normalizeHeader(_header);
if (!accessors[lHeader]) {
buildAccessors(prototype3, _header);
buildAccessors(prototype2, _header);
accessors[lHeader] = true;
}
}
@ -1241,13 +1240,22 @@ function isCancel(value) {
}
// node_modules/axios/lib/cancel/CanceledError.js
function CanceledError(message, config, request) {
AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
this.name = "CanceledError";
}
utils_default.inherits(CanceledError, AxiosError_default, {
__CANCEL__: true
});
var CanceledError = class extends AxiosError_default {
/**
* A `CanceledError` is an object that is thrown when an operation is canceled.
*
* @param {string=} message The message.
* @param {Object=} config The config.
* @param {Object=} request The request.
*
* @returns {CanceledError} The created error.
*/
constructor(message, config, request) {
super(message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
this.name = "CanceledError";
this.__CANCEL__ = true;
}
};
var CanceledError_default = CanceledError;
// node_modules/axios/lib/core/settle.js
@ -1391,20 +1399,33 @@ var isURLSameOrigin_default = platform_default.hasStandardBrowserEnv ? /* @__PUR
var cookies_default = platform_default.hasStandardBrowserEnv ? (
// Standard browser envs support document.cookie
{
write(name, value, expires, path, domain, secure) {
const cookie = [name + "=" + encodeURIComponent(value)];
utils_default.isNumber(expires) && cookie.push("expires=" + new Date(expires).toGMTString());
utils_default.isString(path) && cookie.push("path=" + path);
utils_default.isString(domain) && cookie.push("domain=" + domain);
secure === true && cookie.push("secure");
write(name, value, expires, path, domain, secure, sameSite) {
if (typeof document === "undefined") return;
const cookie = [`${name}=${encodeURIComponent(value)}`];
if (utils_default.isNumber(expires)) {
cookie.push(`expires=${new Date(expires).toUTCString()}`);
}
if (utils_default.isString(path)) {
cookie.push(`path=${path}`);
}
if (utils_default.isString(domain)) {
cookie.push(`domain=${domain}`);
}
if (secure === true) {
cookie.push("secure");
}
if (utils_default.isString(sameSite)) {
cookie.push(`SameSite=${sameSite}`);
}
document.cookie = cookie.join("; ");
},
read(name) {
const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)"));
return match ? decodeURIComponent(match[3]) : null;
if (typeof document === "undefined") return null;
const match = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
return match ? decodeURIComponent(match[1]) : null;
},
remove(name) {
this.write(name, "", Date.now() - 864e5);
this.write(name, "", Date.now() - 864e5, "/");
}
}
) : (
@ -1702,7 +1723,7 @@ var composeSignals = (signals, timeout) => {
};
let timer = timeout && setTimeout(() => {
timer = null;
onabort(new AxiosError_default(`timeout ${timeout} of ms exceeded`, AxiosError_default.ETIMEDOUT));
onabort(new AxiosError_default(`timeout of ${timeout}ms exceeded`, AxiosError_default.ETIMEDOUT));
}, timeout);
const unsubscribe = () => {
if (signals) {
@ -1802,8 +1823,7 @@ var trackStream = (stream, chunkSize, onProgress, onFinish) => {
// node_modules/axios/lib/adapters/fetch.js
var DEFAULT_CHUNK_SIZE = 64 * 1024;
var { isFunction: isFunction2 } = utils_default;
var globalFetchAPI = (({ fetch, Request, Response }) => ({
fetch,
var globalFetchAPI = (({ Request, Response }) => ({
Request,
Response
}))(utils_default.global);
@ -1819,8 +1839,11 @@ var test = (fn, ...args) => {
}
};
var factory = (env) => {
const { fetch, Request, Response } = Object.assign({}, globalFetchAPI, env);
const isFetchSupported = isFunction2(fetch);
env = utils_default.merge.call({
skipUndefined: true
}, globalFetchAPI, env);
const { fetch: envFetch, Request, Response } = env;
const isFetchSupported = envFetch ? isFunction2(envFetch) : typeof fetch === "function";
const isRequestSupported = isFunction2(Request);
const isResponseSupported = isFunction2(Response);
if (!isFetchSupported) {
@ -1898,6 +1921,7 @@ var factory = (env) => {
withCredentials = "same-origin",
fetchOptions
} = resolveConfig_default(config);
let _fetch = envFetch || fetch;
responseType = responseType ? (responseType + "").toLowerCase() : "text";
let composedSignal = composeSignals_default([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
let request = null;
@ -1938,7 +1962,7 @@ var factory = (env) => {
credentials: isCredentialsSupported ? withCredentials : void 0
};
request = isRequestSupported && new Request(url, resolvedOptions);
let response = await (isRequestSupported ? fetch(request, fetchOptions) : fetch(url, resolvedOptions));
let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url, resolvedOptions));
const isStreamResponse = supportsResponseStream && (responseType === "stream" || responseType === "response");
if (supportsResponseStream && (onDownloadProgress || isStreamResponse && unsubscribe)) {
const options = {};
@ -1987,14 +2011,12 @@ var factory = (env) => {
};
var seedCache = /* @__PURE__ */ new Map();
var getFetch = (config) => {
let env = utils_default.merge.call({
skipUndefined: true
}, globalFetchAPI, config ? config.env : null);
const { fetch, Request, Response } = env;
let env = config && config.env || {};
const { fetch: fetch2, Request, Response } = env;
const seeds = [
Request,
Response,
fetch
fetch2
];
let len = seeds.length, i = len, seed, target, map = seedCache;
while (i--) {
@ -2026,40 +2048,49 @@ utils_default.forEach(knownAdapters, (fn, value) => {
});
var renderReason = (reason) => `- ${reason}`;
var isResolvedHandle = (adapter2) => utils_default.isFunction(adapter2) || adapter2 === null || adapter2 === false;
function getAdapter(adapters, config) {
adapters = utils_default.isArray(adapters) ? adapters : [adapters];
const { length } = adapters;
let nameOrAdapter;
let adapter2;
const rejectedReasons = {};
for (let i = 0; i < length; i++) {
nameOrAdapter = adapters[i];
let id;
adapter2 = nameOrAdapter;
if (!isResolvedHandle(nameOrAdapter)) {
adapter2 = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
if (adapter2 === void 0) {
throw new AxiosError_default(`Unknown adapter '${id}'`);
}
}
if (adapter2 && (utils_default.isFunction(adapter2) || (adapter2 = adapter2.get(config)))) {
break;
}
rejectedReasons[id || "#" + i] = adapter2;
}
if (!adapter2) {
const reasons = Object.entries(rejectedReasons).map(
([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build")
);
let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified";
throw new AxiosError_default(
`There is no suitable adapter to dispatch the request ` + s,
"ERR_NOT_SUPPORT"
);
}
return adapter2;
}
var adapters_default = {
getAdapter: (adapters, config) => {
adapters = utils_default.isArray(adapters) ? adapters : [adapters];
const { length } = adapters;
let nameOrAdapter;
let adapter2;
const rejectedReasons = {};
for (let i = 0; i < length; i++) {
nameOrAdapter = adapters[i];
let id;
adapter2 = nameOrAdapter;
if (!isResolvedHandle(nameOrAdapter)) {
adapter2 = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
if (adapter2 === void 0) {
throw new AxiosError_default(`Unknown adapter '${id}'`);
}
}
if (adapter2 && (utils_default.isFunction(adapter2) || (adapter2 = adapter2.get(config)))) {
break;
}
rejectedReasons[id || "#" + i] = adapter2;
}
if (!adapter2) {
const reasons = Object.entries(rejectedReasons).map(
([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build")
);
let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified";
throw new AxiosError_default(
`There is no suitable adapter to dispatch the request ` + s,
"ERR_NOT_SUPPORT"
);
}
return adapter2;
},
/**
* Resolve an adapter from a list of adapter names or functions.
* @type {Function}
*/
getAdapter,
/**
* Exposes all known adapters
* @type {Object<string, Function|Object>}
*/
adapters: knownAdapters
};
@ -2109,7 +2140,7 @@ function dispatchRequest(config) {
}
// node_modules/axios/lib/env/data.js
var VERSION = "1.12.0";
var VERSION = "1.13.4";
// node_modules/axios/lib/helpers/validator.js
var validators = {};
@ -2292,7 +2323,6 @@ var Axios = class {
}
len = requestInterceptorChain.length;
let newConfig = config;
i = 0;
while (i < len) {
const onFulfilled = requestInterceptorChain[i++];
const onRejected = requestInterceptorChain[i++];
@ -2522,7 +2552,13 @@ var HttpStatusCode = {
InsufficientStorage: 507,
LoopDetected: 508,
NotExtended: 510,
NetworkAuthenticationRequired: 511
NetworkAuthenticationRequired: 511,
WebServerIsDown: 521,
ConnectionTimedOut: 522,
OriginIsUnreachable: 523,
TimeoutOccurred: 524,
SslHandshakeFailed: 525,
InvalidSslCertificate: 526
};
Object.entries(HttpStatusCode).forEach(([key, value]) => {
HttpStatusCode[value] = key;
@ -2578,7 +2614,7 @@ var {
AxiosHeaders: AxiosHeaders2,
HttpStatusCode: HttpStatusCode2,
formToJSON,
getAdapter,
getAdapter: getAdapter2,
mergeConfig: mergeConfig2
} = axios_default;
export {
@ -2593,7 +2629,7 @@ export {
all2 as all,
axios_default as default,
formToJSON,
getAdapter,
getAdapter2 as getAdapter,
isAxiosError2 as isAxiosError,
isCancel2 as isCancel,
mergeConfig2 as mergeConfig,

File diff suppressed because one or more lines are too long

View File

@ -9,8 +9,7 @@ import * as clientConfig7 from 'D:/xue/dma_handbook/docs/.vuepress/.temp/prismjs
import * as clientConfig8 from 'D:/xue/dma_handbook/docs/.vuepress/.temp/markdown-tab/config.js'
import * as clientConfig9 from 'D:/xue/dma_handbook/node_modules/@vuepress/plugin-theme-data/lib/client/config.js'
import * as clientConfig10 from 'D:/xue/dma_handbook/node_modules/@vuepress/theme-default/lib/client/config.js'
import * as clientConfig11 from 'D:/xue/dma_handbook/node_modules/@vuepress/plugin-search/lib/client/config.js'
import * as clientConfig12 from 'D:/xue/dma_handbook/docs/.vuepress/client.js'
import * as clientConfig11 from 'D:/xue/dma_handbook/docs/.vuepress/client.js'
export const clientConfigs = [
clientConfig0,
@ -25,5 +24,4 @@ export const clientConfigs = [
clientConfig9,
clientConfig10,
clientConfig11,
clientConfig12,
].map((m) => m.default).filter(Boolean)

View File

@ -1,4 +1,4 @@
export const siteData = JSON.parse("{\"base\":\"/dma_handbook/\",\"lang\":\"zh-CN\",\"title\":\"DMA服务人员服务操作手册\",\"description\":\"DMA服务人员服务操作手册\",\"head\":[[\"meta\",{\"name\":\"og:type\",\"content\":\"website\"}],[\"meta\",{\"property\":\"og:title\",\"content\":\"DMA服务人员操作手册\"}],[\"meta\",{\"name\":\"description\",\"content\":\"DMA服务操作手册\"}],[\"meta\",{\"property\":\"og:description\",\"content\":\"DMA服务全流程操作指南\"}],[\"meta\",{\"property\":\"og:image\",\"content\":\"https://images.health.ufutx.com/202503/12/1f227399ffc2ddbf6c58eafa80627d19.png?v=1770021719831\"}],[\"link\",{\"rel\":\"icon\",\"href\":\"https://images.health.ufutx.com/202503/12/1f227399ffc2ddbf6c58eafa80627d19.png?v=1770021719831\"}]],\"locales\":{}}")
export const siteData = JSON.parse("{\"base\":\"/dma_handbook/\",\"lang\":\"zh-CN\",\"title\":\"DMA服务人员服务操作手册\",\"description\":\"DMA服务人员服务操作手册\",\"head\":[[\"meta\",{\"name\":\"og:type\",\"content\":\"website\"}],[\"meta\",{\"property\":\"og:title\",\"content\":\"DMA服务人员操作手册\"}],[\"meta\",{\"name\":\"description\",\"content\":\"DMA服务操作手册\"}],[\"meta\",{\"property\":\"og:description\",\"content\":\"DMA服务全流程操作指南\"}],[\"meta\",{\"property\":\"og:image\",\"content\":\"https://images.health.ufutx.com/202503/12/1f227399ffc2ddbf6c58eafa80627d19.png?v=1770343814876\"}],[\"link\",{\"rel\":\"icon\",\"href\":\"https://images.health.ufutx.com/202503/12/1f227399ffc2ddbf6c58eafa80627d19.png?v=1770343814876\"}]],\"locales\":{}}")
if (import.meta.webpackHot) {
import.meta.webpackHot.accept()

View File

@ -1,5 +1,5 @@
import comp from "D:/xue/dma_handbook/docs/.vuepress/.temp/pages/index.html.vue"
const data = JSON.parse("{\"path\":\"/\",\"title\":\"首页\",\"lang\":\"zh-CN\",\"frontmatter\":{},\"headers\":[{\"level\":2,\"title\":\"一、手册目的\",\"slug\":\"一、手册目的\",\"link\":\"#一、手册目的\",\"children\":[]},{\"level\":2,\"title\":\"二、适用范围\",\"slug\":\"二、适用范围\",\"link\":\"#二、适用范围\",\"children\":[]},{\"level\":2,\"title\":\"三、核心原则\",\"slug\":\"三、核心原则\",\"link\":\"#三、核心原则\",\"children\":[]},{\"level\":2,\"title\":\"四、岗位权责\",\"slug\":\"四、岗位权责\",\"link\":\"#四、岗位权责\",\"children\":[{\"level\":3,\"title\":\"(一)行政\",\"slug\":\"一-行政\",\"link\":\"#一-行政\",\"children\":[]},{\"level\":3,\"title\":\"(二)客服\",\"slug\":\"二-客服\",\"link\":\"#二-客服\",\"children\":[]},{\"level\":3,\"title\":\"(三)健康管理师\",\"slug\":\"三-健康管理师\",\"link\":\"#三-健康管理师\",\"children\":[]},{\"level\":3,\"title\":\"(四)系统审核员\",\"slug\":\"四-系统审核员\",\"link\":\"#四-系统审核员\",\"children\":[]},{\"level\":3,\"title\":\"(五)主教练、副教练\",\"slug\":\"五-主教练、副教练\",\"link\":\"#五-主教练、副教练\",\"children\":[]}]},{\"level\":2,\"title\":\"五、服务规范与沟通话术\",\"slug\":\"五、服务规范与沟通话术\",\"link\":\"#五、服务规范与沟通话术\",\"children\":[{\"level\":3,\"title\":\"(一)仪容仪表规范\",\"slug\":\"一-仪容仪表规范\",\"link\":\"#一-仪容仪表规范\",\"children\":[]},{\"level\":3,\"title\":\"(二)沟通话术规范\",\"slug\":\"二-沟通话术规范\",\"link\":\"#二-沟通话术规范\",\"children\":[]}]},{\"level\":2,\"title\":\"六、系统工具使用说明\",\"slug\":\"六、系统工具使用说明\",\"link\":\"#六、系统工具使用说明\",\"children\":[{\"level\":3,\"title\":\"(一)后台系统常用功能\",\"slug\":\"一-后台系统常用功能\",\"link\":\"#一-后台系统常用功能\",\"children\":[]},{\"level\":3,\"title\":\"(二)群聊管理工具使用\",\"slug\":\"二-群聊管理工具使用\",\"link\":\"#二-群聊管理工具使用\",\"children\":[]}]},{\"level\":2,\"title\":\"七、考核与反馈机制\",\"slug\":\"七、考核与反馈机制\",\"link\":\"#七、考核与反馈机制\",\"children\":[{\"level\":3,\"title\":\"(一)考核指标\",\"slug\":\"一-考核指标\",\"link\":\"#一-考核指标\",\"children\":[]},{\"level\":3,\"title\":\"(二)反馈渠道\",\"slug\":\"二-反馈渠道\",\"link\":\"#二-反馈渠道\",\"children\":[]}]},{\"level\":2,\"title\":\"八、更新日志\",\"slug\":\"八、更新日志\",\"link\":\"#八、更新日志\",\"children\":[]},{\"level\":2,\"title\":\"附录:流程节点时效汇总表\",\"slug\":\"附录-流程节点时效汇总表\",\"link\":\"#附录-流程节点时效汇总表\",\"children\":[]}],\"git\":{\"updatedTime\":1766471007000,\"contributors\":[{\"name\":\"lanzhihui\",\"username\":\"\",\"email\":\"503792708@qq.com\",\"commits\":4}],\"changelog\":[{\"hash\":\"326fedda6067ab0da7a7c497e8fef608057cb12e\",\"time\":1766471007000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"update\"},{\"hash\":\"169908d04e7a4ef15ffea1d8ca58004c9c7451c4\",\"time\":1762222814000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"update\"},{\"hash\":\"7799842e4c8bfd3bbd24d9cbc89c8ac4c28c918b\",\"time\":1761103662000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"更新\"},{\"hash\":\"e73bbe09086600f49aec344301695549746ba3c4\",\"time\":1759135896000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"初始化\"}]},\"filePathRelative\":\"README.md\"}")
const data = JSON.parse("{\"path\":\"/\",\"title\":\"首页\",\"lang\":\"zh-CN\",\"frontmatter\":{},\"headers\":[{\"level\":2,\"title\":\"一、手册目的\",\"slug\":\"一、手册目的\",\"link\":\"#一、手册目的\",\"children\":[]},{\"level\":2,\"title\":\"二、适用范围\",\"slug\":\"二、适用范围\",\"link\":\"#二、适用范围\",\"children\":[]},{\"level\":2,\"title\":\"三、核心原则\",\"slug\":\"三、核心原则\",\"link\":\"#三、核心原则\",\"children\":[]},{\"level\":2,\"title\":\"四、岗位权责\",\"slug\":\"四、岗位权责\",\"link\":\"#四、岗位权责\",\"children\":[{\"level\":3,\"title\":\"(一)行政\",\"slug\":\"一-行政\",\"link\":\"#一-行政\",\"children\":[]},{\"level\":3,\"title\":\"(二)客服\",\"slug\":\"二-客服\",\"link\":\"#二-客服\",\"children\":[]},{\"level\":3,\"title\":\"(三)健康管理师\",\"slug\":\"三-健康管理师\",\"link\":\"#三-健康管理师\",\"children\":[]},{\"level\":3,\"title\":\"(四)系统审核员\",\"slug\":\"四-系统审核员\",\"link\":\"#四-系统审核员\",\"children\":[]},{\"level\":3,\"title\":\"(五)主教练、副教练\",\"slug\":\"五-主教练、副教练\",\"link\":\"#五-主教练、副教练\",\"children\":[]}]},{\"level\":2,\"title\":\"五、服务规范与沟通话术\",\"slug\":\"五、服务规范与沟通话术\",\"link\":\"#五、服务规范与沟通话术\",\"children\":[{\"level\":3,\"title\":\"(一)仪容仪表规范\",\"slug\":\"一-仪容仪表规范\",\"link\":\"#一-仪容仪表规范\",\"children\":[]},{\"level\":3,\"title\":\"(二)沟通话术规范\",\"slug\":\"二-沟通话术规范\",\"link\":\"#二-沟通话术规范\",\"children\":[]}]},{\"level\":2,\"title\":\"六、系统工具使用说明\",\"slug\":\"六、系统工具使用说明\",\"link\":\"#六、系统工具使用说明\",\"children\":[{\"level\":3,\"title\":\"(一)后台系统常用功能\",\"slug\":\"一-后台系统常用功能\",\"link\":\"#一-后台系统常用功能\",\"children\":[]},{\"level\":3,\"title\":\"(二)群聊管理工具使用\",\"slug\":\"二-群聊管理工具使用\",\"link\":\"#二-群聊管理工具使用\",\"children\":[]}]},{\"level\":2,\"title\":\"七、考核与反馈机制\",\"slug\":\"七、考核与反馈机制\",\"link\":\"#七、考核与反馈机制\",\"children\":[{\"level\":3,\"title\":\"(一)考核指标\",\"slug\":\"一-考核指标\",\"link\":\"#一-考核指标\",\"children\":[]},{\"level\":3,\"title\":\"(二)反馈渠道\",\"slug\":\"二-反馈渠道\",\"link\":\"#二-反馈渠道\",\"children\":[]}]},{\"level\":2,\"title\":\"八、更新日志\",\"slug\":\"八、更新日志\",\"link\":\"#八、更新日志\",\"children\":[]},{\"level\":2,\"title\":\"附录:流程节点时效汇总表\",\"slug\":\"附录-流程节点时效汇总表\",\"link\":\"#附录-流程节点时效汇总表\",\"children\":[]}],\"git\":{\"updatedTime\":1770258280000,\"contributors\":[{\"name\":\"lanzhihui\",\"username\":\"\",\"email\":\"503792708@qq.com\",\"commits\":5}],\"changelog\":[{\"hash\":\"118aab4f3bb5c4790ce2ecfc3c5897cfd7146161\",\"time\":1770258280000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"增加登录功能和权限验证\"},{\"hash\":\"326fedda6067ab0da7a7c497e8fef608057cb12e\",\"time\":1766471007000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"update\"},{\"hash\":\"169908d04e7a4ef15ffea1d8ca58004c9c7451c4\",\"time\":1762222814000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"update\"},{\"hash\":\"7799842e4c8bfd3bbd24d9cbc89c8ac4c28c918b\",\"time\":1761103662000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"更新\"},{\"hash\":\"e73bbe09086600f49aec344301695549746ba3c4\",\"time\":1759135896000,\"email\":\"503792708@qq.com\",\"author\":\"lanzhihui\",\"message\":\"初始化\"}]},\"filePathRelative\":\"README.md\"}")
export { comp, data }
if (import.meta.webpackHot) {

File diff suppressed because one or more lines are too long

View File

@ -12,9 +12,6 @@
<p>您可通过以下方式查看手环电量</p>
<ul>
<li>
<p>直接查看手环屏幕通常会显示电量百分比</p>
</li>
<li>
<p>打开友福同享APP进入设备管理页面找到对应手环设备即可查看实时电量信息</p>
</li>
<li>
@ -22,7 +19,7 @@
</li>
<li>
<p>也可以通过APP手环首页顶部电量百分比查看电量低于30%的情况请及时充电</p>
<longPic src="https://images.health.ufutx.com/202408/16/d2b5ca33bd970f64a6301fa75ae2eb221723775855837.jpeg"></longPic><p>后续会规划低电量预警警告提醒功能请耐心等待</p>
<longPic src="https://images.health.ufutx.com/202602/05/ef2e5a95d213ba80b022eff89877fd1c.jpg"></longPic><p>后续会规划低电量预警警告提醒功能请耐心等待</p>
</li>
</ul>
<h3 id="_4-手环正确佩戴方式是什么" tabindex="-1"><a class="header-anchor" href="#_4-手环正确佩戴方式是什么"><span>4. 手环正确佩戴方式是什么</span></a></h3>
@ -124,7 +121,7 @@
<p><strong><a href="https://images.health.ufutx.com/202410/15/2024101401.mp4" target="_blank" rel="noopener noreferrer">点击查看使用健康体脂秤用视频</a></strong></p>
</li>
</ul>
<h3 id="_14-购买25800元友福同享dma智能健康方案-它包含哪些服务-及相关的流程是什么" tabindex="-1"><a class="header-anchor" href="#_14-购买25800元友福同享dma智能健康方案-它包含哪些服务-及相关的流程是什么"><span>14. 购买25800元友福同享DMA智能健康方案它包含哪些服务及相关的流程是什么</span></a></h3>
<h3 id="_14-购买友福同享dma智能健康方案-它包含哪些服务-及相关的流程是什么" tabindex="-1"><a class="header-anchor" href="#_14-购买友福同享dma智能健康方案-它包含哪些服务-及相关的流程是什么"><span>14. 购买友福同享DMA智能健康方案它包含哪些服务及相关的流程是什么</span></a></h3>
<p>友福同享DMA智能健康方案包含以下服务与流程具体以实际为准建议咨询客服确认</p>
<ul>
<li>
@ -304,7 +301,7 @@
<div class="hint-container tip">
<p class="hint-container-title"> 支持换货的情形</p>
<ul>
<li>非电池原因导致 <strong>屏幕无法显示</strong> <strong>无法测量数据</strong></li>
<li>非电池原因导致 <strong>无法测量数据</strong></li>
<li>出厂即存在功能缺陷</li>
</ul>
</div>
@ -325,7 +322,7 @@
<ol>
<li>
<p><strong>客服介入</strong><br>
DMA 服务群内的专属客服全程跟进换货事宜</p>
DMA群里的客服跟进</p>
</li>
<li>
<p><strong>资料收集与申请</strong><br>
@ -338,11 +335,36 @@
<span class="line"> - 手环 / 体脂秤</span>
<span class="line"> - 若为手环请注明类型A已测试 B未拆封</span>
<span class="line"> - 是否需同步配发 Type-C USB 转换头</span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></li>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></li>
<li>
<p><strong>正在方案用户处理</strong><br>
对于正在方案中的用户可以同步配送新机和退货</p>
</li>
<li>
<p><strong>已完成方案用户处理</strong><br>
对于已完成方案的用户需要先将旧的商品退回我司</p>
</li>
<li>
<p><strong>退货跟进</strong><br>
退货由服务群的客服跟进以确保用户会处理退货并提供相关的退货快递单号方便公司收件跟进</p>
</li>
<li>
<p><strong>退货寄件要求</strong><br>
用户寄回商品采用到付方式收件信息如下</p>
<div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text"><pre v-pre><code><span class="line">收件人: 陈声飞 </span>
<span class="line">手机号码: 13471927441 </span>
<span class="line">收件地址: 广东省深圳市南山区南山街道东滨路阳光科创中心B座3302 </span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></li>
<li>
<p><strong>新机出库配送</strong><br>
当更换的物料手环或体脂秤准备好后通知客服来领取相关物料双方确认物料齐全后出库由客服发快递寄出如果客服不在深圳由供应链工作人员代发邮寄但需客服根据邮寄照片确认物料齐全</p>
</li>
<li>
<p><strong>用户通知</strong><br>
客服在DMA用户群发送快递单号通知用户留意查收</p>
</li>
</ol>
<h2 id="四、培训业务类" tabindex="-1"><a class="header-anchor" href="#四、培训业务类"><span>培训业务类</span></a></h2>
<h3 id="_1-友福同享健康教练双证报考条件是什么" tabindex="-1"><a class="header-anchor" href="#_1-友福同享健康教练双证报考条件是什么"><span>1. 友福同享健康教练双证报考条件是什么</span></a></h3>

View File

@ -2,12 +2,10 @@
<h2 id="一、进入「收益提现」模块" tabindex="-1"><a class="header-anchor" href="#一、进入「收益提现」模块"><span>进入收益提现模块</span></a></h2>
<p><strong>操作步骤</strong></p>
<ol>
<li>打开APP点击底部导航栏的 <strong>应用</strong> 模块</li>
<li>应用界面选择 <strong>智能健康入口</strong>进入对应页面</li>
<li>打开APP点击底部导航栏的 <strong>我的</strong> 模块</li>
<li>我的界面选择 <strong>我的收益入口</strong>进入对应页面</li>
</ol>
<img alt="" src="/images/shareBenefit/img.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">
<br>
<img alt="" src="/images/shareBenefit/img_1.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">
<img alt="" src="https://images.health.ufutx.com/202602/05/a159dc901155fc12d1e9510dbe46c3b3.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">
<h2 id="二、提现操作流程-分润订单提现" tabindex="-1"><a class="header-anchor" href="#二、提现操作流程-分润订单提现"><span>提现操作流程分润订单提现</span></a></h2>
<h3 id="_2-1-发起提现申请" tabindex="-1"><a class="header-anchor" href="#_2-1-发起提现申请"><span>2.1 发起提现申请</span></a></h3>
<ol>

View File

@ -60,49 +60,49 @@ export default defineClientConfig({
// 全局路由守卫VuePress 2.x 适配版(白名单+未登录跳登录)
const whiteList = ['/login.html'] // 无需登录的页面
// 隐藏登录功能
// router.beforeEach(async (to, from, next) => {
// const userStore = useUserStore()
// const isLogin = userStore.isLogin
//
// // 白名单页面,直接放行
// if (whiteList.includes(to.path)) {
// next()
// return
// }
//
// // 未登录跳登录页并记录跳转前地址适配base: /dma_handbook/
// // 替换client.js中路由守卫的未登录跳转代码
// if (!isLogin) {
// showToast('请先登录后访问')
// // 核心修复直接使用to.fullPath已包含SITE_BASE无需手动拼接
// let redirectPath = to.fullPath
// // 兜底校验极端情况若fullPath未带SITE_BASE手动拼接防止地址栏手动修改
// if (!redirectPath.startsWith(SITE_BASE)) {
// redirectPath = `${SITE_BASE}${redirectPath.replace(/^\//, '')}` // 去掉开头的/,避免双斜杠
// }
// // 编码后拼接登录页地址
// const redirect = encodeURIComponent(redirectPath)
// window.location.href = `${SITE_BASE}login.html?redirect=${redirect}`
// return
// }
// // 核心修改:仅【已登录 + 未拉取过用户信息】时,才调用接口
// if (!userStore.isUserInfoFetched) {
// await getUserInfo(userStore)
// // 拉取成功后更新标记为true本次会话不再重复调用
// userStore.setUserInfoFetched(true)
// }
// // 已登录,正常放行
// next()
// })
// 全局退出登录方法6. 挂载到window所有环境Markdown/组件)都能调用
window.$logout = () => {
const userStore = useUserStore()
userStore.resetStore() // 清除Pinia+localStorage状态
showToast('退出登录成功')
window.location.href = `${SITE_BASE}login.html`
if (typeof window !== 'undefined') {
return
}
// 隐藏登录功能
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
const isLogin = userStore.isLogin
// 白名单页面,直接放行
if (whiteList.includes(to.path)) {
next()
return
}
if (typeof window == 'undefined') {
next()
return
}
// 未登录跳登录页并记录跳转前地址适配base: /dma_handbook/
// 替换client.js中路由守卫的未登录跳转代码
if (!isLogin) {
showToast('请先登录后访问')
// 核心修复直接使用to.fullPath已包含SITE_BASE无需手动拼接
let redirectPath = to.fullPath
// 兜底校验极端情况若fullPath未带SITE_BASE手动拼接防止地址栏手动修改
if (!redirectPath.startsWith(SITE_BASE)) {
redirectPath = `${SITE_BASE}${redirectPath.replace(/^\//, '')}` // 去掉开头的/,避免双斜杠
}
// 编码后拼接登录页地址
const redirect = encodeURIComponent(redirectPath)
window.location.href = `${SITE_BASE}login.html?redirect=${redirect}`
return
}
// 核心修改:仅【已登录 + 未拉取过用户信息】时,才调用接口
if (!userStore.isUserInfoFetched) {
await getUserInfo(userStore)
// 拉取成功后更新标记为true本次会话不再重复调用
userStore.setUserInfoFetched(true)
}
// 已登录,正常放行
next()
})
},
setup() {},
})

View File

@ -40,6 +40,9 @@ const redirect = ref('');
//
onMounted(() => {
if (typeof window === "undefined"){
return
}
const searchParams = new URLSearchParams(window.location.search);
console.log(searchParams,'searchParams');
// URLredirect

View File

@ -3,7 +3,7 @@ import { defaultTheme } from '@vuepress/theme-default'
import { defineUserConfig } from 'vuepress'
import fs from 'fs-extra'
import path from 'path'
import { searchPlugin } from '@vuepress/plugin-search'
// import { searchPlugin } from '@vuepress/plugin-search'
// 核心修改:从全局常量文件导入,替代本地定义
import { SITE_BASE, CDN_BASE} from './constants.js';
// import * as path from "path";
@ -276,16 +276,16 @@ export default defineUserConfig({
}
}
}],
searchPlugin({
// 可选:自定义最大建议条数
maxSuggestions: 10,
// 可选:设置触发搜索的快捷键(支持多个)
hotKeys: ['s', '/'],
// 可选:自定义搜索索引字段(默认包含 title 和 frontmatter
// getExtraFields: (page) => page.frontmatter.tags,
}),
// searchPlugin({
// // 可选:自定义最大建议条数
// maxSuggestions: 10,
//
// // 可选:设置触发搜索的快捷键(支持多个)
// hotKeys: ['s', '/'],
//
// // 可选:自定义搜索索引字段(默认包含 title 和 frontmatter
// // getExtraFields: (page) => page.frontmatter.tags,
// }),
// registerComponentsPlugin({
// // 配置项
// componentsDir: path.resolve(__dirname, '../../', 'components'), // 自动注册全局组件,

View File

@ -1,9 +1,9 @@
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('rt_token') || '',
userInfo: JSON.parse(localStorage.getItem('userInfo') || '{}'),
roles: JSON.parse(localStorage.getItem('roles') || '[]'),
token: typeof window !== 'undefined' ? localStorage.getItem('rt_token') || '' :'',
userInfo: typeof window !== 'undefined' ? JSON.parse(localStorage.getItem('userInfo') || '{}') : {},
roles: typeof window !== 'undefined' ? JSON.parse(localStorage.getItem('roles') || '[]') : [],
// 新增:会话级标记(是否已拉取过用户信息,不持久化,刷新自动重置)
isUserInfoFetched: false
}),
@ -15,12 +15,16 @@ export const useUserStore = defineStore('user', {
// 确保该方法存在:设置用户信息
setUserInfo(userInfo) {
this.userInfo = userInfo;
localStorage.setItem('userInfo', JSON.stringify(userInfo)); // 持久化到本地
if (typeof window !== 'undefined') {
localStorage.setItem('userInfo', JSON.stringify(userInfo)); // 持久化到本地
}
},
// 确保该方法存在:设置权限角色
setRoles(roleList) {
this.roles = roleList;
localStorage.setItem('roles', JSON.stringify(roleList)); // 持久化到本地
if (typeof window !== 'undefined') {
localStorage.setItem('roles', JSON.stringify(roleList)); // 持久化到本地
}
},
// 新增:更新用户信息拉取标记
setUserInfoFetched(status) {
@ -30,13 +34,17 @@ export const useUserStore = defineStore('user', {
this.token = ''
this.userInfo = {}
this.roles = []
localStorage.removeItem('rt_token')
localStorage.removeItem('userInfo')
localStorage.removeItem('roles')
if (typeof window !== 'undefined') {
localStorage.removeItem('rt_token')
localStorage.removeItem('userInfo')
localStorage.removeItem('roles')
}
},
setToken(token) {
this.token = token
localStorage.setItem('rt_token', token)
if (typeof window !== 'undefined') {
localStorage.setItem('rt_token', token)
}
},
// 其他setUserInfo/setRoles方法...
},

View File

@ -17,12 +17,11 @@ Type-C充电接口具备充电速度快、支持双向充电、接口可逆插
### 3. 手环电量怎么查看?
您可通过以下方式查看手环电量:
- 直接查看手环屏幕,通常会显示电量百分比;
- 打开友福同享APP进入「设备管理」页面找到对应手环设备即可查看实时电量信息。
- 按下手环右侧按钮查看显示灯颜色,绿灯表示电量充足,正常使用没有问题。红灯闪烁表示电量不足,指示灯不亮表示没有电,请及时充电。
- 也可以通过APP手环首页顶部电量百分比查看电量低于30%的情况,请及时充电。
<longPic src="https://images.health.ufutx.com/202408/16/d2b5ca33bd970f64a6301fa75ae2eb221723775855837.jpeg"></longPic>
<longPic src="https://images.health.ufutx.com/202602/05/ef2e5a95d213ba80b022eff89877fd1c.jpg"></longPic>
后续会规划低电量预警警告提醒功能,请耐心等待。
@ -116,7 +115,7 @@ Type-C充电接口具备充电速度快、支持双向充电、接口可逆插
- **[点击查看使用健康体脂秤用视频](https://images.health.ufutx.com/202410/15/2024101401.mp4)**
### 14. 购买25800元友福同享DMA智能健康方案它包含哪些服务及相关的流程是什么
### 14. 购买友福同享DMA智能健康方案它包含哪些服务及相关的流程是什么
友福同享DMA智能健康方案包含以下服务与流程具体以实际为准建议咨询客服确认
- **服务内容**:专属健康评估、定制运动计划、营养膳食指导、定期健康监测(含手环、体脂秤等设备使用)、健康教练在线咨询等;
- **服务流程**:支付成功后,客服将联系您预约健康评估,随后根据评估结果定制方案,配送设备并指导使用,后续将定期跟踪健康数据并调整方案。
@ -270,7 +269,7 @@ DMA健康方案的体检项目通常包括具体以实际套餐为准
#### (二)体脂秤换货标准
::: tip ✅ 支持换货的情形
- 非电池原因导致 **屏幕无法显示** 或 **无法测量数据**
- 非电池原因导致 **无法测量数据**
- 出厂即存在功能缺陷。
:::
@ -289,7 +288,7 @@ DMA健康方案的体检项目通常包括具体以实际套餐为准
### 3、不良设备换货操作流程
1. **客服介入**
DMA 服务群内的专属客服全程跟进换货事宜
DMA群里的客服跟进
2. **资料收集与申请**
客服需整理以下信息,并通过微信发送至 **“友福审核”** 申请新设备:
@ -303,7 +302,23 @@ DMA健康方案的体检项目通常包括具体以实际套餐为准
- 手环 / 体脂秤
- 若为手环请注明类型A已测试或 B未拆封
- 是否需同步配发 Type-C 转 USB 转换头?
3. **正在方案用户处理**
对于正在方案中的用户,可以同步配送新机和退货;
4. **已完成方案用户处理**
对于已完成方案的用户,需要先将旧的商品退回我司;
5. **退货跟进**
退货:由服务群的客服跟进,以确保用户会处理退货;并提供相关的退货快递单号,方便公司收件跟进。
6. **退货寄件要求**
用户寄回商品,采用到付方式,收件信息如下:
```text
收件人: 陈声飞
手机号码: 13471927441
收件地址: 广东省深圳市南山区南山街道东滨路阳光科创中心B座3302
7. **新机出库配送**
当更换的物料(手环或体脂秤)准备好后,通知客服来领取相关物料。双方确认物料齐全后出库,由客服发快递寄出。如果客服不在深圳,由供应链工作人员代发邮寄,但需客服根据邮寄照片确认物料齐全。
8. **用户通知**
客服在DMA用户群发送快递单号通知用户留意查收。
## 四、培训业务类

View File

@ -3,13 +3,11 @@
## 一、进入「收益提现」模块
**操作步骤**
1. 打开APP点击底部导航栏的 **应用】** 模块。
2. 在【应用】界面,选择 **「智能健康」入口**,进入对应页面。
1. 打开APP点击底部导航栏的 **我的】** 模块。
2. 在【我的】界面,选择 **「我的收益」入口**,进入对应页面。
[//]: # ( ![img.png]&#40;../.vuepress/public/images/shareBenefit/img.png&#41;)
<img alt="" src="/images/shareBenefit/img.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">
<br>
<img alt="" src="/images/shareBenefit/img_1.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">
<img alt="" src="https://images.health.ufutx.com/202602/05/a159dc901155fc12d1e9510dbe46c3b3.png" loading="lazy" style="width:300px;height:auto;marginTop:10px;">

View File

@ -2,8 +2,10 @@ import { PERMISSIONS } from '../.vuepress/roles';
import axios from 'axios'
export function getCurrentUserRole() {
console.log('32-')
// 从store或localStorage获取用户角色
return localStorage.getItem('userRole') || 'coach';
if (typeof window !== 'undefined') {
// 从store或localStorage获取用户角色
return localStorage.getItem('userRole') || 'coach';
}
}
export function checkPermission(currentRole, requiredPath) {
@ -18,7 +20,9 @@ const allowedPaths = PERMISSIONS[currentRole] || [];
}
export function isLoggedIn() {
return !!localStorage.getItem('authToken');
if (typeof window !== 'undefined') {
return !!localStorage.getItem('authToken');
}
}
export function showLoginModal() {
@ -27,7 +31,9 @@ export function showLoginModal() {
// 添加登录API调用方法
export async function login(credentials) {
const response = await axios.post('/api/login', credentials);
localStorage.setItem('authToken', response.data.token);
localStorage.setItem('userRole', response.data.role);
if (typeof window !== 'undefined') {
const response = await axios.post('/api/login', credentials);
localStorage.setItem('authToken', response.data.token);
localStorage.setItem('userRole', response.data.role);
}
}

View File

@ -6,7 +6,9 @@
export function backFillLoginData(res, userStore) {
if (res.token) {
userStore.setToken(res.token);
localStorage.setItem('rt_token', res.token);
if (typeof window !== 'undefined'){
localStorage.setItem('rt_token', res.token);
}
}
if (res.userInfo) {
userStore.setUserInfo(res.userInfo);

View File

@ -58,7 +58,7 @@ service.interceptors.request.use(
// 携带Token仅保留核心rt_token联动Pinia
if (isBrowser) {
const userStore = useUserStore();
const token = userStore.token || localStorage.getItem('rt_token') || '';
const token = userStore.token || typeof window !== 'undefined' ? localStorage.getItem('rt_token') : '' || '';
if (token) config.headers['Authorization'] = `Bearer ${token}`;
}
// 处理POST表单参数
@ -100,7 +100,9 @@ service.interceptors.response.use(
const userStore = useUserStore();
// 清除状态,跳登录页并记录跳转地址
userStore.resetStore();
localStorage.removeItem('rt_token');
if (typeof window !== 'undefined') {
localStorage.removeItem('rt_token');
}
const redirect = encodeURIComponent(window.location.href);
window.location.href = `/dma_handbook/login?redirect=${redirect}`;
}

10
package-lock.json generated
View File

@ -12,7 +12,7 @@
"@fortawesome/fontawesome-free": "^6.7.2",
"@vuepress/plugin-medium-zoom": "^2.0.0-rc.86",
"@vueuse/core": "^13.5.0",
"axios": "^1.10.0",
"axios": "^1.12.0",
"pinia": "^3.0.3",
"vue-router": "^4.5.1",
"vuepress-plugin-seo": "^0.2.0"
@ -2728,13 +2728,13 @@
}
},
"node_modules/axios": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz",
"integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},

View File

@ -21,7 +21,6 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.7.2",
"@vuepress/plugin-medium-zoom": "^2.0.0-rc.86",
"@vuepress/plugin-search": "^2.0.0-rc.86",
"@vueuse/core": "^13.5.0",
"axios": "^1.12.0",
"pinia": "^3.0.3",